From 12e3774bc3e8838a162a8124a83680d7328e007c Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Mon, 30 Mar 2026 00:04:26 +0300 Subject: [PATCH 1/2] Remove single-IG prolog restriction --- src/coreclr/jit/codegenarm64.cpp | 2 +- src/coreclr/jit/codegencommon.cpp | 2 +- src/coreclr/jit/codegenloongarch64.cpp | 2 +- src/coreclr/jit/codegenriscv64.cpp | 2 +- src/coreclr/jit/codegenxarch.cpp | 2 +- src/coreclr/jit/emit.cpp | 148 ++++++++++++------------- src/coreclr/jit/emit.h | 68 ++++++------ src/coreclr/jit/emitinl.h | 4 +- src/coreclr/jit/emitloongarch64.cpp | 14 +-- src/coreclr/jit/emitpub.h | 8 +- src/coreclr/jit/emitxarch.cpp | 3 +- src/coreclr/jit/unwind.cpp | 25 +---- 12 files changed, 122 insertions(+), 158 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 47ecfbea7dc7de..3733e587b77e8c 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -3816,7 +3816,7 @@ void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) // void CodeGen::genFtnEntry(GenTree* treeNode) { - GetEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, GetEmitter()->emitPrologIG, treeNode->GetRegNum()); + GetEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, GetEmitter()->emitGetFirstPrologIG(), treeNode->GetRegNum()); genProduceReg(treeNode); } diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 2fe77b1a3294b0..8eb1e7d262c55a 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -5582,7 +5582,7 @@ void CodeGen::genFnProlog() // For OSR we may have a zero-length prolog. That's not supported // when the method must report a generics context,/ so add a nop if so. // - if (m_compiler->opts.IsOSR() && (GetEmitter()->emitGetPrologOffsetEstimate() == 0) && + if (m_compiler->opts.IsOSR() && (GetEmitter()->emitGetCurrentCodeOffsetFrom(nullptr) == 0) && (m_compiler->lvaReportParamTypeArg() || m_compiler->lvaKeepAliveAndReportThis())) { JITDUMP("OSR: prolog was zero length and has generic context to report: adding nop to pad prolog.\n"); diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index 26a80d31204e52..7e5aa1d9409847 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -2348,7 +2348,7 @@ void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) // void CodeGen::genFtnEntry(GenTree* treeNode) { - GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, GetEmitter()->emitPrologIG, treeNode->GetRegNum()); + GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, GetEmitter()->emitGetFirstPrologIG(), treeNode->GetRegNum()); genProduceReg(treeNode); } diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index 540d92a906023c..c7ee5c185d3608 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -2323,7 +2323,7 @@ void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) // void CodeGen::genFtnEntry(GenTree* treeNode) { - GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, GetEmitter()->emitPrologIG, treeNode->GetRegNum()); + GetEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, GetEmitter()->emitGetFirstPrologIG(), treeNode->GetRegNum()); genProduceReg(treeNode); } diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index b8d5ffb8f9452c..ebbc84af8b984c 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -4319,7 +4319,7 @@ void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) // void CodeGen::genFtnEntry(GenTree* treeNode) { - GetEmitter()->emitIns_R_L(INS_lea, EA_PTR_DSP_RELOC, GetEmitter()->emitPrologIG, treeNode->GetRegNum()); + GetEmitter()->emitIns_R_L(INS_lea, EA_PTR_DSP_RELOC, GetEmitter()->emitGetFirstPrologIG(), treeNode->GetRegNum()); genProduceReg(treeNode); } diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index ea343f496cce66..37f7b074d6bf63 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -71,26 +71,6 @@ int emitLocation::GetInsOffset() const return emitGetInsOfsFromCodePos(codePos); } -// Get the instruction offset in the current instruction region, which must be a funclet prolog. -// This is used to find an instruction offset used in unwind data. -UNATIVE_OFFSET emitLocation::GetFuncletPrologOffset(emitter* emit) const -{ - assert(ig->igFuncIdx != 0); - assert((ig->igFlags & IGF_FUNCLET_PROLOG) != 0); - assert((ig->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0); - assert(GetInsOffset() == 0); - - unsigned offset = 0; - insGroup* lastIG = ig; - while (lastIG != emit->emitCurIG) - { - offset += lastIG->igSize; - lastIG = lastIG->igNext; - } - assert((lastIG->igFlags & IGF_FUNCLET_PROLOG) != 0); - - return offset + emit->emitCurIGsize; -} //------------------------------------------------------------------------ // IsPreviousInsNum: Returns true if the emitter is on the next instruction // of the same group as this emitLocation. @@ -1284,7 +1264,7 @@ insGroup* emitter::emitSavIG(bool emitAdd) if (last != nullptr) { // Append the jump(s) from this IG to the global list - bool prologJump = (ig == emitPrologIG); + bool prologJump = emitIGisInProlog(ig); if ((emitJumpList == nullptr) || prologJump) { last->idjNext = emitJumpList; @@ -1371,6 +1351,8 @@ void emitter::emitBegFN(bool hasFramePtr emitChkAlign = chkAlign; #endif + emitPrologEndPos.Init(); + /* We have no epilogs yet */ emitEpilogSize = 0; @@ -1467,7 +1449,8 @@ void emitter::emitBegFN(bool hasFramePtr emitNxtIGnum = 1; - emitPrologIG = emitIGlist = emitIGlast = emitCurIG = ig = emitAllocIG(); + emitIGlist = emitIGlast = emitCurIG = ig = emitAllocIG(); + emitCurIG->igFlags |= (IGF_PROLOG | IGF_OUT_OF_ORDER_HEAD); emitLastIns = nullptr; emitLastInsIG = nullptr; @@ -1484,8 +1467,10 @@ void emitter::emitBegFN(bool hasFramePtr #endif /* Append another group, to start generating the method body */ - emitNewIG(); + + /* The group after the placeholder prolog group doesn't get the "propagate" flags */ + emitCurIG->igFlags &= ~IGF_PROPAGATE_MASK; } /***************************************************************************** @@ -1725,8 +1710,8 @@ void* emitter::emitAllocAnyInstr(size_t sz, emitAttr opsz) { #ifdef DEBUG // Under STRESS_EMITTER, put every instruction in its own instruction group. - if (m_compiler->compStressCompile(Compiler::STRESS_EMITTER, 1) && emitCurIGinsCnt && !emitIGisInProlog(emitCurIG) && - !emitIGisInFuncletProlog(emitCurIG) && !emitCurIG->endsWithAlignInstr()) + if (m_compiler->compStressCompile(Compiler::STRESS_EMITTER, 1) && (emitCurIGinsCnt != 0) && + !emitCurIG->endsWithAlignInstr()) { emitNxtIG(true); } @@ -1886,8 +1871,6 @@ void* emitter::emitAllocAnyInstr(size_t sz, emitAttr opsz) // void emitter::emitCheckIGList() { - assert(emitPrologIG != nullptr); - #if EMIT_BACKWARDS_NAVIGATION struct IGIDPair { @@ -1919,17 +1902,18 @@ void emitter::emitCheckIGList() assert((currIG->igFlags & IGF_EXTEND) == 0); // First IG must be the function prolog. - assert(currIG == emitPrologIG); + assert((currIG->igFlags & IGF_PROLOG) != 0); } - if (currIG == emitPrologIG) + if ((currIG->igFlags & IGF_PROLOG) != 0) { // If we're in the function prolog, we can't be in any other prolog or epilog. assert((currIG->igFlags & (IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG | IGF_EPILOG)) == 0); } // An IG can have at most one of the prolog and epilog flags set. - assert(genCountBits((unsigned)currIG->igFlags & (IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG | IGF_EPILOG)) <= 1); + assert(genCountBits((unsigned)currIG->igFlags & + (IGF_PROLOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG | IGF_EPILOG)) <= 1); // An IG can't have both IGF_HAS_ALIGN and IGF_REMOVED_ALIGN. assert(genCountBits((unsigned)currIG->igFlags & (IGF_HAS_ALIGN | IGF_REMOVED_ALIGN)) <= 1); @@ -1945,16 +1929,13 @@ void emitter::emitCheckIGList() // not be EXTEND groups, and would there be a benefit to that? Since epilogs are NOGC // it would help eliminate NOGC EXTEND groups. // - // Note that function prologs must currently exist entirely within one IG and there is - // no flag to indicate a function prolog (the `emitPrologIG` variable points to the single - // unique prolog IG). - // // Thus, we can't have this assert: // assert((currIG->igFlags & (IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG | IGF_EPILOG)) == // (prevIG->igFlags & (IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG | IGF_EPILOG))); - // If this is a funclet prolog IG, then it can only extend another funclet prolog IG. - assert((currIG->igFlags & IGF_FUNCLET_PROLOG) == (prevIG->igFlags & IGF_FUNCLET_PROLOG)); + // If this is a prolog IG, then it can only extend another prolog IG. + assert((currIG->igFlags & (IGF_PROLOG | IGF_FUNCLET_PROLOG)) == + (prevIG->igFlags & (IGF_PROLOG | IGF_FUNCLET_PROLOG))); // If this is a function epilog IG, it can't extend a funclet prolog or funclet epilog IG. if (currIG->igFlags & IGF_EPILOG) @@ -2053,8 +2034,7 @@ void emitter::emitBegProlog() emitForceNewIG = false; /* Switch to the pre-allocated prolog IG */ - - emitGenIG(emitPrologIG); + emitGenIG(emitGetFirstPrologIG()); /* Nothing is live on entry to the prolog */ @@ -2067,21 +2047,6 @@ void emitter::emitBegProlog() emitPrevByrefRegs = RBM_NONE; } -/***************************************************************************** - * - * Return the code offset of the current location in the prolog. - */ - -unsigned emitter::emitGetPrologOffsetEstimate() -{ - /* For now only allow a single prolog ins group */ - - assert(emitPrologIG); - assert(emitPrologIG == emitCurIG); - - return emitCurIGsize; -} - /***************************************************************************** * * Mark the code offset of the current location as the end of the prolog, @@ -2091,13 +2056,7 @@ unsigned emitter::emitGetPrologOffsetEstimate() void emitter::emitMarkPrologEnd() { assert(m_compiler->compGeneratingProlog); - - /* For now only allow a single prolog ins group */ - - assert(emitPrologIG); - assert(emitPrologIG == emitCurIG); - - emitPrologEndPos = emitCurOffset(); + emitPrologEndPos.CaptureLocation(this); } /***************************************************************************** @@ -2114,7 +2073,7 @@ void emitter::emitEndProlog() /* Save the prolog IG if non-empty or if only one block */ - if (emitCurIGnonEmpty() || emitCurIG == emitPrologIG) + if (emitCurIGnonEmpty() || (emitCurIG == emitGetFirstPrologIG())) { emitSavIG(); } @@ -2291,7 +2250,6 @@ void emitter::emitCreatePlaceholderIG(insGroupPlaceholderType igType, emitForceStoreGCState = true; /* The group after the placeholder group doesn't get the "propagate" flags */ - emitCurIG->igFlags &= ~IGF_PROPAGATE_MASK; } @@ -2418,6 +2376,11 @@ void emitter::emitFinishPrologEpilogGeneration() * Common code for prolog / epilog beginning. Convert the placeholder group to actual code IG, * and set it as the current group. */ +insGroup* emitter::emitGetFirstPrologIG() const +{ + assert(emitIGisInProlog(emitIGlist)); + return emitIGlist; +} void emitter::emitBegPrologEpilog(insGroup* igPh) { @@ -4070,6 +4033,14 @@ void emitter::emitDispIGflags(unsigned flags) { printf(", byref"); } + if (flags & IGF_PROLOG) + { + printf(", prolog"); + } + if (flags & IGF_EPILOG) + { + printf(", epilog"); + } if (flags & IGF_FUNCLET_PROLOG) { printf(", funclet prolog"); @@ -4078,10 +4049,6 @@ void emitter::emitDispIGflags(unsigned flags) { printf(", funclet epilog"); } - if (flags & IGF_EPILOG) - { - printf(", epilog"); - } if (flags & IGF_NOGCINTERRUPT) { printf(", nogc"); @@ -4268,10 +4235,6 @@ void emitter::emitDispIG(insGroup* ig, bool displayFunc, bool displayInstruction { printf(" <-- Current IG"); } - if (ig == emitPrologIG) - { - printf(" <-- Prolog IG"); - } } printf("\n"); @@ -4953,9 +4916,6 @@ void emitter::emitJumpDistBind() UNATIVE_OFFSET adjIG; UNATIVE_OFFSET adjLJ; insGroup* lstIG; -#ifdef DEBUG - insGroup* prologIG = emitPrologIG; -#endif // DEBUG int jmp_iteration = 1; @@ -5146,7 +5106,7 @@ void emitter::emitJumpDistBind() assert(lastLJ == nullptr || lastIG != jmp->idjIG || lastLJ->idjOffs < jmp->idjOffs); lastLJ = (lastIG == jmp->idjIG) ? jmp : nullptr; - assert(lastIG == nullptr || lastIG->IsBeforeOrEqual(jmp->idjIG) || jmp->idjIG == prologIG); + assert(lastIG == nullptr || lastIG->IsBeforeOrEqual(jmp->idjIG) || emitIGisInProlog(jmp->idjIG)); lastIG = jmp->idjIG; #endif // DEBUG @@ -7768,7 +7728,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, #endif // DEBUG // Assign the real prolog size - *prologSize = emitCodeOffset(emitPrologIG, emitPrologEndPos); + *prologSize = emitPrologEndPos.CodeOffset(this); /* Return the amount of code we've generated */ @@ -9549,6 +9509,39 @@ UNATIVE_OFFSET emitter::emitCodeOffset(void* blockPtr, unsigned codePos) return ig->igOffs + of; } +//------------------------------------------------------------------------ +// emitGetCurrentCodeOffsetFrom: Get current code offset relative to "ig". +// +// This is used to retrieve the current offset within a prolog being generated +// for unwind info. Thus, the offset we return from here can't later shrink, +// and overestimating the code size of prolog instructions is fatal. +// +// Arguments: +// ig - IG denoting the start of code, "nullptr" for main function prolog +// +// Return Value: +// Effectively " - ig->igOffs". +// +UNATIVE_OFFSET emitter::emitGetCurrentCodeOffsetFrom(insGroup* ig) +{ + if (ig == nullptr) + { + ig = emitGetFirstPrologIG(); + } + assert((ig->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0); + + unsigned igKind = ig->igFlags & (IGF_PROLOG | IGF_FUNCLET_PROLOG); + unsigned offset = 0; + while (ig != emitCurIG) + { + offset += ig->igSize; + ig = ig->igNext; + } + assert((ig->igFlags & igKind) == igKind); + + return offset + emitCurIGsize; +} + /***************************************************************************** * * Record the fact that the given register now contains a live GC ref. @@ -9979,12 +9972,7 @@ void emitter::emitInsertIGAfter(insGroup* insertAfterIG, insGroup* ig) void emitter::emitNxtIG(bool extend) { - /* Right now we don't allow multi-IG prologs */ - - assert(emitCurIG != emitPrologIG); - /* First save the current group */ - emitSavIG(extend); /* Update the GC live sets for the group's start diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index d871a91cd8a516..6a2deec2efc175 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -213,8 +213,6 @@ class emitLocation return true; } - UNATIVE_OFFSET GetFuncletPrologOffset(emitter* emit) const; - bool IsPreviousInsNum(emitter* emit) const; #ifdef DEBUG @@ -293,38 +291,35 @@ struct insGroup insGroup* igLoopBackEdge; // "last" back-edge that branches back to an aligned loop head. #endif -#define IGF_GC_VARS 0x0001 // new set of live GC ref variables -#define IGF_BYREF_REGS 0x0002 // new set of live by-ref registers -#define IGF_FUNCLET_PROLOG 0x0004 // this group belongs to a funclet prolog -#define IGF_FUNCLET_EPILOG 0x0008 // this group belongs to a funclet epilog. -#define IGF_EPILOG 0x0010 // this group belongs to a main function epilog -#define IGF_NOGCINTERRUPT 0x0020 // this IG is in a no-interrupt region (prolog, epilog, etc.) -#define IGF_UPD_ISZ 0x0040 // some instruction sizes updated -#define IGF_PLACEHOLDER 0x0080 // this is a placeholder group, to be filled in later -#define IGF_EXTEND \ - 0x0100 // this block is conceptually an extension of the previous block - // and the emitter should continue to track GC info as if there was no new block. -#define IGF_HAS_ALIGN \ - 0x0200 // this group contains an alignment instruction(s) at the end to align either the next - // IG, or, if this IG contains with an unconditional branch, some subsequent IG. -#define IGF_REMOVED_ALIGN \ - 0x0400 // IG was marked as having an alignment instruction(s), but was later unmarked - // without updating the IG's size/offsets. -#define IGF_HAS_REMOVABLE_JMP 0x0800 // this group ends with an unconditional jump which is a candidate for removal +#define IGF_GC_VARS (1 << 0) // new set of live GC ref variables +#define IGF_BYREF_REGS (1 << 1) // new set of live by-ref registers +#define IGF_PROLOG (1 << 2) // this group belongs to a main function prolog +#define IGF_EPILOG (1 << 3) // this group belongs to a main function epilog +#define IGF_FUNCLET_PROLOG (1 << 4) // this group belongs to a funclet prolog +#define IGF_FUNCLET_EPILOG (1 << 5) // this group belongs to a funclet epilog. +#define IGF_NOGCINTERRUPT (1 << 6) // this IG is in a no-interrupt region (prolog, epilog, etc.) +#define IGF_UPD_ISZ (1 << 7) // some instruction sizes updated +#define IGF_PLACEHOLDER (1 << 8) // this is a placeholder group, to be filled in later +// This block is conceptually an extension of the previous block +// and the emitter should continue to track GC info as if there was no new block. +#define IGF_EXTEND (1 << 9) +// This group contains an alignment instruction(s) at the end to align either the next +// IG, or, if this IG contains with an unconditional branch, some subsequent IG. +#define IGF_HAS_ALIGN (1 << 10) +// IG was marked as having an alignment instruction(s), but was later unmarked +// without updating the IG's size/offsets. +#define IGF_REMOVED_ALIGN (1 << 11) +#define IGF_HAS_REMOVABLE_JMP (1 << 12) // this group ends with an unconditional jump which is a candidate for removal #ifdef TARGET_ARM64 -#define IGF_HAS_REMOVED_INSTR 0x1000 // this group has an instruction that was removed. +#define IGF_HAS_REMOVED_INSTR (1 << 13) // this group has an instruction that was removed. #endif -#define IGF_OUT_OF_ORDER_HEAD 0x2000 // first group (generated in-order) of a region generated out-of-order +#define IGF_OUT_OF_ORDER_HEAD (1 << 14) // first group (generated in-order) of a region generated out-of-order // Mask of IGF_* flags that should be propagated to new blocks when they are created. // This allows prologs and epilogs to be any number of IGs, but still be // automatically marked properly. -#ifdef DEBUG -#define IGF_PROPAGATE_MASK (IGF_EPILOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG) -#else // DEBUG -#define IGF_PROPAGATE_MASK (IGF_EPILOG | IGF_FUNCLET_PROLOG) -#endif // DEBUG -#define IGF_OUT_OF_ORDER_MASK (IGF_EPILOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG) +#define IGF_PROPAGATE_MASK (IGF_PROLOG | IGF_EPILOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG) +#define IGF_OUT_OF_ORDER_MASK (IGF_PROLOG | IGF_EPILOG | IGF_FUNCLET_PROLOG | IGF_FUNCLET_EPILOG) // Try to do better packing based on how large regMaskSmall is (8, 16, or 64 bits). @@ -583,22 +578,22 @@ class emitter static emitAttr emitDecodeSize(emitter::opSize ensz); // Currently, we only allow one IG for the prolog - bool emitIGisInProlog(const insGroup* ig) + bool emitIGisInProlog(const insGroup* ig) const { - return ig == emitPrologIG; + return (ig != nullptr) && ((ig->igFlags & IGF_PROLOG) != 0); } - bool emitIGisInEpilog(const insGroup* ig) + bool emitIGisInEpilog(const insGroup* ig) const { return (ig != nullptr) && ((ig->igFlags & IGF_EPILOG) != 0); } - bool emitIGisInFuncletProlog(const insGroup* ig) + bool emitIGisInFuncletProlog(const insGroup* ig) const { return (ig != nullptr) && ((ig->igFlags & IGF_FUNCLET_PROLOG) != 0); } - bool emitIGisInFuncletEpilog(const insGroup* ig) + bool emitIGisInFuncletEpilog(const insGroup* ig) const { return (ig != nullptr) && ((ig->igFlags & IGF_FUNCLET_EPILOG) != 0); } @@ -2604,7 +2599,7 @@ class emitter /* Method prolog and epilog */ /************************************************************************/ - unsigned emitPrologEndPos; + emitLocation emitPrologEndPos; unsigned emitEpilogCnt; UNATIVE_OFFSET emitEpilogSize; @@ -2649,6 +2644,8 @@ class emitter #endif // JIT32_GCENCODER + insGroup* emitGetFirstPrologIG() const; + void emitBegPrologEpilog(insGroup* igPh); void emitEndPrologEpilog(); @@ -2901,9 +2898,6 @@ class emitter insGroup* emitIGlist; // first instruction group insGroup* emitIGlast; // last instruction group - insGroup* emitIGthis; // issued instruction group - - insGroup* emitPrologIG; // prolog instruction group instrDescJmp* emitJumpList; // list of local jumps in method instrDescJmp* emitJumpLast; // last of local jumps in method diff --git a/src/coreclr/jit/emitinl.h b/src/coreclr/jit/emitinl.h index 88f88713e58b39..ecd74685901e7b 100644 --- a/src/coreclr/jit/emitinl.h +++ b/src/coreclr/jit/emitinl.h @@ -611,9 +611,7 @@ bool emitter::emitGenNoGCLst(Callback& cb, bool skipMainPrologsAndEpilogs /* = f { if (skipMainPrologsAndEpilogs) { - if (ig == emitPrologIG) - continue; - if (ig->igFlags & IGF_EPILOG) + if ((ig->igFlags & (IGF_PROLOG | IGF_EPILOG)) != 0) continue; } if ((ig->igFlags & IGF_NOGCINTERRUPT) && ig->igSize > 0) diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index a4822839ce7de6..716e15f392627f 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -2827,9 +2827,6 @@ void emitter::emitJumpDistBind() UNATIVE_OFFSET adjIG; UNATIVE_OFFSET adjSJ; insGroup* lstIG; -#ifdef DEBUG - insGroup* prologIG = emitPrologIG; -#endif // DEBUG // NOTE: // bit0 of isLinkingEnd_LA: indicating whether updating the instrDescJmp's size with the type INS_OPTS_J; @@ -2884,7 +2881,7 @@ void emitter::emitJumpDistBind() assert(lastSJ == nullptr || lastIG != jmp->idjIG || lastSJ->idjOffs < (jmp->idjOffs + adjSJ)); lastSJ = (lastIG == jmp->idjIG) ? jmp : nullptr; - assert(lastIG == nullptr || lastIG->IsBeforeOrEqual(jmp->idjIG) || jmp->idjIG == prologIG); + assert(lastIG == nullptr || lastIG->IsBeforeOrEqual(jmp->idjIG) || emitIGisInProlog(jmp->idjIG)); lastIG = jmp->idjIG; #endif // DEBUG @@ -4119,7 +4116,8 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) { printf("%s, %s, 0x%lx\n", RegNames[regd], RegNames[regj], offs16); } - else if ((unsigned)(addr - emitCodeBlock) < emitPrologIG->igSize) // only for prolog + // only for prolog + else if (emitPrologEndPos.Valid() && ((unsigned)(addr - emitCodeBlock) < emitPrologEndPos.CodeOffset(this))) { if (offs16 < 0) { @@ -4140,7 +4138,8 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) { tmp = (((code >> 10) & 0xffff) | ((code & 0x1f) << 16)) << 11; tmp >>= 9; - if ((unsigned)(addr - emitCodeBlock) < emitPrologIG->igSize) // only for prolog + // only for prolog + if (emitPrologEndPos.Valid() && ((unsigned)(addr - emitCodeBlock) < emitPrologEndPos.CodeOffset(this))) { tmp >>= 2; if (tmp < 0) @@ -4169,7 +4168,8 @@ void emitter::emitDisInsName(code_t code, const BYTE* addr, instrDesc* id) methodName = m_compiler->eeGetMethodFullName((CORINFO_METHOD_HANDLE)id->idDebugOnlyInfo()->idMemCookie); printf("# %s\n", methodName); } - else if ((unsigned)(addr - emitCodeBlock) < emitPrologIG->igSize) // only for prolog + // only for prolog + else if (emitPrologEndPos.Valid() && ((unsigned)(addr - emitCodeBlock) < emitPrologEndPos.CodeOffset(this))) { tmp >>= 2; if (tmp < 0) diff --git a/src/coreclr/jit/emitpub.h b/src/coreclr/jit/emitpub.h index d57799eca1eec8..cda3839c43341a 100644 --- a/src/coreclr/jit/emitpub.h +++ b/src/coreclr/jit/emitpub.h @@ -43,10 +43,9 @@ unsigned emitGetEpilogCnt(); template bool emitGenNoGCLst(Callback& cb, bool skipMainPrologsAndEpilogs = false); -void emitBegProlog(); -unsigned emitGetPrologOffsetEstimate(); -void emitMarkPrologEnd(); -void emitEndProlog(); +void emitBegProlog(); +void emitMarkPrologEnd(); +void emitEndProlog(); void emitCreatePlaceholderIG(insGroupPlaceholderType igType, BasicBlock* igBB, @@ -67,6 +66,7 @@ unsigned emitCurOffset(); unsigned emitSpecifiedOffset(unsigned insCount, unsigned igSize); UNATIVE_OFFSET emitCodeOffset(void* blockPtr, unsigned codeOffs); +UNATIVE_OFFSET emitGetCurrentCodeOffsetFrom(insGroup* ig); #ifdef DEBUG const char* emitOffsetToLabel(unsigned offs); diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 06eec05ce90b60..8db4a7ff4484e6 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -10966,8 +10966,7 @@ void emitter::emitIns_J(instruction ins, else { /* Only allow non-label jmps in prolog */ - assert(emitPrologIG); - assert(emitPrologIG == emitCurIG); + assert(emitIGisInProlog(emitCurIG)); assert(instrCount != 0); } diff --git a/src/coreclr/jit/unwind.cpp b/src/coreclr/jit/unwind.cpp index 1b4d454e142326..f767089de347df 100644 --- a/src/coreclr/jit/unwind.cpp +++ b/src/coreclr/jit/unwind.cpp @@ -24,7 +24,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // locations must remain correct after the prolog and epilogs are generated. // // For the prolog, instructions are put in the special, preallocated, prolog instruction group. -// We don't want to expose the emitPrologIG unnecessarily (locations are actually pointers to +// We don't want to expose the prolog IG unnecessarily (locations are actually pointers to // emitter instruction groups). Since we know the offset of the start of the function/funclet, // where the prolog is, will be zero, we use a nullptr start location to indicate that. // @@ -421,26 +421,11 @@ void Compiler::DumpCfiInfo(bool isHotCode, UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func) { assert(compGeneratingProlog); - UNATIVE_OFFSET offset; - if (func->funKind == FUNC_ROOT) - { - offset = GetEmitter()->emitGetPrologOffsetEstimate(); - } - else - { - if (TargetArchitecture::IsX64 || - (TargetOS::IsUnix && - (TargetArchitecture::IsArmArch || TargetArchitecture::IsX86 || TargetArchitecture::IsLoongArch64))) - { - assert(func->startLoc != nullptr); - offset = func->startLoc->GetFuncletPrologOffset(GetEmitter()); - } - else - { - offset = 0; // TODO ??? - } - } + emitLocation* loc = func->startLoc; + insGroup* ig = (loc != nullptr) ? loc->GetIG() : nullptr; + assert((ig == nullptr) || (loc->GetInsOffset() == 0)); + UNATIVE_OFFSET offset = GetEmitter()->emitGetCurrentCodeOffsetFrom(ig); return offset; } From 4ae63e6cedba2489ef47532c4b107cd7f800afe6 Mon Sep 17 00:00:00 2001 From: SingleAccretion Date: Sat, 4 Apr 2026 22:21:10 +0300 Subject: [PATCH 2/2] Fix jumps encoded as "+/- " By deleting them. --- src/coreclr/jit/codegenarm.cpp | 4 +- src/coreclr/jit/codegenarm64.cpp | 15 +-- src/coreclr/jit/codegencommon.cpp | 3 + src/coreclr/jit/codegenriscv64.cpp | 5 +- src/coreclr/jit/codegenxarch.cpp | 7 +- src/coreclr/jit/emit.cpp | 151 +++++++++++++++++------------ src/coreclr/jit/emit.h | 26 ++--- src/coreclr/jit/emitarm.cpp | 67 ++++--------- src/coreclr/jit/emitarm.h | 2 +- src/coreclr/jit/emitarm64.cpp | 72 ++++---------- src/coreclr/jit/emitarm64.h | 2 +- src/coreclr/jit/emitriscv64.cpp | 86 +--------------- src/coreclr/jit/emitriscv64.h | 7 +- src/coreclr/jit/emitxarch.cpp | 75 +++----------- src/coreclr/jit/emitxarch.h | 2 +- 15 files changed, 182 insertions(+), 342 deletions(-) diff --git a/src/coreclr/jit/codegenarm.cpp b/src/coreclr/jit/codegenarm.cpp index 635107af30ac26..91cb2a2673b76a 100644 --- a/src/coreclr/jit/codegenarm.cpp +++ b/src/coreclr/jit/codegenarm.cpp @@ -2659,9 +2659,11 @@ void CodeGen::genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNu } else { + BasicBlock* loopHead = genCreateTempLabel(); + genDefineInlineTempLabel(loopHead); GetEmitter()->emitIns_R_I(INS_stm, EA_PTRSIZE, rAddr, stmImm); // zero stack slots GetEmitter()->emitIns_R_I(INS_sub, EA_PTRSIZE, rCnt, 1, INS_FLAGS_SET); - GetEmitter()->emitIns_J(INS_bhi, NULL, -3); + GetEmitter()->emitIns_ShortJ(INS_bhi, loopHead); uCntBytes %= REGSIZE_BYTES * 2; } diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 3733e587b77e8c..dc9602c094025a 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -1957,10 +1957,12 @@ void CodeGen::genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNu GetEmitter()->emitIns_R_R_I_I(INS_bfm, EA_PTRSIZE, addrReg, REG_ZR, 0, 5); // addrReg points at the beginning of a cache line. + BasicBlock* loopHead = genCreateTempLabel(); + genDefineInlineTempLabel(loopHead); GetEmitter()->emitIns_R(INS_dczva, EA_PTRSIZE, addrReg); GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, addrReg, addrReg, 64); GetEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, addrReg, endAddrReg); - GetEmitter()->emitIns_J(INS_blo, NULL, -4); + GetEmitter()->emitIns_ShortJ(INS_blo, loopHead); addrReg = endAddrReg; bytesToWrite = 64; @@ -1979,12 +1981,14 @@ void CodeGen::genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNu instGen_Set_Reg_To_Imm(EA_PTRSIZE, countReg, bytesToWrite - 64); + BasicBlock* loopHead = genCreateTempLabel(); + genDefineInlineTempLabel(loopHead); GetEmitter()->emitIns_R_R_R_I(INS_stp, EA_16BYTE, zeroSimdReg, zeroSimdReg, addrReg, 32); GetEmitter()->emitIns_R_R_R_I(INS_stp, EA_16BYTE, zeroSimdReg, zeroSimdReg, addrReg, 64, INS_OPTS_PRE_INDEX); GetEmitter()->emitIns_R_R_I(INS_subs, EA_PTRSIZE, countReg, countReg, 64); - GetEmitter()->emitIns_J(INS_bge, NULL, -4); + GetEmitter()->emitIns_ShortJ(INS_bge, loopHead); bytesToWrite %= 64; } @@ -5914,13 +5918,12 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni instGen_Set_Reg_To_Imm(EA_PTRSIZE, rOffset, -(ssize_t)pageSize); instGen_Set_Reg_To_Imm(EA_PTRSIZE, rLimit, -(ssize_t)frameSize); - // There's a "virtual" label here. But we can't create a label in the prolog, so we use the magic - // `emitIns_J` with a negative `instrCount` to branch back a specific number of instructions. - + BasicBlock* loopHead = genCreateTempLabel(); + genDefineInlineTempLabel(loopHead); GetEmitter()->emitIns_R_R_R(INS_ldr, EA_4BYTE, REG_ZR, REG_SPBASE, rOffset); GetEmitter()->emitIns_R_R_I(INS_sub, EA_PTRSIZE, rOffset, rOffset, pageSize); GetEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, rLimit, rOffset); // If equal, we need to probe again - GetEmitter()->emitIns_J(INS_bls, NULL, -4); + GetEmitter()->emitIns_ShortJ(INS_bls, loopHead); *pInitRegZeroed = false; // The initReg does not contain zero diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 8eb1e7d262c55a..308c498efaca3f 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -6026,6 +6026,7 @@ void CodeGen::genGeneratePrologsAndEpilogs() GetEmitter()->emitStartPrologEpilogGeneration(); + m_compiler->compCurBB = m_compiler->fgFirstBB; // Set the current BB for label creation. gcInfo.gcResetForBB(); genFnProlog(); @@ -6053,6 +6054,8 @@ void CodeGen::genGeneratePrologsAndEpilogs() GetEmitter()->emitFinishPrologEpilogGeneration(); + m_compiler->compCurBB = nullptr; + #ifdef DEBUG if (verbose) { diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index c7ee5c185d3608..fe128281570911 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -822,14 +822,15 @@ void CodeGen::genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNu GetEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, rEndAddr, rEndAddr, rAddr); } - // TODO-RISCV64-RVC: Remove hardcoded branch offset here + BasicBlock* loopHead = genCreateTempLabel(); + genDefineInlineTempLabel(loopHead); GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, rAddr, padding); GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, rAddr, padding + REGSIZE_BYTES); GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, rAddr, padding + 2 * REGSIZE_BYTES); GetEmitter()->emitIns_R_R_I(INS_sd, EA_PTRSIZE, REG_R0, rAddr, padding + 3 * REGSIZE_BYTES); GetEmitter()->emitIns_R_R_I(INS_addi, EA_PTRSIZE, rAddr, rAddr, 4 * REGSIZE_BYTES); - GetEmitter()->emitIns_R_R_I(INS_bltu, EA_PTRSIZE, rAddr, rEndAddr, -5 << 2); + GetEmitter()->emitIns_J_cond_la(INS_bltu, loopHead, rAddr, rEndAddr); uLclBytes -= uLoopBytes; uAddrCurr = 0; diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index ebbc84af8b984c..a68f3acf49aa56 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -1685,7 +1685,7 @@ void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock, bool isRemovableJ #endif #endif // !FEATURE_FIXED_OUT_ARGS - GetEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock, 0, isRemovableJmpCandidate); + GetEmitter()->emitIns_J(emitter::emitJumpKindToIns(jmp), tgtBlock, /* keepShort*/ false, isRemovableJmpCandidate); } //------------------------------------------------------------------------ @@ -11301,7 +11301,10 @@ void CodeGen::genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNu // Set loop counter emit->emitIns_R_I(INS_mov, EA_PTRSIZE, initReg, -(ssize_t)blkSize); + // Loop start + BasicBlock* loopHead = genCreateTempLabel(); + genDefineInlineTempLabel(loopHead); emit->emitIns_ARX_R(simdMov, EA_ATTR(XMM_REGSIZE_BYTES), zeroSIMDReg, frameReg, initReg, 1, alignedLclHi); emit->emitIns_ARX_R(simdMov, EA_ATTR(XMM_REGSIZE_BYTES), zeroSIMDReg, frameReg, initReg, 1, alignedLclHi + XMM_REGSIZE_BYTES); @@ -11310,7 +11313,7 @@ void CodeGen::genZeroInitFrameUsingBlockInit(int untrLclHi, int untrLclLo, regNu emit->emitIns_R_I(INS_add, EA_PTRSIZE, initReg, XMM_REGSIZE_BYTES * 3); // Loop until counter is 0 - emit->emitIns_J(INS_jne, nullptr, -5); + emit->emitIns_ShortJ(INS_jne, loopHead); // initReg will be zero at end of the loop *pInitRegZeroed = true; diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 37f7b074d6bf63..c69dc4875812c2 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -1238,16 +1238,14 @@ insGroup* emitter::emitSavIG(bool emitAdd) assert(last == nullptr || last->idjOffs > nj->idjOffs); - if (ig->igFlags & IGF_FUNCLET_PROLOG) + if ((ig->igFlags & IGF_OUT_OF_ORDER_MASK) != 0) { - // Our funclet prologs have short jumps, if the prolog would ever have - // long jumps, then we'd have to insert the list in sorted order than - // just append to the emitJumpList. - noway_assert(nj->idjShort); - if (nj->idjShort) - { - continue; - } + // Our out of order groups have short jumps. If we ever need the shortening capability + // for these jumps, we'll need to insert them at the appropriate place in emitJumpList. + nj->idjNext = emitFixedSizeJumpList; + emitFixedSizeJumpList = nj; + assert(nj->idjShort); + continue; } // Append the new jump to the list @@ -1264,8 +1262,7 @@ insGroup* emitter::emitSavIG(bool emitAdd) if (last != nullptr) { // Append the jump(s) from this IG to the global list - bool prologJump = emitIGisInProlog(ig); - if ((emitJumpList == nullptr) || prologJump) + if (emitJumpList == nullptr) { last->idjNext = emitJumpList; emitJumpList = list; @@ -1276,10 +1273,7 @@ insGroup* emitter::emitSavIG(bool emitAdd) emitJumpLast->idjNext = list; } - if (!prologJump || (emitJumpLast == nullptr)) - { - emitJumpLast = last; - } + emitJumpLast = last; } } @@ -1372,6 +1366,7 @@ void emitter::emitBegFN(bool hasFramePtr /* We don't have any jumps */ emitJumpList = emitJumpLast = nullptr; + emitFixedSizeJumpList = nullptr; emitCurIGjmpList = nullptr; emitFwdJumps = false; @@ -2416,14 +2411,15 @@ void emitter::emitBegPrologEpilog(insGroup* igPh) emitThisGCrefRegs = emitInitGCrefRegs = igPh->igPhData->igPhInitGCrefRegs; emitThisByrefRegs = emitInitByrefRegs = igPh->igPhData->igPhInitByrefRegs; + // Set the current BB for label creation. + m_compiler->compCurBB = igPh->igPhData->igPhBB; + igPh->igPhData = nullptr; /* Create a non-placeholder group pointer that we'll now use */ - insGroup* ig = igPh; /* Set the current function using the function index we stored */ - m_compiler->funSetCurrentFunc(ig->igFuncIdx); /* Set the new IG as the place to generate code */ @@ -3602,6 +3598,26 @@ void emitter::emitSetSecondRetRegGCType(instrDescCGCA* id, emitAttr secondRetSiz #endif // MULTIREG_HAS_SECOND_GC_RET #ifndef TARGET_WASM +//------------------------------------------------------------------------ +// emitIns_ShortJ: Emit a 'forced' short jump. +// +// Jumps in prologs are hardcoded to be short since we don't shorten +// them in binding. +// +// Arguments: +// ins - The jump instruction +// dst - The destination label (must already be bound to an IG) +// +void emitter::emitIns_ShortJ(instruction ins, BasicBlock* dst) +{ + assert((emitCurIG->igFlags & IGF_OUT_OF_ORDER_MASK) != 0); + + // We currently have a limitation where all jumps in the prolog must be short. + // This is mostly because we the prolog can't change size in emission, as we + // currently hardcode offsets from it into the unwind info during IG building. + // We also don't insert the jumps into the jump list in layout order. + emitIns_J(ins, dst, /* keepShort */ true); +} /***************************************************************************** * @@ -4903,6 +4919,15 @@ void emitter::emitJumpDistBind() } #endif + // For the fixed-size jumps, we only need to bind them. + for (instrDescJmp* jmp = emitFixedSizeJumpList; jmp != nullptr; jmp = jmp->idjNext) + { + if (!jmp->idIsBound()) + { + emitBindJump(jmp); + } + } + instrDescJmp* jmp; UNATIVE_OFFSET minShortExtra; // The smallest offset greater than that required for a jump to be converted @@ -5220,40 +5245,7 @@ void emitter::emitJumpDistBind() else { /* First time we've seen this label, convert its target */ - -#ifdef DEBUG - if (EMITVERBOSE) - { - printf("Binding: "); - emitDispIns(jmp, false, false, false); - printf("Binding L_M%03u_" FMT_BB, m_compiler->compMethodID, jmp->idAddr()->iiaBBlabel->bbNum); - } -#endif // DEBUG - - tgtIG = (insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel); - -#ifdef DEBUG - if (EMITVERBOSE) - { - if (tgtIG) - { - printf(" to %s\n", emitLabelString(tgtIG)); - } - else - { - printf("-- ERROR, no emitter cookie for " FMT_BB "; it is probably missing BBF_HAS_LABEL.\n", - jmp->idAddr()->iiaBBlabel->bbNum); - } - } -#endif // DEBUG - - assert(jmp->idAddr()->iiaBBlabel->HasFlag(BBF_HAS_LABEL)); - assert(tgtIG); - - /* Record the bound target */ - - jmp->idAddr()->iiaIGlabel = tgtIG; - jmp->idSetIsBound(); + tgtIG = emitBindJump(jmp); } // We should not be jumping/branching across funclets/functions @@ -5674,6 +5666,54 @@ void emitter::emitJumpDistBind() emitCheckIGList(); #endif // DEBUG } + +//------------------------------------------------------------------------ +// emitBindJump: 'Bind' a jump by assigning its target label field. +// +// Arguments: +// jmp - The jump instruction +// +// Return Value: +// The target IG "jmp" was bound to. +// +insGroup* emitter::emitBindJump(instrDescJmp* jmp) +{ + assert(!jmp->idIsBound()); + +#ifdef DEBUG + if (EMITVERBOSE) + { + printf("Binding: "); + emitDispIns(jmp, false, false, false); + printf("Binding L_M%03u_" FMT_BB, m_compiler->compMethodID, jmp->idAddr()->iiaBBlabel->bbNum); + } +#endif // DEBUG + + insGroup* tgtIG = (insGroup*)emitCodeGetCookie(jmp->idAddr()->iiaBBlabel); + +#ifdef DEBUG + if (EMITVERBOSE) + { + if (tgtIG) + { + printf(" to %s\n", emitLabelString(tgtIG)); + } + else + { + printf("-- ERROR, no emitter cookie for " FMT_BB "; it is probably missing BBF_HAS_LABEL.\n", + jmp->idAddr()->iiaBBlabel->bbNum); + } + } +#endif // DEBUG + + assert(jmp->idAddr()->iiaBBlabel->HasFlag(BBF_HAS_LABEL)); + assert(tgtIG != nullptr); + + /* Record the bound target */ + jmp->idAddr()->iiaIGlabel = tgtIG; + jmp->idSetIsBound(); + return tgtIG; +} #endif #if FEATURE_LOOP_ALIGN @@ -6604,13 +6644,6 @@ void emitter::emitCheckFuncletBranch(instrDesc* jmp, insGroup* jmpIG) } #endif - if (jmp->idAddr()->iiaHasInstrCount()) - { - // Too hard to figure out funclets from just an instruction count - // You're on your own! - return; - } - #ifdef TARGET_ARM64 // No interest if it's not jmp. if (emitIsLoadLabel(jmp) || emitIsLoadConstant(jmp)) @@ -7634,7 +7667,6 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, // Presumably we could also just call "emitOutputLJ(NULL, adr, jmp)", like for long jumps? *(short int*)(adr + writeableOffset) -= (short)adj; #elif defined(TARGET_ARM64) - assert(!jmp->idAddr()->iiaHasInstrCount()); emitOutputLJ(NULL, adr, jmp); #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) // For LoongArch64 and RiscV64 `emitFwdJumps` is always false. @@ -7651,7 +7683,6 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, #if defined(TARGET_XARCH) *(int*)(adr + writeableOffset) -= adj; #elif defined(TARGET_ARMARCH) - assert(!jmp->idAddr()->iiaHasInstrCount()); emitOutputLJ(NULL, adr, jmp); #elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) // For LoongArch64 and RiscV64 `emitFwdJumps` is always false. diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 6a2deec2efc175..13d60b28ce9b36 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -1058,8 +1058,9 @@ class emitter int iiaGetJitDataOffset() const; // iiaEncodedInstrCount and its accessor functions are used to specify an instruction - // count for jumps, instead of using a label and multiple blocks. This is used in the - // prolog as well as for IF_LARGEJMP pseudo-branch instructions. + // count for jumps, instead of using a label and multiple blocks. This is only used + // for IF_LARGEJMP pseudo-branch instructions printing. + // TODO-Cleanup: remove this. int iiaEncodedInstrCount; bool iiaHasInstrCount() const @@ -2833,6 +2834,7 @@ class emitter insFormat emitMapFmtAtoM(insFormat fmt); void emitHandleMemOp(GenTreeIndir* indir, instrDesc* id, insFormat fmt, instruction ins); void spillIntArgRegsToShadowSlots(); + void emitIns_ShortJ(instruction ins, BasicBlock* dst); #ifdef TARGET_XARCH bool emitIsInstrWritingToReg(instrDesc* id, regNumber reg); @@ -2857,17 +2859,7 @@ class emitter // can hold at least one of the largest instruction descriptor forms), since we can always overflow // to subsequent instruction groups. // - // The only place where this fixed instruction group size is a problem is in the main function prolog, - // where we only support a single instruction group, and no extension groups. We should really fix that. - // Thus, the buffer size needs to be large enough to hold the maximum number of instructions that - // can possibly be generated into the prolog instruction group. That is difficult to statically determine. - // - // If we do generate an overflow prolog group, we will hit a NOWAY assert and fall back to MinOpts. - // This should reduce the number of instructions generated into the prolog. - // - // Note that OSR prologs require additional code not seen in normal prologs. - // - // Also, note that DEBUG and non-DEBUG builds have different instrDesc sizes, and there are multiple + // Note that DEBUG and non-DEBUG builds have different instrDesc sizes, and there are multiple // sizes of instruction descriptors, so the number of instructions that will fit in the largest // instruction group depends on the instruction mix as well as DEBUG/non-DEBUG build type. See the // EMITTER_STATS output for various statistics related to this. @@ -2899,9 +2891,11 @@ class emitter insGroup* emitIGlist; // first instruction group insGroup* emitIGlast; // last instruction group - instrDescJmp* emitJumpList; // list of local jumps in method - instrDescJmp* emitJumpLast; // last of local jumps in method - void emitJumpDistBind(); // Bind all the local jumps in method + instrDescJmp* emitJumpList; // list of local jumps in method + instrDescJmp* emitJumpLast; // last of local jumps in method + instrDescJmp* emitFixedSizeJumpList; // list of local jumps not eligible for shortening + void emitJumpDistBind(); // Bind all the local jumps in method + insGroup* emitBindJump(instrDescJmp* jmp); bool emitContainsRemovableJmpCandidates; void emitRemoveJumpToNextInst(); // try to remove unconditional jumps to the next instruction diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index cfb5de23666cac..8532b6dbdb3cea 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -4316,8 +4316,6 @@ void emitter::emitSetMediumJump(instrDescJmp* id) /***************************************************************************** * * Add a jmp instruction. - * When dst is NULL, instrCount specifies number of instructions - * to jump: positive is forward, negative is backward. * Unconditional branches have two sizes: short and long. * Conditional branches have three sizes: short, medium, and long. A long * branch is a pseudo-instruction that represents two instructions: @@ -4325,20 +4323,12 @@ void emitter::emitSetMediumJump(instrDescJmp* id) * branch. Thus, we can handle branch offsets of imm24 instead of just imm20. */ -void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount /* = 0 */) +void emitter::emitIns_J(instruction ins, BasicBlock* dst, bool keepShort) { - insFormat fmt = IF_NONE; - - if (dst != NULL) - { - assert(dst->HasFlag(BBF_HAS_LABEL)); - } - else - { - assert(instrCount != 0); - } + assert(dst->HasFlag(BBF_HAS_LABEL)); /* Figure out the encoding format of the instruction */ + insFormat fmt = IF_NONE; switch (ins) { case INS_b: @@ -4374,35 +4364,31 @@ void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount /* = 0 id->idInsFmt(fmt); id->idInsSize(isz); -#ifdef DEBUG - // Mark the finally call - if ((ins == INS_bl) && m_compiler->compCurBB->KindIs(BBJ_CALLFINALLY)) + id->idAddr()->iiaBBlabel = dst; + if (keepShort) { - id->idDebugOnlyInfo()->idFinallyCall = true; + id->idjKeepLong = false; + emitSetShortJump(id); } -#endif // DEBUG - - /* Assume the jump will be long */ - - id->idjShort = 0; - if (dst != NULL) + else { - id->idAddr()->iiaBBlabel = dst; - id->idjKeepLong = (ins == INS_bl) || m_compiler->fgInDifferentRegions(m_compiler->compCurBB, dst); - + id->idjShort = false; + id->idjKeepLong = (ins == INS_bl) || m_compiler->fgInDifferentRegions(m_compiler->compCurBB, dst); #ifdef DEBUG if (m_compiler->opts.compLongAddress) // Force long branches + { id->idjKeepLong = 1; + } #endif // DEBUG } - else + +#ifdef DEBUG + // Mark the finally call + if ((ins == INS_bl) && m_compiler->compCurBB->KindIs(BBJ_CALLFINALLY)) { - id->idAddr()->iiaSetInstrCount(instrCount); - id->idjKeepLong = false; - /* This jump must be short */ - emitSetShortJump(id); - id->idSetIsBound(); + id->idDebugOnlyInfo()->idFinallyCall = true; } +#endif // DEBUG /* Record the jump's IG and offset within it */ @@ -5302,22 +5288,7 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) /* Figure out the distance to the target */ srcOffs = emitCurCodeOffs(dst); - if (id->idAddr()->iiaHasInstrCount()) - { - assert(ig != NULL); - int instrCount = id->idAddr()->iiaGetInstrCount(); - unsigned insNum = emitFindInsNum(ig, id); - if (instrCount < 0) - { - // Backward branches using instruction count must be within the same instruction group. - assert(insNum + 1 >= (unsigned)(-instrCount)); - } - dstOffs = ig->igOffs + emitFindOffset(ig, (insNum + 1 + instrCount)); - } - else - { - dstOffs = id->idAddr()->iiaIGlabel->igOffs; - } + dstOffs = id->idAddr()->iiaIGlabel->igOffs; if (relAddr) { diff --git a/src/coreclr/jit/emitarm.h b/src/coreclr/jit/emitarm.h index 6e3eb5793c54aa..b2b918f8b67b9c 100644 --- a/src/coreclr/jit/emitarm.h +++ b/src/coreclr/jit/emitarm.h @@ -205,7 +205,7 @@ inline static unsigned getBitWidth(emitAttr size) /* Output target-independent instructions */ /************************************************************************/ -void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0); +void emitIns_J(instruction ins, BasicBlock* dst, bool keepShort = false); /************************************************************************/ /* The public entry points to output instructions */ diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 250af9a94d9213..222e8bf15dc295 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -9297,21 +9297,12 @@ void emitter::emitIns_J_R_I(instruction ins, emitAttr attr, BasicBlock* dst, reg appendToCurIG(id); } -void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount) +void emitter::emitIns_J(instruction ins, BasicBlock* dst, bool keepShort) { - insFormat fmt = IF_NONE; - - if (dst != nullptr) - { - assert(dst->HasFlag(BBF_HAS_LABEL)); - } - else - { - assert(instrCount != 0); - } + assert(dst->HasFlag(BBF_HAS_LABEL)); /* Figure out the encoding format of the instruction */ - + insFormat fmt = IF_NONE; switch (ins) { case INS_bl_local: @@ -9348,39 +9339,32 @@ void emitter::emitIns_J(instruction ins, BasicBlock* dst, int instrCount) id->idIns(ins); id->idInsFmt(fmt); - id->idjShort = false; -#ifdef DEBUG - // Mark the finally call - if (ins == INS_bl_local && m_compiler->compCurBB->KindIs(BBJ_CALLFINALLY)) + id->idAddr()->iiaBBlabel = dst; + if (keepShort) { - id->idDebugOnlyInfo()->idFinallyCall = true; + id->idjKeepLong = false; + emitSetShortJump(id); } -#endif // DEBUG - - if (dst != nullptr) + else { - id->idAddr()->iiaBBlabel = dst; - - // Skip unconditional jump that has a single form. - // The target needs to be relocated. - id->idjKeepLong = m_compiler->fgInDifferentRegions(m_compiler->compCurBB, dst); - + id->idjShort = false; + id->idjKeepLong = (ins == INS_bl) || m_compiler->fgInDifferentRegions(m_compiler->compCurBB, dst); #ifdef DEBUG if (m_compiler->opts.compLongAddress) // Force long branches { - id->idjKeepLong = true; + id->idjKeepLong = 1; } #endif // DEBUG } - else + +#ifdef DEBUG + // Mark the finally call + if (ins == INS_bl_local && m_compiler->compCurBB->KindIs(BBJ_CALLFINALLY)) { - id->idAddr()->iiaSetInstrCount(instrCount); - id->idjKeepLong = false; - /* This jump must be short */ - emitSetShortJump(id); - id->idSetIsBound(); + id->idDebugOnlyInfo()->idFinallyCall = true; } +#endif // DEBUG /* Record the jump's IG and offset within it */ @@ -10726,26 +10710,8 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) assert(loadLabel || isJump); - if (id->idAddr()->iiaHasInstrCount()) - { - assert(ig != NULL); - int instrCount = id->idAddr()->iiaGetInstrCount(); - unsigned insNum = emitFindInsNum(ig, id); - if (instrCount < 0) - { - // Backward branches using instruction count must be within the same instruction group. - assert(insNum + 1 >= (unsigned)(-instrCount)); - } - - dstOffs = ig->igOffs + emitFindOffset(ig, (insNum + 1 + instrCount)); - dstAddr = emitOffsetToPtr(dstOffs); - } - else - { - dstOffs = id->idAddr()->iiaIGlabel->igOffs; - dstAddr = emitOffsetToPtr(dstOffs); - } - + dstOffs = id->idAddr()->iiaIGlabel->igOffs; + dstAddr = emitOffsetToPtr(dstOffs); distVal = (ssize_t)(dstAddr - srcAddr); if (dstOffs <= srcOffs) diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index 6b54d0e643b641..07efef1652a32c 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -1461,7 +1461,7 @@ inline static ssize_t computeRelPageAddr(size_t dstAddr, size_t srcAddr) /* Output target-independent instructions */ /************************************************************************/ -void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0); +void emitIns_J(instruction ins, BasicBlock* dst, bool keepShort = false); /************************************************************************/ /* The public entry points to output instructions */ diff --git a/src/coreclr/jit/emitriscv64.cpp b/src/coreclr/jit/emitriscv64.cpp index 70b17f905ca915..657ea9d69defd4 100644 --- a/src/coreclr/jit/emitriscv64.cpp +++ b/src/coreclr/jit/emitriscv64.cpp @@ -771,22 +771,6 @@ void emitter::emitIns_R_R_I( code |= (((imm >> 5) & 0x7f) << 25) | ((imm & 0x1f) << 7); // imm break; - case MajorOpcode::Branch: - assert(isGeneralRegister(reg1)); - assert(isGeneralRegister(reg2)); - assert(isValidSimm13(imm)); - assert(!(imm & 3)); - code |= reg1 << 15; - code |= reg2 << 20; - code |= ((imm >> 11) & 0x1) << 7; - code |= ((imm >> 1) & 0xf) << 8; - code |= ((imm >> 5) & 0x3f) << 25; - code |= ((imm >> 12) & 0x1) << 31; - // TODO-RISCV64: Move jump logic to emitIns_J - // TODO-RISC64-RVC: Remove this once all branches uses emitIns_J - id->idAddr()->iiaSetInstrCount(static_cast(imm / sizeof(code_t))); - break; - case MajorOpcode::System: assert(ins == INS_csrrs || ins == INS_csrrw || ins == INS_csrrc); assert(isGeneralRegisterOrR0(reg1)); @@ -1446,7 +1430,7 @@ void emitter::emitIns_R_R_Addr(instruction ins, emitAttr attr, regNumber regData } } -void emitter::emitIns_J(instruction ins, BasicBlock* dst) +void emitter::emitIns_J(instruction ins, BasicBlock* dst, bool keepShort) { assert(emitIsUncondJump(ins)); regNumber linkReg = (ins == INS_jal) ? REG_RA : REG_ZERO; @@ -2821,29 +2805,6 @@ unsigned emitter::emitOutput_JTypeInstr(BYTE* dst, instruction ins, regNumber rd return emitOutput_Instr(dst, insEncodeJTypeInstr(insCode, rd, imm21)); } -void emitter::emitOutputInstrJumpDistanceHelper(const insGroup* ig, - instrDescJmp* jmp, - UNATIVE_OFFSET& dstOffs, - const BYTE*& dstAddr) const -{ - if (jmp->idAddr()->iiaHasInstrCount()) - { - assert(ig != nullptr); - int instrCount = jmp->idAddr()->iiaGetInstrCount(); - unsigned insNum = emitFindInsNum(ig, jmp); - if (instrCount < 0) - { - // Backward branches using instruction count must be within the same instruction group. - assert(insNum + 1 >= static_cast(-instrCount)); - } - dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount); - dstAddr = emitOffsetToPtr(dstOffs); - return; - } - dstOffs = jmp->idAddr()->iiaIGlabel->igOffs; - dstAddr = emitOffsetToPtr(dstOffs); -} - /***************************************************************************** * * Calculates a current jump instruction distance @@ -2857,9 +2818,8 @@ ssize_t emitter::emitOutputInstrJumpDistance(const BYTE* src, const insGroup* ig assert(!jmp->idAddr()->iiaIsJitDataOffset()); // not used by riscv64 impl - UNATIVE_OFFSET dstOffs{}; - const BYTE* dstAddr = nullptr; - emitOutputInstrJumpDistanceHelper(ig, jmp, dstOffs, dstAddr); + UNATIVE_OFFSET dstOffs = jmp->idAddr()->iiaIGlabel->igOffs; + const BYTE* dstAddr = emitOffsetToPtr(dstOffs); ssize_t distVal = static_cast(dstAddr - srcAddr); @@ -3593,35 +3553,6 @@ bool emitter::emitDispBranchInstrType(unsigned opcode2, bool is_zero_reg, bool& return true; } -void emitter::emitDispBranchOffset(const instrDesc* id, const insGroup* ig, bool printOffsetPlaceholder) const -{ - if (printOffsetPlaceholder) - { - printf("pc+?? instructions"); - return; - } - - int instrCount = id->idAddr()->iiaGetInstrCount(); - if (ig == nullptr) - { - printf("pc%+d instructions", instrCount); - return; - } - unsigned insNum = emitFindInsNum(ig, id); - - if (ig->igInsCnt < insNum + 1 + instrCount) - { - // TODO-RISCV64-BUG: This should be a labeled offset but does not contain an iiaIGlabel - printf("pc%+d instructions", instrCount); - return; - } - - UNATIVE_OFFSET srcOffs = ig->igOffs + emitFindOffset(ig, insNum + 1); - UNATIVE_OFFSET dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount); - ssize_t relOffs = static_cast(emitOffsetToPtr(dstOffs) - emitOffsetToPtr(srcOffs)); - printf("pc%+d (%d instructions)", static_cast(relOffs), instrCount); -} - void emitter::emitDispBranchLabel(const instrDesc* id) const { if (id->idIsBound()) @@ -3649,16 +3580,7 @@ bool emitter::emitDispBranch(unsigned opcode2, printf("%s, ", RegNames[rs2]); } assert(id != nullptr); - if (id->idAddr()->iiaHasInstrCount()) - { - // Branch is jumping to some non-labeled offset - emitDispBranchOffset(id, ig, printOffsetPlaceholder); - } - else - { - // Branch is jumping to the labeled offset - emitDispBranchLabel(id); - } + emitDispBranchLabel(id); printf("\n"); return true; } diff --git a/src/coreclr/jit/emitriscv64.h b/src/coreclr/jit/emitriscv64.h index 13efbe550b4e24..10a38dbf356658 100644 --- a/src/coreclr/jit/emitriscv64.h +++ b/src/coreclr/jit/emitriscv64.h @@ -30,7 +30,7 @@ const char* emitVectorRegName(regNumber reg); #endif // DEBUG void emitIns_J_cond_la(instruction ins, BasicBlock* dst, regNumber reg1 = REG_R0, regNumber reg2 = REG_R0); -void emitIns_J(instruction ins, BasicBlock* dst); +void emitIns_J(instruction ins, BasicBlock* dst, bool keepShort = false); template int emitLoadImmediate(emitAttr attr, regNumber reg, ssize_t imm); @@ -186,7 +186,6 @@ bool emitDispBranch(unsigned opcode2, const instrDesc* id, const insGroup* ig, bool printOffsetPlaceholder) const; -void emitDispBranchOffset(const instrDesc* id, const insGroup* ig, bool printOffsetPlaceholder) const; void emitDispBranchLabel(const instrDesc* id) const; bool emitDispBranchInstrType(unsigned opcode2, bool is_zero_reg, bool& print_second_reg) const; void emitDispIllegalInstruction(code_t instructionCode); @@ -208,10 +207,6 @@ void emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataReg, GenTr unsigned emitOutput_Instr(BYTE* dst, code_t code) const; ssize_t emitOutputInstrJumpDistance(const BYTE* src, const insGroup* ig, instrDescJmp* jmp); -void emitOutputInstrJumpDistanceHelper(const insGroup* ig, - instrDescJmp* jmp, - UNATIVE_OFFSET& dstOffs, - const BYTE*& dstAddr) const; // Method to do check if mov is redundant with respect to the last instruction. // If yes, the caller of this method can choose to omit current mov instruction. diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 8db4a7ff4484e6..ccf0cc54a59978 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -10941,14 +10941,9 @@ void emitter::emitSetShortJump(instrDescJmp* id) /***************************************************************************** * * Add a jmp instruction. - * When dst is NULL, instrCount specifies number of instructions - * to jump: positive is forward, negative is backward. */ -void emitter::emitIns_J(instruction ins, - BasicBlock* dst, - int instrCount /* = 0 */, - bool isRemovableJmpCandidate /* = false */) +void emitter::emitIns_J(instruction ins, BasicBlock* dst, bool keepShort, bool isRemovableJmpCandidate /* = false */) { #ifdef TARGET_AMD64 // Check emitter::emitLastIns before it is updated @@ -10958,18 +10953,7 @@ void emitter::emitIns_J(instruction ins, UNATIVE_OFFSET sz; instrDescJmp* id = emitNewInstrJmp(); - if (dst != nullptr) - { - assert(dst->HasFlag(BBF_HAS_LABEL)); - assert(instrCount == 0); - } - else - { - /* Only allow non-label jmps in prolog */ - assert(emitIGisInProlog(emitCurIG)); - assert(instrCount != 0); - } - + assert(dst->HasFlag(BBF_HAS_LABEL)); id->idIns(ins); id->idInsFmt(IF_LABEL); @@ -10997,24 +10981,12 @@ void emitter::emitIns_J(instruction ins, id->idjIsRemovableJmpCandidate = 0; } - id->idjShort = 0; - if (dst != nullptr) - { - /* Assume the jump will be long */ - id->idAddr()->iiaBBlabel = dst; - id->idjKeepLong = m_compiler->fgInDifferentRegions(m_compiler->compCurBB, dst); - } - else - { - id->idAddr()->iiaSetInstrCount(instrCount); - id->idjKeepLong = false; - /* This jump must be short */ - emitSetShortJump(id); - id->idSetIsBound(); - } + /* Assume the jump will be long */ + id->idjShort = keepShort; + id->idAddr()->iiaBBlabel = dst; + id->idjKeepLong = m_compiler->fgInDifferentRegions(m_compiler->compCurBB, dst); /* Record the jump's IG and offset within it */ - id->idjIG = emitCurIG; id->idjOffs = emitCurIGsize; @@ -11126,7 +11098,7 @@ void emitter::emitIns_J(instruction ins, id->idCodeSize(sz); dispIns(id); - emitCurIGsize += sz; + appendToCurIG(id); emitAdjustStackDepthPushPop(ins); } @@ -14028,14 +14000,7 @@ void emitter::emitDispIns( if (id->idIsBound()) { - if (id->idAddr()->iiaHasInstrCount()) - { - printf("%3d instr", id->idAddr()->iiaGetInstrCount()); - } - else - { - emitPrintLabel(id->idAddr()->iiaIGlabel); - } + emitPrintLabel(id->idAddr()->iiaIGlabel); } else { @@ -17776,27 +17741,11 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i) srcOffs = emitCurCodeOffs(dst); srcAddr = emitOffsetToPtr(srcOffs); - if (id->idAddr()->iiaHasInstrCount()) + dstOffs = id->idAddr()->iiaIGlabel->igOffs; + dstAddr = emitOffsetToPtr(dstOffs); + if (!relAddr) { - assert(ig != nullptr); - int instrCount = id->idAddr()->iiaGetInstrCount(); - unsigned insNum = emitFindInsNum(ig, id); - if (instrCount < 0) - { - // Backward branches using instruction count must be within the same instruction group. - assert(insNum + 1 >= (unsigned)(-instrCount)); - } - dstOffs = ig->igOffs + emitFindOffset(ig, (insNum + 1 + instrCount)); - dstAddr = emitOffsetToPtr(dstOffs); - } - else - { - dstOffs = id->idAddr()->iiaIGlabel->igOffs; - dstAddr = emitOffsetToPtr(dstOffs); - if (!relAddr) - { - srcAddr = nullptr; - } + srcAddr = nullptr; } distVal = (ssize_t)(dstAddr - srcAddr); diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h index 38ade6a38f3930..cc7d3bcca21d6a 100644 --- a/src/coreclr/jit/emitxarch.h +++ b/src/coreclr/jit/emitxarch.h @@ -891,7 +891,7 @@ inline emitAttr emitDecodeScale(unsigned ensz) const /* Output target-independent instructions */ /************************************************************************/ -void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0, bool isRemovableJmpCandidate = false); +void emitIns_J(instruction ins, BasicBlock* dst, bool keepShort = false, bool isRemovableJmpCandidate = false); /************************************************************************/ /* The public entry points to output instructions */