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.
5 /*****************************************************************************/
19 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
20 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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
28 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
29 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
33 /*****************************************************************************
35 * Keep track of the current state of each register. This is intended to be
36 * used for things like register reload suppression, but for now the only
37 * thing it does is note which registers we use in each method.
42 RV_TRASH, // random unclassified garbage
43 RV_INT_CNS, // integer constant
44 RV_LCL_VAR, // local variable value
45 RV_LCL_VAR_LNG_LO, // lower half of long local variable
48 #endif // LEGACY_BACKEND
50 /*****************************************************************************/
55 friend class CodeGenInterface;
58 Compiler* m_rsCompiler;
62 RegSet(Compiler* compiler, GCInfo& gcInfo);
65 regMaskTP rsMaskPreSpillRegs(bool includeAlignment)
67 return includeAlignment ? (rsMaskPreSpillRegArg | rsMaskPreSpillAlign) : rsMaskPreSpillRegArg;
69 #endif // _TARGET_ARM_
72 // The same descriptor is also used for 'multi-use' register tracking, BTW.
75 SpillDsc* spillNext; // next spilled value of same reg
78 GenTree* spillTree; // the value that was spilled
80 LclVarDsc* spillVarDsc; // variable if it's an enregistered variable
81 #endif // LEGACY_BACKEND
84 TempDsc* spillTemp; // the temp holding the spilled value
87 GenTree* spillAddr; // owning complex address mode or nullptr
91 bool bEnregisteredVariable; // For FP. Indicates that what was spilled was
92 // an enregistered variable
94 #endif // LEGACY_BACKEND
96 static SpillDsc* alloc(Compiler* pComp, RegSet* regSet, var_types type);
97 static void freeDsc(RegSet* regSet, SpillDsc* spillDsc);
100 #ifdef LEGACY_BACKEND
102 regMaskTP rsUseIfZero(regMaskTP regs, regMaskTP includeHint);
103 #endif // LEGACY_BACKEND
105 //-------------------------------------------------------------------------
107 // Track the status of the registers
109 #ifdef LEGACY_BACKEND
110 public: // TODO-Cleanup: Should be private, but Compiler uses it
111 GenTree* rsUsedTree[REG_COUNT]; // trees currently sitting in the registers
113 GenTree* rsUsedAddr[REG_COUNT]; // addr for which rsUsedTree[reg] is a part of the addressing mode
114 SpillDsc* rsMultiDesc[REG_COUNT]; // keeps track of 'multiple-use' registers.
115 #endif // LEGACY_BACKEND
118 bool rsNeededSpillReg; // true if this method needed to spill any registers
119 regMaskTP rsModifiedRegsMask; // mask of the registers modified by the current function.
122 bool rsModifiedRegsMaskInitialized; // Has rsModifiedRegsMask been initialized? Guards against illegal use.
126 regMaskTP rsGetModifiedRegsMask() const
128 assert(rsModifiedRegsMaskInitialized);
129 return rsModifiedRegsMask;
132 void rsClearRegsModified();
134 void rsSetRegsModified(regMaskTP mask DEBUGARG(bool suppressDump = false));
136 void rsRemoveRegsModified(regMaskTP mask);
138 bool rsRegsModified(regMaskTP mask) const
140 assert(rsModifiedRegsMaskInitialized);
141 return (rsModifiedRegsMask & mask) != 0;
144 public: // TODO-Cleanup: Should be private, but GCInfo uses them
145 #ifdef LEGACY_BACKEND
146 regMaskTP rsMaskUsed; // currently 'used' registers mask
147 #endif // LEGACY_BACKEND
149 __declspec(property(get = GetMaskVars, put = SetMaskVars)) regMaskTP rsMaskVars; // mask of registers currently
150 // allocated to variables
152 regMaskTP GetMaskVars() const // 'get' property function for rsMaskVars property
157 void SetMaskVars(regMaskTP newMaskVars); // 'put' property function for rsMaskVars property
159 void AddMaskVars(regMaskTP addMaskVars) // union 'addMaskVars' with the rsMaskVars set
161 SetMaskVars(_rsMaskVars | addMaskVars);
164 void RemoveMaskVars(regMaskTP removeMaskVars) // remove 'removeMaskVars' from the rsMaskVars set (like bitset DiffD)
166 SetMaskVars(_rsMaskVars & ~removeMaskVars);
169 void ClearMaskVars() // Like SetMaskVars(RBM_NONE), but without any debug output.
171 _rsMaskVars = RBM_NONE;
175 regMaskTP _rsMaskVars; // backing store for rsMaskVars property
177 #ifdef LEGACY_BACKEND
178 regMaskTP rsMaskLock; // currently 'locked' registers mask
179 regMaskTP rsMaskMult; // currently 'multiply used' registers mask
180 #endif // LEGACY_BACKEND
182 #ifdef _TARGET_ARMARCH_
183 regMaskTP rsMaskCalleeSaved; // mask of the registers pushed/popped in the prolog/epilog
184 #endif // _TARGET_ARM_
186 public: // TODO-Cleanup: Should be private, but Compiler uses it
187 regMaskTP rsMaskResvd; // mask of the registers that are reserved for special purposes (typically empty)
189 public: // The PreSpill masks are used in LclVars.cpp
191 regMaskTP rsMaskPreSpillAlign; // Mask of alignment padding added to prespill to keep double aligned args
192 // at aligned stack addresses.
193 regMaskTP rsMaskPreSpillRegArg; // mask of incoming registers that are spilled at the start of the prolog
194 // This includes registers used to pass a struct (or part of a struct)
195 // and all enregistered user arguments in a varargs call
196 #endif // _TARGET_ARM_
198 #ifdef LEGACY_BACKEND
201 // These getters/setters are ifdef here so that the accesses to these values in sharedfloat.cpp are redirected
202 // to the appropriate value.
203 // With FEATURE_STACK_FP_X87 (x86 FP codegen) we have separate register mask that just handle FP registers.
204 // For all other platforms (and eventually on x86) we use unified register masks that handle both kinds.
206 regMaskTP rsGetMaskUsed(); // Getter for rsMaskUsed or rsMaskUsedFloat
207 regMaskTP rsGetMaskVars(); // Getter for rsMaskVars or rsMaskRegVarFloat
208 regMaskTP rsGetMaskLock(); // Getter for rsMaskLock or rsMaskLockedFloat
209 regMaskTP rsGetMaskMult(); // Getter for rsMaskMult or 0
211 void rsSetMaskUsed(regMaskTP maskUsed); // Setter for rsMaskUsed or rsMaskUsedFloat
212 void rsSetMaskVars(regMaskTP maskVars); // Setter for rsMaskVars or rsMaskRegVarFloat
213 void rsSetMaskLock(regMaskTP maskLock); // Setter for rsMaskLock or rsMaskLockedFloat
215 void rsSetUsedTree(regNumber regNum, GenTree* tree); // Setter for rsUsedTree[]/genUsedRegsFloat[]
216 void rsFreeUsedTree(regNumber regNum, GenTree* tree); // Free for rsUsedTree[]/genUsedRegsFloat[]
219 regPairNo rsFindRegPairNo(regMaskTP regMask);
222 bool rsIsTreeInReg(regNumber reg, GenTree* tree);
224 regMaskTP rsExcludeHint(regMaskTP regs, regMaskTP excludeHint);
225 regMaskTP rsNarrowHint(regMaskTP regs, regMaskTP narrowHint);
226 regMaskTP rsMustExclude(regMaskTP regs, regMaskTP exclude);
227 regMaskTP rsRegMaskFree();
228 regMaskTP rsRegMaskCanGrab();
230 void rsMarkRegUsed(GenTree* tree, GenTree* addr = 0);
231 // A special case of "rsMarkRegUsed": the register used is an argument register, used to hold part of
232 // the given argument node "promotedStructArg". (The name suggests that we're likely to use use this
233 // for register holding a promoted struct argument, but the implementation doesn't depend on that.) The
234 // "isGCRef" argument indicates whether the register contains a GC reference.
235 void rsMarkArgRegUsedByPromotedFieldArg(GenTree* promotedStructArg, regNumber regNum, bool isGCRef);
237 void rsMarkRegPairUsed(GenTree* tree);
239 void rsMarkRegFree(regMaskTP regMask);
240 void rsMarkRegFree(regNumber reg, GenTree* tree);
241 void rsMultRegFree(regMaskTP regMask);
242 unsigned rsFreeNeededRegCount(regMaskTP needReg);
244 void rsLockReg(regMaskTP regMask);
245 void rsUnlockReg(regMaskTP regMask);
246 void rsLockUsedReg(regMaskTP regMask);
247 void rsUnlockUsedReg(regMaskTP regMask);
248 void rsLockReg(regMaskTP regMask, regMaskTP* usedMask);
249 void rsUnlockReg(regMaskTP regMask, regMaskTP usedMask);
251 regMaskTP rsRegExclMask(regMaskTP regMask, regMaskTP rmvMask);
253 regNumber rsPickRegInTmpOrder(regMaskTP regMask);
255 public: // used by emitter (!)
256 regNumber rsGrabReg(regMaskTP regMask);
259 regNumber rsPickReg(regMaskTP regMask = RBM_NONE, regMaskTP regBest = RBM_NONE);
261 public: // used by emitter (!)
262 regNumber rsPickFreeReg(regMaskTP regMaskHint = RBM_ALLINT);
265 regPairNo rsGrabRegPair(regMaskTP regMask);
266 regPairNo rsPickRegPair(regMaskTP regMask);
268 class RegisterPreference
273 RegisterPreference(regMaskTP _ok, regMaskTP _best)
279 regNumber PickRegFloat(GenTree* tree,
280 var_types type = TYP_DOUBLE,
281 RegisterPreference* pref = NULL,
283 regNumber PickRegFloat(var_types type = TYP_DOUBLE, RegisterPreference* pref = NULL, bool bUsed = true);
284 regNumber PickRegFloatOtherThan(GenTree* tree, var_types type, regNumber reg);
285 regNumber PickRegFloatOtherThan(var_types type, regNumber reg);
287 regMaskTP RegFreeFloat();
289 void SetUsedRegFloat(GenTree* tree, bool bValue);
290 void SetLockedRegFloat(GenTree* tree, bool bValue);
291 bool IsLockedRegFloat(GenTree* tree);
293 var_types rsRmvMultiReg(regNumber reg);
294 void rsRecMultiReg(regNumber reg, var_types type);
295 #endif // LEGACY_BACKEND
299 /*****************************************************************************
300 * Should we stress register tracking logic ?
301 * This is set via COMPlus_JitStressRegs.
302 * The following values are ordered, such that any value greater than RS_xx
304 * LSRA defines a different set of values, but uses the same COMPlus_JitStressRegs
305 * value, with the same notion of relative ordering.
306 * 1 = rsPickReg() picks 'bad' registers.
307 * 2 = codegen spills at safe points. This is still flaky
309 enum rsStressRegsType
312 RS_PICK_BAD_REG = 01,
315 rsStressRegsType rsStressRegs();
319 //-------------------------------------------------------------------------
321 // The following tables keep track of spilled register values.
324 // When a register gets spilled, the old information is stored here
325 SpillDsc* rsSpillDesc[REG_COUNT];
326 SpillDsc* rsSpillFree; // list of unused spill descriptors
328 #ifdef LEGACY_BACKEND
329 SpillDsc* rsSpillFloat;
330 #endif // LEGACY_BACKEND
338 void rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx = 0);
340 #if defined(_TARGET_X86_) && !FEATURE_STACK_FP_X87
341 void rsSpillFPStack(GenTreeCall* call);
342 #endif // defined(_TARGET_X86_) && !FEATURE_STACK_FP_X87
344 #ifdef LEGACY_BACKEND
345 void rsSpillReg(regNumber reg);
346 void rsSpillRegIfUsed(regNumber reg);
347 void rsSpillRegs(regMaskTP regMask);
348 #endif // LEGACY_BACKEND
350 SpillDsc* rsGetSpillInfo(GenTree* tree,
352 SpillDsc** pPrevDsc = nullptr
353 #ifdef LEGACY_BACKEND
355 SpillDsc** pMultiDsc = NULL
356 #endif // LEGACY_BACKEND
359 TempDsc* rsGetSpillTempWord(regNumber oldReg, SpillDsc* dsc, SpillDsc* prevDsc);
361 #ifdef LEGACY_BACKEND
373 regNumber rsUnspillOneReg(GenTree* tree, regNumber oldReg, KeepReg willKeepNewReg, regMaskTP needReg);
374 #endif // LEGACY_BACKEND
376 TempDsc* rsUnspillInPlace(GenTree* tree, regNumber oldReg, unsigned regIdx = 0);
378 #ifdef LEGACY_BACKEND
379 void rsUnspillReg(GenTree* tree, regMaskTP needReg, KeepReg keepReg);
381 void rsUnspillRegPair(GenTree* tree, regMaskTP needReg, KeepReg keepReg);
382 #endif // LEGACY_BACKEND
384 void rsMarkSpill(GenTree* tree, regNumber reg);
386 #ifdef LEGACY_BACKEND
387 void rsMarkUnspill(GenTree* tree, regNumber reg);
388 #endif // LEGACY_BACKEND
390 #if FEATURE_STACK_FP_X87
391 regMaskTP rsMaskUsedFloat;
392 regMaskTP rsMaskRegVarFloat;
393 regMaskTP rsMaskLockedFloat;
394 GenTree* genUsedRegsFloat[REG_FPCOUNT];
395 LclVarDsc* genRegVarsFloat[REG_FPCOUNT];
396 #endif // FEATURE_STACK_FP_X87
399 //-------------------------------------------------------------------------
401 // These are used to track the contents of the registers during
404 // Only integer registers are tracked.
407 #ifdef LEGACY_BACKEND
412 ssize_t rvdIntCnsVal; // for rvdKind == RV_INT_CNS
413 unsigned rvdLclVarNum; // for rvdKind == RV_LCL_VAR, RV_LCL_VAR_LNG_LO, RV_LCL_VAR_LNG_HI
416 #endif // LEGACY_BACKEND
422 #ifdef LEGACY_BACKEND
423 RegValDsc rsRegValues[REG_COUNT];
427 void rsTrackInit(Compiler* comp, RegSet* rs)
431 #ifdef LEGACY_BACKEND
436 #ifdef LEGACY_BACKEND
437 void rsTrackRegClr();
438 void rsTrackRegClrPtr();
439 #endif // LEGACY_BACKEND
440 void rsTrackRegTrash(regNumber reg);
441 #ifdef LEGACY_BACKEND
442 void rsTrackRegMaskTrash(regMaskTP regMask);
443 regMaskTP rsTrashRegsForGCInterruptability();
444 #endif // LEGACY_BACKEND
445 void rsTrackRegIntCns(regNumber reg, ssize_t val);
446 void rsTrackRegLclVar(regNumber reg, unsigned var);
447 #ifdef LEGACY_BACKEND
448 void rsTrackRegLclVarLng(regNumber reg, unsigned var, bool low);
449 bool rsTrackIsLclVarLng(regValKind rvKind);
450 void rsTrackRegClsVar(regNumber reg, GenTree* clsVar);
451 #endif // LEGACY_BACKEND
452 void rsTrackRegCopy(regNumber reg1, regNumber reg2);
453 #ifdef LEGACY_BACKEND
454 void rsTrackRegSwap(regNumber reg1, regNumber reg2);
455 void rsTrackRegAssign(GenTree* op1, GenTree* op2);
457 regNumber rsIconIsInReg(ssize_t val, ssize_t* closeDelta = nullptr);
458 bool rsIconIsInReg(ssize_t val, regNumber reg);
459 regNumber rsLclIsInReg(unsigned var);
460 regPairNo rsLclIsInRegPair(unsigned var);
462 //---------------------- Load suppression ---------------------------------
464 void rsTrashLclLong(unsigned var);
465 void rsTrashLcl(unsigned var);
466 #endif // LEGACY_BACKEND
467 void rsTrashRegSet(regMaskTP regMask);
468 #ifdef LEGACY_BACKEND
469 regMaskTP rsUselessRegs();
470 #endif // LEGACY_BACKEND