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
12class LclVarDsc;
13class TempDsc;
14class Compiler;
15class CodeGen;
16class GCInfo;
17
18/*
19XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
20XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
21XX XX
22XX RegSet XX
23XX XX
24XX Represents the register set, and their states during code generation XX
25XX Can select an unused register, keeps track of the contents of the XX
26XX registers, and can spill registers XX
27XX XX
28XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
29XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
30*/
31
32/*****************************************************************************/
33
34class RegSet
35{
36 friend class CodeGen;
37 friend class CodeGenInterface;
38
39private:
40 Compiler* m_rsCompiler;
41 GCInfo& m_rsGCInfo;
42
43public:
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
53private:
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
70private:
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
78public:
79 regMaskTP rsGetModifiedRegsMask() const
80 {
81 assert(rsModifiedRegsMaskInitialized);
82 return rsModifiedRegsMask;
83 }
84
85 void rsClearRegsModified();
86
87 void rsSetRegsModified(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
101public: // 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
127private:
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
134public: // 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
137public: // 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
146private:
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* rsSpillDesc[REG_COUNT];
154 SpillDsc* rsSpillFree; // list of unused spill descriptors
155
156 void rsSpillChk();
157 void rsSpillInit();
158 void rsSpillDone();
159 void rsSpillBeg();
160 void rsSpillEnd();
161
162 void rsSpillTree(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
176public:
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
206private:
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