Skip to content

Commit 1895e05

Browse files
authored
JIT: Simplify internal GC tracking structures (#113071)
Track all integer registers for calls in `regPtrDsc`. This does not cost any extra memory and it saves us from going back and forth between an intermediate format. It also unblocks proper GC reporting for helper calls that are GC reported with non-standard calling convention.
1 parent 6d344b3 commit 1895e05

9 files changed

+44
-86
lines changed

src/coreclr/jit/emit.cpp

+9-17
Original file line numberDiff line numberDiff line change
@@ -9983,7 +9983,6 @@ void emitter::emitStackPopLargeStk(BYTE* addr, bool isCall, unsigned char callIn
99839983

99849984
unsigned argStkCnt;
99859985
S_UINT16 argRecCnt(0); // arg count for ESP, ptr-arg count for EBP
9986-
unsigned gcrefRegs, byrefRegs;
99879986

99889987
#ifdef JIT32_GCENCODER
99899988
// For the general encoder, we always need to record calls, so we make this call
@@ -10025,26 +10024,19 @@ void emitter::emitStackPopLargeStk(BYTE* addr, bool isCall, unsigned char callIn
1002510024
return;
1002610025
#endif
1002710026

10028-
// Do we have any interesting (i.e., callee-saved) registers live here?
10027+
// Do we have any interesting registers live here?
1002910028

10030-
gcrefRegs = byrefRegs = 0;
10029+
unsigned gcrefRegs = emitThisGCrefRegs.GetIntRegSet() >> REG_INT_FIRST;
10030+
unsigned byrefRegs = emitThisByrefRegs.GetIntRegSet() >> REG_INT_FIRST;
1003110031

10032-
// We make a bitmask whose bits correspond to callee-saved register indices (in the sequence
10033-
// of callee-saved registers only).
10034-
for (unsigned calleeSavedRegIdx = 0; calleeSavedRegIdx < CNT_CALL_GC_REGS; calleeSavedRegIdx++)
10035-
{
10036-
regMaskTP calleeSavedRbm = raRbmCalleeSaveOrder[calleeSavedRegIdx];
10037-
if (emitThisGCrefRegs & calleeSavedRbm)
10038-
{
10039-
gcrefRegs |= (1 << calleeSavedRegIdx);
10040-
}
10041-
if (emitThisByrefRegs & calleeSavedRbm)
10042-
{
10043-
byrefRegs |= (1 << calleeSavedRegIdx);
10044-
}
10045-
}
10032+
assert(regMaskTP::FromIntRegSet(SingleTypeRegSet(gcrefRegs << REG_INT_FIRST)) == emitThisGCrefRegs);
10033+
assert(regMaskTP::FromIntRegSet(SingleTypeRegSet(byrefRegs << REG_INT_FIRST)) == emitThisByrefRegs);
1004610034

1004710035
#ifdef JIT32_GCENCODER
10036+
// x86 does not report GC refs/byrefs in return registers at call sites
10037+
gcrefRegs &= ~(1u << (REG_INTRET - REG_INT_FIRST));
10038+
byrefRegs &= ~(1u << (REG_INTRET - REG_INT_FIRST));
10039+
1004810040
// For the general encoder, we always have to record calls, so we don't take this early return. /* Are there any
1004910041
// args to pop at this call site?
1005010042

src/coreclr/jit/gcencode.cpp

+21-9
Original file line numberDiff line numberDiff line change
@@ -3199,9 +3199,24 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un
31993199

32003200
callArgCnt = genRegPtrTemp->rpdPtrArg;
32013201

3202-
unsigned gcrefRegMask = genRegPtrTemp->rpdCallGCrefRegs;
3202+
unsigned gcrefRegMask = 0;
32033203

3204-
byrefRegMask = genRegPtrTemp->rpdCallByrefRegs;
3204+
byrefRegMask = 0;
3205+
3206+
// The order here is fixed: it must agree with the order assumed in eetwain.
3207+
// NB: x86 GC decoder does not report return registers at call sites.
3208+
static const regNumber calleeSaveOrder[] = {REG_EDI, REG_ESI, REG_EBX, REG_EBP};
3209+
for (unsigned i = 0; i < ArrLen(calleeSaveOrder); i++)
3210+
{
3211+
if ((genRegPtrTemp->rpdCallGCrefRegs & (1 << (calleeSaveOrder[i] - REG_INT_FIRST))) != 0)
3212+
{
3213+
gcrefRegMask |= 1u << i;
3214+
}
3215+
if ((genRegPtrTemp->rpdCallByrefRegs & (1 << (calleeSaveOrder[i] - REG_INT_FIRST))) != 0)
3216+
{
3217+
byrefRegMask |= 1u << i;
3218+
}
3219+
}
32053220

32063221
assert((gcrefRegMask & byrefRegMask) == 0);
32073222

@@ -4465,8 +4480,8 @@ void GCInfo::gcMakeRegPtrTable(
44654480
assert(call->u1.cdArgMask == 0 && call->cdArgCnt == 0);
44664481

44674482
// Other than that, we just have to deal with the regmasks.
4468-
regMaskSmall gcrefRegMask = call->cdGCrefRegs & RBM_CALL_GC_REGS.GetIntRegSet();
4469-
regMaskSmall byrefRegMask = call->cdByrefRegs & RBM_CALL_GC_REGS.GetIntRegSet();
4483+
regMaskSmall gcrefRegMask = call->cdGCrefRegs;
4484+
regMaskSmall byrefRegMask = call->cdByrefRegs;
44704485

44714486
assert((gcrefRegMask & byrefRegMask) == 0);
44724487

@@ -4552,11 +4567,8 @@ void GCInfo::gcMakeRegPtrTable(
45524567
{
45534568
// This is a true call site.
45544569

4555-
regMaskSmall gcrefRegMask =
4556-
genRegMaskFromCalleeSavedMask(genRegPtrTemp->rpdCallGCrefRegs).GetIntRegSet();
4557-
4558-
regMaskSmall byrefRegMask =
4559-
genRegMaskFromCalleeSavedMask(genRegPtrTemp->rpdCallByrefRegs).GetIntRegSet();
4570+
regMaskSmall gcrefRegMask = regMaskSmall(genRegPtrTemp->rpdCallGCrefRegs << REG_INT_FIRST);
4571+
regMaskSmall byrefRegMask = regMaskSmall(genRegPtrTemp->rpdCallByrefRegs << REG_INT_FIRST);
45604572

45614573
assert((gcrefRegMask & byrefRegMask) == 0);
45624574

src/coreclr/jit/jitgcinfo.h

+9-6
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,13 @@ class GCInfo
162162
regMaskSmall rpdDel; // regptr bitset being removed
163163
} rpdCompiler;
164164

165-
unsigned short rpdPtrArg; // arg offset or popped arg count
165+
struct
166+
{
167+
// Registers after call containing GC/byref (index 0 = REG_INT_FIRST)
168+
unsigned int rpdCallGCrefRegs;
169+
unsigned int rpdCallByrefRegs;
170+
unsigned short rpdPtrArg; // arg offset or popped arg count
171+
};
166172
};
167173

168174
#ifndef JIT32_GCENCODER
@@ -182,11 +188,8 @@ class GCInfo
182188
return (GCtype)rpdGCtype;
183189
}
184190

185-
unsigned short rpdIsThis : 1; // is it the 'this' pointer
186-
unsigned short rpdCall : 1; // is this a true call site?
187-
unsigned short : 1; // Padding bit, so next two start on a byte boundary
188-
unsigned short rpdCallGCrefRegs : CNT_CALL_GC_REGS; // Callee-saved and return registers containing GC pointers.
189-
unsigned short rpdCallByrefRegs : CNT_CALL_GC_REGS; // Callee-saved and return registers containing byrefs.
191+
unsigned short rpdIsThis : 1; // is it the 'this' pointer
192+
unsigned short rpdCall : 1; // is this a true call site?
190193

191194
#ifndef JIT32_GCENCODER
192195
bool rpdIsCallInstr()

src/coreclr/jit/regset.cpp

-21
Original file line numberDiff line numberDiff line change
@@ -944,27 +944,6 @@ regNumber genRegArgNext(regNumber argReg)
944944
}
945945
}
946946

947-
/*****************************************************************************
948-
*
949-
* The following table determines the order in which callee registers
950-
* are encoded in GC information at call sites.
951-
*/
952-
953-
const regMaskTP raRbmCalleeSaveOrder[] = {RBM_CALL_GC_REGS_ORDER};
954-
955-
regMaskTP genRegMaskFromCalleeSavedMask(unsigned short calleeSaveMask)
956-
{
957-
regMaskTP res = 0;
958-
for (int i = 0; i < CNT_CALL_GC_REGS; i++)
959-
{
960-
if ((calleeSaveMask & (1 << i)) != 0)
961-
{
962-
res |= raRbmCalleeSaveOrder[i];
963-
}
964-
}
965-
return res;
966-
}
967-
968947
/*****************************************************************************
969948
*
970949
* Initializes the spill code. Should be called once per function compiled.

src/coreclr/jit/target.h

+5-10
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,11 @@ struct regMaskTP
379379
#endif
380380
}
381381

382+
static regMaskTP FromIntRegSet(SingleTypeRegSet intRegs)
383+
{
384+
return regMaskTP(intRegs);
385+
}
386+
382387
void operator|=(const regMaskTP& second)
383388
{
384389
low |= second.getLow();
@@ -1066,16 +1071,6 @@ inline SingleTypeRegSet getSingleTypeRegMask(regNumber reg, var_types regType)
10661071
return regMask;
10671072
}
10681073

1069-
/*****************************************************************************
1070-
*
1071-
* These arrays list the callee-saved register numbers (and bitmaps, respectively) for
1072-
* the current architecture.
1073-
*/
1074-
extern const regMaskTP raRbmCalleeSaveOrder[CNT_CALL_GC_REGS];
1075-
1076-
// This method takes a "compact" bitset of the callee-saved registers, and "expands" it to a full register mask.
1077-
regMaskTP genRegMaskFromCalleeSavedMask(unsigned short);
1078-
10791074
/*****************************************************************************
10801075
*
10811076
* Assumes that "reg" is of the given "type". Return the next unused reg number after "reg"

src/coreclr/jit/targetamd64.h

-8
Original file line numberDiff line numberDiff line change
@@ -300,24 +300,19 @@
300300
#ifdef UNIX_AMD64_ABI
301301
#define CNT_CALLEE_SAVED (5 + REG_ETW_FRAMED_EBP_COUNT)
302302
#define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
303-
#define CNT_CALL_GC_REGS (CNT_CALLEE_SAVED + 2)
304303

305304
#define CNT_CALLEE_TRASH_INT_INIT (9)
306305
#define CNT_CALLEE_TRASH_HIGHINT (8)
307306

308307
#define CNT_CALLEE_SAVED_FLOAT (0)
309308
#define CNT_CALLEE_TRASH_FLOAT_INIT (16)
310309
#define CNT_CALLEE_TRASH_HIGHFLOAT (16)
311-
/* NOTE: Sync with variable name defined in compiler.h */
312-
#define RBM_CALL_GC_REGS_ORDER RBM_EBX,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15,RBM_INTRET,RBM_INTRET_1
313-
#define RBM_CALL_GC_REGS (RBM_EBX|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15|RBM_INTRET|RBM_INTRET_1)
314310

315311
// For SysV we have more volatile registers so we do not save any callee saves for EnC.
316312
#define RBM_ENC_CALLEE_SAVED 0
317313
#else // !UNIX_AMD64_ABI
318314
#define CNT_CALLEE_SAVED (7 + REG_ETW_FRAMED_EBP_COUNT)
319315
#define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED)
320-
#define CNT_CALL_GC_REGS (CNT_CALLEE_SAVED + 1)
321316

322317
#define CNT_CALLEE_TRASH_INT_INIT (7)
323318
#define CNT_CALLEE_TRASH_HIGHINT (8)
@@ -326,9 +321,6 @@
326321
#define CNT_CALLEE_SAVED_FLOAT (10)
327322
#define CNT_CALLEE_TRASH_FLOAT_INIT (6)
328323
#define CNT_CALLEE_TRASH_HIGHFLOAT (16)
329-
/* NOTE: Sync with variable name defined in compiler.h */
330-
#define RBM_CALL_GC_REGS_ORDER RBM_EBX,RBM_ESI,RBM_EDI,RBM_ETW_FRAMED_EBP_LIST RBM_R12,RBM_R13,RBM_R14,RBM_R15,RBM_INTRET
331-
#define RBM_CALL_GC_REGS (RBM_EBX|RBM_ESI|RBM_EDI|RBM_ETW_FRAMED_EBP|RBM_R12|RBM_R13|RBM_R14|RBM_R15|RBM_INTRET)
332324

333325
// Callee-preserved registers we always save and allow use of for EnC code, since there are quite few volatile registers.
334326
#define RBM_ENC_CALLEE_SAVED (RBM_RSI | RBM_RDI)

src/coreclr/jit/targetarm.h

-4
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,9 @@
8989
#define RBM_LOW_REGS (RBM_R0|RBM_R1|RBM_R2|RBM_R3|RBM_R4|RBM_R5|RBM_R6|RBM_R7)
9090
#define RBM_HIGH_REGS (RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_R12|RBM_SP|RBM_LR|RBM_PC)
9191

92-
#define RBM_CALL_GC_REGS_ORDER RBM_R4,RBM_R5,RBM_R6,RBM_R7,RBM_R8,RBM_R9,RBM_R10,RBM_R11,RBM_INTRET
93-
#define RBM_CALL_GC_REGS (RBM_R4|RBM_R5|RBM_R6|RBM_R7|RBM_R8|RBM_R9|RBM_R10|RBM_R11|RBM_INTRET)
94-
9592
#define CNT_CALLEE_SAVED (8)
9693
#define CNT_CALLEE_TRASH (6)
9794
#define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
98-
#define CNT_CALL_GC_REGS (CNT_CALLEE_SAVED+1)
9995

10096
#define CNT_CALLEE_SAVED_FLOAT (16)
10197
#define CNT_CALLEE_TRASH_FLOAT (16)

src/coreclr/jit/targetarm64.h

-4
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,9 @@
108108
REG_V12, REG_V13, REG_V14, REG_V15, \
109109
REG_V3, REG_V2, REG_V1, REG_V0
110110

111-
#define RBM_CALL_GC_REGS_ORDER RBM_R19,RBM_R20,RBM_R21,RBM_R22,RBM_R23,RBM_R24,RBM_R25,RBM_R26,RBM_R27,RBM_R28,RBM_INTRET,RBM_INTRET_1
112-
#define RBM_CALL_GC_REGS (RBM_R19|RBM_R20|RBM_R21|RBM_R22|RBM_R23|RBM_R24|RBM_R25|RBM_R26|RBM_R27|RBM_R28|RBM_INTRET|RBM_INTRET_1)
113-
114111
#define CNT_CALLEE_SAVED (11)
115112
#define CNT_CALLEE_TRASH (17)
116113
#define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
117-
#define CNT_CALL_GC_REGS (CNT_CALLEE_SAVED+2)
118114

119115
#define CNT_CALLEE_SAVED_FLOAT (8)
120116
#define CNT_CALLEE_TRASH_FLOAT (24)

src/coreclr/jit/targetx86.h

-7
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,9 @@
143143
#define REG_VAR_ORDER REG_EAX,REG_EDX,REG_ECX,REG_ESI,REG_EDI,REG_EBX
144144
#define MAX_VAR_ORDER_SIZE 6
145145

146-
// The order here is fixed: it must agree with an order assumed in eetwain...
147-
// NB: x86 GC decoder does not report return registers at call sites.
148-
#define RBM_CALL_GC_REGS_ORDER RBM_EDI,RBM_ESI,RBM_EBX,RBM_EBP
149-
#define RBM_CALL_GC_REGS (RBM_EDI|RBM_ESI|RBM_EBX|RBM_EBP)
150-
151146
#define CNT_CALLEE_SAVED (4)
152147
#define CNT_CALLEE_TRASH (3)
153148
#define CNT_CALLEE_ENREG (CNT_CALLEE_SAVED-1)
154-
// NB: x86 GC decoder does not report return registers at call sites.
155-
#define CNT_CALL_GC_REGS (CNT_CALLEE_SAVED)
156149

157150
#define CNT_CALLEE_SAVED_FLOAT (0)
158151
#define CNT_CALLEE_TRASH_FLOAT (6)

0 commit comments

Comments
 (0)