1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /*****************************************************************************/ |
6 | |
7 | #ifndef _REGSET_H |
8 | #define _REGSET_H |
9 | #include "vartype.h" |
10 | #include "target.h" |
11 | |
12 | class LclVarDsc; |
13 | class TempDsc; |
14 | class Compiler; |
15 | class CodeGen; |
16 | class GCInfo; |
17 | |
18 | /* |
19 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
20 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
21 | XX XX |
22 | XX RegSet XX |
23 | XX XX |
24 | XX Represents the register set, and their states during code generation XX |
25 | XX Can select an unused register, keeps track of the contents of the XX |
26 | XX registers, and can spill registers XX |
27 | XX XX |
28 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
29 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
30 | */ |
31 | |
32 | /*****************************************************************************/ |
33 | |
34 | class RegSet |
35 | { |
36 | friend class CodeGen; |
37 | friend class CodeGenInterface; |
38 | |
39 | private: |
40 | Compiler* m_rsCompiler; |
41 | GCInfo& m_rsGCInfo; |
42 | |
43 | public: |
44 | RegSet(Compiler* compiler, GCInfo& gcInfo); |
45 | |
46 | #ifdef _TARGET_ARM_ |
47 | regMaskTP rsMaskPreSpillRegs(bool includeAlignment) |
48 | { |
49 | return includeAlignment ? (rsMaskPreSpillRegArg | rsMaskPreSpillAlign) : rsMaskPreSpillRegArg; |
50 | } |
51 | #endif // _TARGET_ARM_ |
52 | |
53 | private: |
54 | // The same descriptor is also used for 'multi-use' register tracking, BTW. |
55 | struct SpillDsc |
56 | { |
57 | SpillDsc* spillNext; // next spilled value of same reg |
58 | GenTree* spillTree; // the value that was spilled |
59 | TempDsc* spillTemp; // the temp holding the spilled value |
60 | |
61 | static SpillDsc* alloc(Compiler* pComp, RegSet* regSet, var_types type); |
62 | static void freeDsc(RegSet* regSet, SpillDsc* spillDsc); |
63 | }; |
64 | |
65 | //------------------------------------------------------------------------- |
66 | // |
67 | // Track the status of the registers |
68 | // |
69 | |
70 | private: |
71 | bool rsNeededSpillReg; // true if this method needed to spill any registers |
72 | regMaskTP rsModifiedRegsMask; // mask of the registers modified by the current function. |
73 | |
74 | #ifdef DEBUG |
75 | bool rsModifiedRegsMaskInitialized; // Has rsModifiedRegsMask been initialized? Guards against illegal use. |
76 | #endif // DEBUG |
77 | |
78 | public: |
79 | regMaskTP rsGetModifiedRegsMask() const |
80 | { |
81 | assert(rsModifiedRegsMaskInitialized); |
82 | return rsModifiedRegsMask; |
83 | } |
84 | |
85 | void rsClearRegsModified(); |
86 | |
87 | void (regMaskTP mask DEBUGARG(bool suppressDump = false)); |
88 | |
89 | void rsRemoveRegsModified(regMaskTP mask); |
90 | |
91 | bool rsRegsModified(regMaskTP mask) const |
92 | { |
93 | assert(rsModifiedRegsMaskInitialized); |
94 | return (rsModifiedRegsMask & mask) != 0; |
95 | } |
96 | |
97 | void verifyRegUsed(regNumber reg); |
98 | |
99 | void verifyRegistersUsed(regMaskTP regMask); |
100 | |
101 | public: // TODO-Cleanup: Should be private, but GCInfo uses them |
102 | __declspec(property(get = GetMaskVars, put = SetMaskVars)) regMaskTP rsMaskVars; // mask of registers currently |
103 | // allocated to variables |
104 | |
105 | regMaskTP GetMaskVars() const // 'get' property function for rsMaskVars property |
106 | { |
107 | return _rsMaskVars; |
108 | } |
109 | |
110 | void SetMaskVars(regMaskTP newMaskVars); // 'put' property function for rsMaskVars property |
111 | |
112 | void AddMaskVars(regMaskTP addMaskVars) // union 'addMaskVars' with the rsMaskVars set |
113 | { |
114 | SetMaskVars(_rsMaskVars | addMaskVars); |
115 | } |
116 | |
117 | void RemoveMaskVars(regMaskTP removeMaskVars) // remove 'removeMaskVars' from the rsMaskVars set (like bitset DiffD) |
118 | { |
119 | SetMaskVars(_rsMaskVars & ~removeMaskVars); |
120 | } |
121 | |
122 | void ClearMaskVars() // Like SetMaskVars(RBM_NONE), but without any debug output. |
123 | { |
124 | _rsMaskVars = RBM_NONE; |
125 | } |
126 | |
127 | private: |
128 | regMaskTP _rsMaskVars; // backing store for rsMaskVars property |
129 | |
130 | #ifdef _TARGET_ARMARCH_ |
131 | regMaskTP rsMaskCalleeSaved; // mask of the registers pushed/popped in the prolog/epilog |
132 | #endif // _TARGET_ARM_ |
133 | |
134 | public: // TODO-Cleanup: Should be private, but Compiler uses it |
135 | regMaskTP rsMaskResvd; // mask of the registers that are reserved for special purposes (typically empty) |
136 | |
137 | public: // The PreSpill masks are used in LclVars.cpp |
138 | #ifdef _TARGET_ARM_ |
139 | regMaskTP rsMaskPreSpillAlign; // Mask of alignment padding added to prespill to keep double aligned args |
140 | // at aligned stack addresses. |
141 | regMaskTP rsMaskPreSpillRegArg; // mask of incoming registers that are spilled at the start of the prolog |
142 | // This includes registers used to pass a struct (or part of a struct) |
143 | // and all enregistered user arguments in a varargs call |
144 | #endif // _TARGET_ARM_ |
145 | |
146 | private: |
147 | //------------------------------------------------------------------------- |
148 | // |
149 | // The following tables keep track of spilled register values. |
150 | // |
151 | |
152 | // When a register gets spilled, the old information is stored here |
153 | SpillDsc* [REG_COUNT]; |
154 | SpillDsc* ; // list of unused spill descriptors |
155 | |
156 | void (); |
157 | void (); |
158 | void (); |
159 | void (); |
160 | void (); |
161 | |
162 | void (regNumber reg, GenTree* tree, unsigned regIdx = 0); |
163 | |
164 | #if defined(_TARGET_X86_) |
165 | void rsSpillFPStack(GenTreeCall* call); |
166 | #endif // defined(_TARGET_X86_) |
167 | |
168 | SpillDsc* rsGetSpillInfo(GenTree* tree, regNumber reg, SpillDsc** pPrevDsc = nullptr); |
169 | |
170 | TempDsc* rsGetSpillTempWord(regNumber oldReg, SpillDsc* dsc, SpillDsc* prevDsc); |
171 | |
172 | TempDsc* rsUnspillInPlace(GenTree* tree, regNumber oldReg, unsigned regIdx = 0); |
173 | |
174 | void rsMarkSpill(GenTree* tree, regNumber reg); |
175 | |
176 | public: |
177 | void tmpInit(); |
178 | |
179 | enum TEMP_USAGE_TYPE |
180 | { |
181 | TEMP_USAGE_FREE, |
182 | TEMP_USAGE_USED |
183 | }; |
184 | |
185 | static var_types tmpNormalizeType(var_types type); |
186 | TempDsc* tmpGetTemp(var_types type); // get temp for the given type |
187 | void tmpRlsTemp(TempDsc* temp); |
188 | TempDsc* tmpFindNum(int temp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const; |
189 | |
190 | void tmpEnd(); |
191 | TempDsc* tmpListBeg(TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const; |
192 | TempDsc* tmpListNxt(TempDsc* curTemp, TEMP_USAGE_TYPE usageType = TEMP_USAGE_FREE) const; |
193 | void tmpDone(); |
194 | |
195 | #ifdef DEBUG |
196 | bool tmpAllFree() const; |
197 | #endif // DEBUG |
198 | |
199 | void tmpPreAllocateTemps(var_types type, unsigned count); |
200 | |
201 | unsigned tmpGetTotalSize() |
202 | { |
203 | return tmpSize; |
204 | } |
205 | |
206 | private: |
207 | unsigned tmpCount; // Number of temps |
208 | unsigned tmpSize; // Size of all the temps |
209 | #ifdef DEBUG |
210 | // Used by RegSet::rsSpillChk() |
211 | unsigned tmpGetCount; // Temps which haven't been released yet |
212 | #endif |
213 | static unsigned tmpSlot(unsigned size); // which slot in tmpFree[] or tmpUsed[] to use |
214 | |
215 | enum TEMP_CONSTANTS : unsigned |
216 | { |
217 | #if defined(FEATURE_SIMD) |
218 | #if defined(_TARGET_XARCH_) |
219 | TEMP_MAX_SIZE = YMM_REGSIZE_BYTES, |
220 | #elif defined(_TARGET_ARM64_) |
221 | TEMP_MAX_SIZE = FP_REGSIZE_BYTES, |
222 | #endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_) |
223 | #else // !FEATURE_SIMD |
224 | TEMP_MAX_SIZE = sizeof(double), |
225 | #endif // !FEATURE_SIMD |
226 | TEMP_SLOT_COUNT = (TEMP_MAX_SIZE / sizeof(int)) |
227 | }; |
228 | |
229 | TempDsc* tmpFree[TEMP_MAX_SIZE / sizeof(int)]; |
230 | TempDsc* tmpUsed[TEMP_MAX_SIZE / sizeof(int)]; |
231 | }; |
232 | |
233 | #endif // _REGSET_H |
234 | |