Skip to content

Commit 0f5c53d

Browse files
committed
NOP
1 parent a1b9329 commit 0f5c53d

10 files changed

+169
-21
lines changed

src/coreclr/jit/codegencommon.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -893,8 +893,8 @@ void CodeGen::genLogLabel(BasicBlock* bb)
893893
void CodeGen::genDefineTempLabel(BasicBlock* label)
894894
{
895895
genLogLabel(label);
896-
label->bbEmitCookie = GetEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
897-
gcInfo.gcRegByrefSetCur DEBUG_ARG(label));
896+
label->bbEmitCookie =
897+
GetEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur);
898898
}
899899

900900
// genDefineInlineTempLabel: Define an inline label that does not affect the GC

src/coreclr/jit/codegenlinear.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ void CodeGen::genCodeForBBlist()
348348
// Mark a label and update the current set of live GC refs
349349

350350
block->bbEmitCookie = GetEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
351-
gcInfo.gcRegByrefSetCur DEBUG_ARG(block));
351+
gcInfo.gcRegByrefSetCur, block->Prev());
352352
}
353353

354354
if (block->IsFirstColdBlock(compiler))

src/coreclr/jit/emit.cpp

+45-3
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,10 @@ void emitter::emitCreatePlaceholderIG(insGroupPlaceholderType igType,
22322232
emitCurIG->igFlags &= ~IGF_PROPAGATE_MASK;
22332233
}
22342234

2235+
// since we have emitted a placeholder, the last ins is not longer the last.
2236+
emitLastIns = nullptr;
2237+
emitLastInsIG = nullptr;
2238+
22352239
#ifdef DEBUG
22362240
if (emitComp->verbose)
22372241
{
@@ -2895,10 +2899,36 @@ bool emitter::emitNoGChelper(CORINFO_METHOD_HANDLE methHnd)
28952899
* Mark the current spot as having a label.
28962900
*/
28972901

2898-
void* emitter::emitAddLabel(VARSET_VALARG_TP GCvars,
2899-
regMaskTP gcrefRegs,
2900-
regMaskTP byrefRegs DEBUG_ARG(BasicBlock* block))
2902+
void* emitter::emitAddLabel(VARSET_VALARG_TP GCvars, regMaskTP gcrefRegs, regMaskTP byrefRegs, BasicBlock* prevBlock)
29012903
{
2904+
if (emitLastInsIsCallWithGC())
2905+
{
2906+
// We have just emitted a call that can do GC and conservatively recorded what is alive after the call.
2907+
// Now we see that the next instruction may be reachable by a branch with a different liveness.
2908+
// We want to maintain the invariant that the GC info at IP after a GC-capable call is the same
2909+
// regardless how it is reached.
2910+
// One way to fix this is to fish out the call instruction and patch its GC info, but we must be
2911+
// certain that the current IP is indeed reachable after the call.
2912+
// Another way it to add an instruction (NOP or BRK) after the call.
2913+
if (emitThisGCrefRegs != gcrefRegs || emitThisByrefRegs != byrefRegs ||
2914+
!VarSetOps::Equal(emitComp, emitThisGCrefVars, GCvars))
2915+
{
2916+
if (prevBlock->KindIs(BBJ_THROW))
2917+
{
2918+
emitIns(INS_BREAKPOINT);
2919+
}
2920+
else
2921+
{
2922+
// other block kinds should emit something at the end that is not a call.
2923+
assert(prevBlock->KindIs(BBJ_ALWAYS));
2924+
// CONSIDER: We could patch up the previous call instruction with new GC info instead.
2925+
// But that will need to be coordinated with how the GC info vor variables is used.
2926+
// We currently apply that info to the instruction before the call. It may need to change.
2927+
emitIns(INS_nop);
2928+
}
2929+
}
2930+
}
2931+
29022932
/* Create a new IG if the current one is non-empty */
29032933

29042934
if (emitCurIGnonEmpty())
@@ -3663,6 +3693,7 @@ emitter::instrDesc* emitter::emitNewInstrCallInd(int argCnt,
36633693

36643694
/* Make sure we didn't waste space unexpectedly */
36653695
assert(!id->idIsLargeCns());
3696+
id->idSetIsCall();
36663697

36673698
#ifdef TARGET_XARCH
36683699
/* Store the displacement and make sure the value fit */
@@ -3742,6 +3773,7 @@ emitter::instrDesc* emitter::emitNewInstrCallDir(int argCnt,
37423773

37433774
/* Make sure we didn't waste space unexpectedly */
37443775
assert(!id->idIsLargeCns());
3776+
id->idSetIsCall();
37453777

37463778
/* Save the live GC registers in the unused register fields */
37473779
assert((gcrefRegs & RBM_CALLEE_TRASH) == 0);
@@ -8754,6 +8786,16 @@ void emitter::emitUpdateLiveGCvars(VARSET_VALARG_TP vars, BYTE* addr)
87548786
emitThisGCrefVset = true;
87558787
}
87568788

8789+
/*****************************************************************************
8790+
*
8791+
* Last emitted instruction is a call and it is not a NoGC call.
8792+
*/
8793+
8794+
bool emitter::emitLastInsIsCallWithGC()
8795+
{
8796+
return emitLastIns != nullptr && emitLastIns->idIsCall() && !emitLastIns->idIsNoGC();
8797+
}
8798+
87578799
/*****************************************************************************
87588800
*
87598801
* Record a call location for GC purposes (we know that this is a method that

src/coreclr/jit/emit.h

+24-10
Original file line numberDiff line numberDiff line change
@@ -772,10 +772,10 @@ class emitter
772772
// loongarch64: 28 bits
773773
// risc-v: 28 bits
774774

775-
unsigned _idSmallDsc : 1; // is this a "small" descriptor?
776-
unsigned _idLargeCns : 1; // does a large constant follow?
777-
unsigned _idLargeDsp : 1; // does a large displacement follow?
778-
unsigned _idLargeCall : 1; // large call descriptor used
775+
unsigned _idSmallDsc : 1; // is this a "small" descriptor?
776+
unsigned _idLargeCns : 1; // does a large constant follow? (or if large call descriptor used)
777+
unsigned _idLargeDsp : 1; // does a large displacement follow?
778+
unsigned _idCall : 1; // this is a call
779779

780780
// We have several pieces of information we need to encode but which are only applicable
781781
// to a subset of instrDescs. To accommodate that, we define a several _idCustom# bitfields
@@ -1575,7 +1575,7 @@ class emitter
15751575

15761576
bool idIsLargeCns() const
15771577
{
1578-
return _idLargeCns != 0;
1578+
return _idLargeCns != 0 && !idIsCall();
15791579
}
15801580
void idSetIsLargeCns()
15811581
{
@@ -1595,13 +1595,23 @@ class emitter
15951595
_idLargeDsp = 0;
15961596
}
15971597

1598+
bool idIsCall() const
1599+
{
1600+
return _idCall != 0;
1601+
}
1602+
void idSetIsCall()
1603+
{
1604+
_idCall = 1;
1605+
}
1606+
15981607
bool idIsLargeCall() const
15991608
{
1600-
return _idLargeCall != 0;
1609+
return idIsCall() && _idLargeCns == 1;
16011610
}
16021611
void idSetIsLargeCall()
16031612
{
1604-
_idLargeCall = 1;
1613+
idSetIsCall();
1614+
_idLargeCns = 1;
16051615
}
16061616

16071617
bool idIsBound() const
@@ -2871,9 +2881,11 @@ class emitter
28712881
// Mark this instruction group as having a label; return the new instruction group.
28722882
// Sets the emitter's record of the currently live GC variables
28732883
// and registers.
2874-
void* emitAddLabel(VARSET_VALARG_TP GCvars,
2875-
regMaskTP gcrefRegs,
2876-
regMaskTP byrefRegs DEBUG_ARG(BasicBlock* block = nullptr));
2884+
// prevBlock is passed when starting a new block.
2885+
void* emitAddLabel(VARSET_VALARG_TP GCvars,
2886+
regMaskTP gcrefRegs,
2887+
regMaskTP byrefRegs,
2888+
BasicBlock* prevBlock = nullptr);
28772889

28782890
// Same as above, except the label is added and is conceptually "inline" in
28792891
// the current block. Thus it extends the previous block and the emitter
@@ -3204,6 +3216,8 @@ class emitter
32043216

32053217
void emitRecordGCcall(BYTE* codePos, unsigned char callInstrSize);
32063218

3219+
bool emitLastInsIsCallWithGC();
3220+
32073221
// Helpers for the above
32083222

32093223
void emitStackPushLargeStk(BYTE* addr, GCtype gcType, unsigned count = 1);

src/coreclr/jit/emitarm.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -4754,6 +4754,16 @@ void emitter::emitIns_Call(EmitCallType callType,
47544754

47554755
/* Update the emitter's live GC ref sets */
47564756

4757+
// If the method returns a GC ref, mark R0 appropriately
4758+
if (retSize == EA_GCREF)
4759+
{
4760+
gcrefRegs |= RBM_R0;
4761+
}
4762+
else if (retSize == EA_BYREF)
4763+
{
4764+
byrefRegs |= RBM_R0;
4765+
}
4766+
47574767
VarSetOps::Assign(emitComp, emitThisGCrefVars, ptrVars);
47584768
emitThisGCrefRegs = gcrefRegs;
47594769
emitThisByrefRegs = byrefRegs;

src/coreclr/jit/emitarm64.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -9020,6 +9020,26 @@ void emitter::emitIns_Call(EmitCallType callType,
90209020

90219021
/* Update the emitter's live GC ref sets */
90229022

9023+
// If the method returns a GC ref, mark RBM_INTRET appropriately
9024+
if (retSize == EA_GCREF)
9025+
{
9026+
gcrefRegs |= RBM_INTRET;
9027+
}
9028+
else if (retSize == EA_BYREF)
9029+
{
9030+
byrefRegs |= RBM_INTRET;
9031+
}
9032+
9033+
// If is a multi-register return method is called, mark RBM_INTRET_1 appropriately
9034+
if (secondRetSize == EA_GCREF)
9035+
{
9036+
gcrefRegs |= RBM_INTRET_1;
9037+
}
9038+
else if (secondRetSize == EA_BYREF)
9039+
{
9040+
byrefRegs |= RBM_INTRET_1;
9041+
}
9042+
90239043
VarSetOps::Assign(emitComp, emitThisGCrefVars, ptrVars);
90249044
emitThisGCrefRegs = gcrefRegs;
90259045
emitThisByrefRegs = byrefRegs;

src/coreclr/jit/emitloongarch64.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -2464,6 +2464,26 @@ void emitter::emitIns_Call(EmitCallType callType,
24642464

24652465
/* Update the emitter's live GC ref sets */
24662466

2467+
// If the method returns a GC ref, mark RBM_INTRET appropriately
2468+
if (retSize == EA_GCREF)
2469+
{
2470+
gcrefRegs |= RBM_INTRET;
2471+
}
2472+
else if (retSize == EA_BYREF)
2473+
{
2474+
byrefRegs |= RBM_INTRET;
2475+
}
2476+
2477+
// If is a multi-register return method is called, mark RBM_INTRET_1 appropriately
2478+
if (secondRetSize == EA_GCREF)
2479+
{
2480+
gcrefRegs |= RBM_INTRET_1;
2481+
}
2482+
else if (secondRetSize == EA_BYREF)
2483+
{
2484+
byrefRegs |= RBM_INTRET_1;
2485+
}
2486+
24672487
VarSetOps::Assign(emitComp, emitThisGCrefVars, ptrVars);
24682488
emitThisGCrefRegs = gcrefRegs;
24692489
emitThisByrefRegs = byrefRegs;

src/coreclr/jit/emitriscv64.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,26 @@ void emitter::emitIns_Call(EmitCallType callType,
13731373

13741374
/* Update the emitter's live GC ref sets */
13751375

1376+
// If the method returns a GC ref, mark RBM_INTRET appropriately
1377+
if (retSize == EA_GCREF)
1378+
{
1379+
gcrefRegs |= RBM_INTRET;
1380+
}
1381+
else if (retSize == EA_BYREF)
1382+
{
1383+
byrefRegs |= RBM_INTRET;
1384+
}
1385+
1386+
// If is a multi-register return method is called, mark RBM_INTRET_1 appropriately
1387+
if (secondRetSize == EA_GCREF)
1388+
{
1389+
gcrefRegs |= RBM_INTRET_1;
1390+
}
1391+
else if (secondRetSize == EA_BYREF)
1392+
{
1393+
byrefRegs |= RBM_INTRET_1;
1394+
}
1395+
13761396
VarSetOps::Assign(emitComp, emitThisGCrefVars, ptrVars);
13771397
emitThisGCrefRegs = gcrefRegs;
13781398
emitThisByrefRegs = byrefRegs;

src/coreclr/jit/emitxarch.cpp

+25-3
Original file line numberDiff line numberDiff line change
@@ -9578,6 +9578,28 @@ void emitter::emitIns_Call(EmitCallType callType,
95789578

95799579
/* Update the emitter's live GC ref sets */
95809580

9581+
// If the method returns a GC ref, mark EAX appropriately
9582+
if (retSize == EA_GCREF)
9583+
{
9584+
gcrefRegs |= RBM_EAX;
9585+
}
9586+
else if (retSize == EA_BYREF)
9587+
{
9588+
byrefRegs |= RBM_EAX;
9589+
}
9590+
9591+
#ifdef UNIX_AMD64_ABI
9592+
// If is a multi-register return method is called, mark RDX appropriately (for System V AMD64).
9593+
if (secondRetSize == EA_GCREF)
9594+
{
9595+
gcrefRegs |= RBM_RDX;
9596+
}
9597+
else if (secondRetSize == EA_BYREF)
9598+
{
9599+
byrefRegs |= RBM_RDX;
9600+
}
9601+
#endif // UNIX_AMD64_ABI
9602+
95819603
VarSetOps::Assign(emitComp, emitThisGCrefVars, ptrVars);
95829604
emitThisGCrefRegs = gcrefRegs;
95839605
emitThisByrefRegs = byrefRegs;
@@ -16548,9 +16570,9 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
1654816570
#ifdef TARGET_X86
1654916571
dst += emitOutputWord(dst, code | 0x0500);
1655016572
#else // TARGET_AMD64
16551-
// Amd64: addr fits within 32-bits and can be encoded as a displacement relative to zero.
16552-
// This addr mode should never be used while generating relocatable ngen code nor if
16553-
// the addr can be encoded as pc-relative address.
16573+
// Amd64: addr fits within 32-bits and can be encoded as a displacement relative to zero.
16574+
// This addr mode should never be used while generating relocatable ngen code nor if
16575+
// the addr can be encoded as pc-relative address.
1655416576
noway_assert(!emitComp->opts.compReloc);
1655516577
noway_assert(codeGen->genAddrRelocTypeHint((size_t)addr) != IMAGE_REL_BASED_REL32);
1655616578
noway_assert(static_cast<int>(reinterpret_cast<intptr_t>(addr)) == (ssize_t)addr);

src/coreclr/jit/jitgcinfo.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ class GCInfo
183183
}
184184

185185
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
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
188188
unsigned short rpdCallGCrefRegs : CNT_CALL_GC_REGS; // Callee-saved and return registers containing GC pointers.
189189
unsigned short rpdCallByrefRegs : CNT_CALL_GC_REGS; // Callee-saved and return registers containing byrefs.
190190

0 commit comments

Comments
 (0)