diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 9acf7268e08a5f..33adf785ad2c30 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -218,6 +218,12 @@ unsigned emitter::emitTotalDescAlignCnt; void emitterStaticStats(FILE* fout) { + // The IG buffer size depends on whether we are storing a debug info pointer or not. For our purposes + // here, do not include that. + + const size_t igBuffSize = + (SC_IG_BUFFER_NUM_SMALL_DESCS * SMALL_IDSC_SIZE) + (SC_IG_BUFFER_NUM_LARGE_DESCS * sizeof(emitter::instrDesc)); + // insGroup members insGroup* igDummy = nullptr; @@ -226,6 +232,10 @@ void emitterStaticStats(FILE* fout) fprintf(fout, "insGroup:\n"); fprintf(fout, "Offset / size of igNext = %2zu / %2zu\n", offsetof(insGroup, igNext), sizeof(igDummy->igNext)); +#if EMIT_BACKWARDS_NAVIGATION + fprintf(fout, "Offset / size of igPrev = %2zu / %2zu\n", offsetof(insGroup, igPrev), + sizeof(igDummy->igPrev)); +#endif // EMIT_BACKWARDS_NAVIGATION #ifdef DEBUG fprintf(fout, "Offset / size of igSelf = %2zu / %2zu\n", offsetof(insGroup, igSelf), sizeof(igDummy->igSelf)); @@ -244,6 +254,10 @@ void emitterStaticStats(FILE* fout) sizeof(igDummy->igData)); fprintf(fout, "Offset / size of igPhData = %2zu / %2zu\n", offsetof(insGroup, igPhData), sizeof(igDummy->igPhData)); +#if EMIT_BACKWARDS_NAVIGATION + fprintf(fout, "Offset / size of igLastIns = %2zu / %2zu\n", offsetof(insGroup, igLastIns), + sizeof(igDummy->igLastIns)); +#endif // EMIT_BACKWARDS_NAVIGATION #if EMIT_TRACK_STACK_DEPTH fprintf(fout, "Offset / size of igStkLvl = %2zu / %2zu\n", offsetof(insGroup, igStkLvl), sizeof(igDummy->igStkLvl)); @@ -282,6 +296,9 @@ void emitterStaticStats(FILE* fout) // fprintf(fout, "Size of _idAddrUnion= %2zu\n", sizeof(((emitter::instrDesc*)0)->_idAddrUnion)); fprintf(fout, "Size of instrDescJmp = %2zu\n", sizeof(emitter::instrDescJmp)); +#if FEATURE_LOOP_ALIGN + fprintf(fout, "Size of instrDescAlign = %2zu\n", sizeof(emitter::instrDescAlign)); +#endif // FEATURE_LOOP_ALIGN #if !defined(TARGET_ARM64) fprintf(fout, "Size of instrDescLbl = %2zu\n", sizeof(emitter::instrDescLbl)); #endif // !defined(TARGET_ARM64) @@ -298,23 +315,23 @@ void emitterStaticStats(FILE* fout) #endif // TARGET_ARM fprintf(fout, "\n"); - fprintf(fout, "SC_IG_BUFFER_SIZE = %2zu\n", SC_IG_BUFFER_SIZE); - fprintf(fout, "SMALL_IDSC_SIZE per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / SMALL_IDSC_SIZE); - fprintf(fout, "instrDesc per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDesc)); - fprintf(fout, "instrDescJmp per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescJmp)); + fprintf(fout, "igBuffSize = %2zu\n", igBuffSize); + fprintf(fout, "SMALL_IDSC_SIZE per IG buffer = %2zu\n", igBuffSize / SMALL_IDSC_SIZE); + fprintf(fout, "instrDesc per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDesc)); + fprintf(fout, "instrDescJmp per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescJmp)); #if !defined(TARGET_ARM64) - fprintf(fout, "instrDescLbl per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescLbl)); + fprintf(fout, "instrDescLbl per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescLbl)); #endif // !defined(TARGET_ARM64) - fprintf(fout, "instrDescCns per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescCns)); - fprintf(fout, "instrDescDsp per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescDsp)); - fprintf(fout, "instrDescCnsDsp per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescCnsDsp)); + fprintf(fout, "instrDescCns per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescCns)); + fprintf(fout, "instrDescDsp per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescDsp)); + fprintf(fout, "instrDescCnsDsp per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescCnsDsp)); #ifdef TARGET_XARCH - fprintf(fout, "instrDescAmd per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescAmd)); - fprintf(fout, "instrDescCnsAmd per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescCnsAmd)); + fprintf(fout, "instrDescAmd per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescAmd)); + fprintf(fout, "instrDescCnsAmd per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescCnsAmd)); #endif // TARGET_XARCH - fprintf(fout, "instrDescCGCA per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescCGCA)); + fprintf(fout, "instrDescCGCA per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescCGCA)); #ifdef TARGET_ARM - fprintf(fout, "instrDescReloc per IG buffer = %2zu\n", SC_IG_BUFFER_SIZE / sizeof(emitter::instrDescReloc)); + fprintf(fout, "instrDescReloc per IG buffer = %2zu\n", igBuffSize / sizeof(emitter::instrDescReloc)); #endif // TARGET_ARM fprintf(fout, "\n"); @@ -715,6 +732,10 @@ void emitter::emitGenIG(insGroup* ig) } emitCurIGfreeNext = emitCurIGfreeBase; + +#if EMIT_BACKWARDS_NAVIGATION + emitLastInsFullSize = 0; +#endif // EMIT_BACKWARDS_NAVIGATION } /***************************************************************************** @@ -734,7 +755,7 @@ void emitter::emitNewIG() if (emitComp->verbose) { printf("Created:\n "); - emitDispIG(ig, nullptr, /* displayInstructions */ false, /* displayLocation */ false); + emitDispIG(ig, /* displayFunc */ false, /* displayInstructions */ false, /* displayLocation */ false); } #endif // DEBUG } @@ -908,7 +929,7 @@ insGroup* emitter::emitSavIG(bool emitAdd) if (emitComp->verbose) { printf("Saved:\n "); - emitDispIG(ig, nullptr, /* displayInstructions */ false, /* displayLocation */ false); + emitDispIG(ig, /* displayFunc */ false, /* displayInstructions */ false, /* displayLocation */ false); } else { @@ -1075,9 +1096,13 @@ insGroup* emitter::emitSavIG(bool emitAdd) emitLastIns = (instrDesc*)((BYTE*)id + ((BYTE*)emitLastIns - (BYTE*)emitCurIGfreeBase)); emitLastInsIG = ig; + +#if EMIT_BACKWARDS_NAVIGATION + ig->igLastIns = emitLastIns; +#endif // EMIT_BACKWARDS_NAVIGATION } - // Reset the buffer free pointers + // Reset the buffer free pointer. emitCurIGfreeNext = emitCurIGfreeBase; @@ -1232,6 +1257,11 @@ void emitter::emitBegFN(bool hasFramePtr ig->igNext = nullptr; +#if EMIT_BACKWARDS_NAVIGATION + emitLastInsFullSize = 0; + ig->igPrev = nullptr; +#endif + #ifdef DEBUG emitScratchSigInfo = nullptr; #endif // DEBUG @@ -1546,12 +1576,22 @@ void* emitter::emitAllocAnyInstr(size_t sz, emitAttr opsz) /* Grab the space for the instruction */ emitLastIns = id = (instrDesc*)(emitCurIGfreeNext + m_debugInfoSize); - emitLastInsIG = emitCurIG; - emitCurIGfreeNext += fullSize; + +#if EMIT_BACKWARDS_NAVIGATION + emitCurIG->igLastIns = id; +#endif // EMIT_BACKWARDS_NAVIGATION assert(sz >= sizeof(void*)); memset(id, 0, sz); +#if EMIT_BACKWARDS_NAVIGATION + id->idSetPrevSize(emitLastInsFullSize); + emitLastInsFullSize = (unsigned)fullSize; +#endif // EMIT_BACKWARDS_NAVIGATION + + emitLastInsIG = emitCurIG; + emitCurIGfreeNext += fullSize; + // These fields should have been zero-ed by the above assert(id->idReg1() == regNumber(0)); assert(id->idReg2() == regNumber(0)); @@ -1665,10 +1705,23 @@ void emitter::emitCheckIGList() { assert(emitPrologIG != nullptr); +#if EMIT_BACKWARDS_NAVIGATION + struct IGIDPair + { + insGroup* ig; + instrDesc* id; + }; + jitstd::list insList(emitComp->getAllocator(CMK_DebugOnly)); +#endif // EMIT_BACKWARDS_NAVIGATION + size_t currentOffset = 0; for (insGroup *currIG = emitIGlist, *prevIG = nullptr; currIG != nullptr; prevIG = currIG, currIG = currIG->igNext) { +#if EMIT_BACKWARDS_NAVIGATION + assert(prevIG == currIG->igPrev); +#endif // EMIT_BACKWARDS_NAVIGATION + if (currIG->igOffs != currentOffset) { printf("IG%02u has offset %08X, expected %08X\n", currIG->igNum, currIG->igOffs, currentOffset); @@ -1746,6 +1799,25 @@ void emitter::emitCheckIGList() // // change any semantics of the included instructions. // assert((currIG->igFlags & IGF_NOGCINTERRUPT) == (prevIG->igFlags & IGF_NOGCINTERRUPT)); } + +#if EMIT_BACKWARDS_NAVIGATION + // Check that the instrDesc "prev" pointers are all correct. + unsigned insCnt = currIG->igInsCnt; + if (insCnt > 0) + { + instrDesc* id = emitFirstInstrDesc(currIG->igData); + insList.push_front({currIG, id}); + assert(id->idPrevSize() == 0); + for (unsigned i = 0; i < insCnt - 1; i++) + { + size_t idSize = emitSizeOfInsDsc(id); + size_t idPrevSize = idSize + m_debugInfoSize; + emitAdvanceInstrDesc(&id, idSize); + insList.push_front({currIG, id}); + assert(id->idPrevSize() == idPrevSize); + } + } +#endif // EMIT_BACKWARDS_NAVIGATION } if (emitTotalCodeSize != 0 && emitTotalCodeSize != currentOffset) @@ -1753,6 +1825,28 @@ void emitter::emitCheckIGList() printf("Total code size is %08X, expected %08X\n", emitTotalCodeSize, currentOffset); assert(!"bad total code size"); } + +#if EMIT_BACKWARDS_NAVIGATION + + // Check that walking the instrDescs backwards using `emitPrevID` is correct. Compare the backwards + // walk against a list of IDs that was constructed above while walking forwards (but constructed in + // reverse order). + + insGroup* ig; + instrDesc* id; + if (emitGetLastIns(&ig, &id)) + { + jitstd::list::iterator nextPair = insList.begin(); + jitstd::list::iterator endPair = insList.end(); + do + { + assert(nextPair != endPair); + assert(ig == nextPair->ig); + assert(id == nextPair->id); + ++nextPair; + } while (emitPrevID(ig, id)); + } +#endif // EMIT_BACKWARDS_NAVIGATION } #endif // DEBUG @@ -3179,6 +3273,76 @@ void emitter::emitUnwindNopPadding(emitLocation* locFrom, Compiler* comp) #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 +#if EMIT_BACKWARDS_NAVIGATION + +//------------------------------------------------------------------------ +// emitGetLastIns: Find the last instruction in the function and point ig/id at that instruction. +// +// Arguments: +// pig - Output. On exit, set *pig to the insGroup* containing the last instruction. +// pid - Output. On exit, set *pid to the instrDesc* of the last instruction. +// +// Returns: +// true if there are any instructions, false otherwise. If `false` is returned, `pig` and `pid` +// are untouched. +// +// Notes: +// If the last IG doesn't contain any instructions, walk backwards until finding an IG that does +// contain instructions. +// +bool emitter::emitGetLastIns(insGroup** pig, instrDesc** pid) +{ + for (insGroup* ig = emitIGlast; ig != nullptr; ig = ig->igPrev) + { + if (ig->igLastIns != nullptr) + { + *pig = ig; + *pid = (instrDesc*)ig->igLastIns; + return true; + } + } + return false; +} + +//------------------------------------------------------------------------ +// emitPrevID: Compute the previous instrDesc, either in this IG, or in a previous IG. 'id' +// will point to this instrDesc. 'ig' will also be updated. +// +// Arguments: +// ig - Current instruction group +// id - Current instrDesc +// +// Return Value: +// Returns true if there is an instruction, or false if we've iterated over all +// the instructions back to the beginning. +// +bool emitter::emitPrevID(insGroup*& ig, instrDesc*& id) +{ + unsigned idPrevSize = id->idPrevSize(); + if (idPrevSize != 0) + { + id = (instrDesc*)((BYTE*)id - idPrevSize); + return true; + } + + // No previous instructions in the group; walk previous IGs. + for (ig = ig->igPrev; ig != nullptr; ig = ig->igPrev) + { + if (ig->igLastIns != nullptr) + { + assert(ig->igInsCnt > 0); + id = (instrDesc*)ig->igLastIns; + return true; + } + + assert(ig->igInsCnt == 0); + } + + return false; +} + +#endif // EMIT_BACKWARDS_NAVIGATION + #if defined(TARGET_ARM) /***************************************************************************** @@ -3324,7 +3488,6 @@ void emitter::emitDispVarSet() // Return Value: // None // - void emitter::emitSetSecondRetRegGCType(instrDescCGCA* id, emitAttr secondRetSize) { if (EA_IS_GCREF(secondRetSize)) @@ -3736,7 +3899,7 @@ void emitter::emitDispIGflags(unsigned flags) } } -void emitter::emitDispIG(insGroup* ig, insGroup* igPrev, bool displayInstructions, bool displayLocation) +void emitter::emitDispIG(insGroup* ig, bool displayFunc, bool displayInstructions, bool displayLocation) { const int TEMP_BUFFER_LEN = 40; char buff[TEMP_BUFFER_LEN]; @@ -3749,7 +3912,7 @@ void emitter::emitDispIG(insGroup* ig, insGroup* igPrev, bool displayInstruction // distinct from the verbose on Compiler.) bool jitdump = emitComp->verbose; - if (jitdump && ((igPrev == nullptr) || (igPrev->igFuncIdx != ig->igFuncIdx))) + if (jitdump && displayFunc) { printf("func=%02u, ", ig->igFuncIdx); } @@ -3951,13 +4114,19 @@ void emitter::emitDispIG(insGroup* ig, insGroup* igPrev, bool displayInstruction void emitter::emitDispIGlist(bool displayInstructions) { - insGroup* ig; - insGroup* igPrev; - - for (igPrev = nullptr, ig = emitIGlist; ig; igPrev = ig, ig = ig->igNext) +#if EMIT_BACKWARDS_NAVIGATION + for (insGroup* ig = emitIGlist; ig != nullptr; ig = ig->igNext) + { + const bool displayFunc = (ig->igPrev == nullptr) || (ig->igPrev->igFuncIdx != ig->igFuncIdx); + emitDispIG(ig, displayFunc, displayInstructions); + } +#else // !EMIT_BACKWARDS_NAVIGATION + for (insGroup *ig = emitIGlist, *igPrev = nullptr; ig != nullptr; igPrev = ig, ig = ig->igNext) { - emitDispIG(ig, igPrev, displayInstructions); + const bool displayFunc = (igPrev == nullptr) || (igPrev->igFuncIdx != ig->igFuncIdx); + emitDispIG(ig, displayFunc, displayInstructions); } +#endif // !EMIT_BACKWARDS_NAVIGATION } void emitter::emitDispGCinfo() @@ -4380,9 +4549,9 @@ void emitter::emitRemoveJumpToNextInst() printf(" id: %u: ", id->idDebugOnlyInfo()->idNum); emitDispIns(id, false, true, false, 0, nullptr, 0, jmpGroup); printf("jump group:\n"); - emitDispIG(jmpGroup, nullptr, /* displayInstructions */ true); + emitDispIG(jmpGroup, /* displayFunc */ false, /* displayInstructions */ true); printf("target group:\n"); - emitDispIG(targetGroup, nullptr, /* displayInstructions */ false); + emitDispIG(targetGroup, /* displayFunc */ false, /* displayInstructions */ false); assert(jmp == id); } @@ -9171,6 +9340,10 @@ void emitter::emitInitIG(insGroup* ig) ig->igGCregs = RBM_NONE; ig->igInsCnt = 0; +#if EMIT_BACKWARDS_NAVIGATION + ig->igLastIns = nullptr; +#endif // EMIT_BACKWARDS_NAVIGATION + #if FEATURE_LOOP_ALIGN ig->igLoopBackEdge = nullptr; #endif @@ -9195,6 +9368,15 @@ void emitter::emitInsertIGAfter(insGroup* insertAfterIG, insGroup* ig) ig->igNext = insertAfterIG->igNext; insertAfterIG->igNext = ig; +#if EMIT_BACKWARDS_NAVIGATION + ig->igPrev = insertAfterIG; + + if (ig->igNext != nullptr) + { + ig->igNext->igPrev = ig; + } +#endif // EMIT_BACKWARDS_NAVIGATION + if (emitIGlast == insertAfterIG) { // If we are inserting at the end, then update the 'last' pointer diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index a8ff3e2cf693f0..17f4d64740877a 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -38,6 +38,8 @@ #define EMIT_INSTLIST_VERBOSE (emitComp->verbose) #endif +#define EMIT_BACKWARDS_NAVIGATION 0 // If 1, enable backwards navigation code for MIR (insGroup/instrDesc). + /*****************************************************************************/ #ifdef DEBUG @@ -252,6 +254,10 @@ struct insGroup { insGroup* igNext; +#if EMIT_BACKWARDS_NAVIGATION + insGroup* igPrev; +#endif + #ifdef DEBUG insGroup* igSelf; // for consistency checking #endif @@ -320,6 +326,12 @@ struct insGroup insPlaceholderGroupData* igPhData; // when igFlags & IGF_PLACEHOLDER }; +#if EMIT_BACKWARDS_NAVIGATION + // Last instruction in group, if any (nullptr if none); used for backwards navigation. + // (Should be type emitter::instrDesc*). + void* igLastIns; +#endif + #if EMIT_TRACK_STACK_DEPTH unsigned igStkLvl; // stack level on entry #endif @@ -335,6 +347,12 @@ struct insGroup insPlaceholderGroupData* igPhData; // when igFlags & IGF_PLACEHOLDER }; +#if EMIT_BACKWARDS_NAVIGATION + // Last instruction in group, if any (nullptr if none); used for backwards navigation. + // (Should be type emitter::instrDesc*). + void* igLastIns; +#endif + #if EMIT_TRACK_STACK_DEPTH unsigned igStkLvl; // stack level on entry #endif @@ -574,8 +592,6 @@ class emitter #endif // TARGET_XARCH - struct instrDesc; - struct instrDescDebugInfo { unsigned idNum; @@ -684,12 +700,6 @@ class emitter } #endif - void idSetRelocFlags(emitAttr attr) - { - _idCnsReloc = (EA_IS_CNS_RELOC(attr) ? 1 : 0); - _idDspReloc = (EA_IS_DSP_RELOC(attr) ? 1 : 0); - } - //////////////////////////////////////////////////////////////////////// // Space taken up to here: // x86: 17 bits @@ -729,7 +739,6 @@ class emitter // the live gcrefReg mask for the call instructions on x86/x64 // regNumber _idReg1 : REGNUM_BITS; // register num - regNumber _idReg2 : REGNUM_BITS; //////////////////////////////////////////////////////////////////////// @@ -738,7 +747,7 @@ class emitter // amd64: 38 bits // arm: 32 bits // arm64: 31 bits - CLANG_FORMAT_COMMENT_ANCHOR; + // loongarch64: 28 bits unsigned _idSmallDsc : 1; // is this a "small" descriptor? unsigned _idLargeCns : 1; // does a large constant follow? @@ -770,18 +779,6 @@ class emitter unsigned _idLclVar : 1; // access a local on stack unsigned _idLclFPBase : 1; // access a local on stack - SP based offset insOpts _idInsOpt : 3; // options for Load/Store instructions - -// For arm we have used 16 bits -#define ID_EXTRA_BITFIELD_BITS (16) - -#elif defined(TARGET_ARM64) -// For Arm64, we have used 17 bits from the second DWORD. -#define ID_EXTRA_BITFIELD_BITS (17) -#elif defined(TARGET_XARCH) || defined(TARGET_LOONGARCH64) - // For xarch and LoongArch64, we have used 14 bits from the second DWORD. -#define ID_EXTRA_BITFIELD_BITS (14) -#else -#error Unsupported or unset target architecture #endif //////////////////////////////////////////////////////////////////////// @@ -792,42 +789,95 @@ class emitter // arm64: 49 bits // loongarch64: 46 bits + // + // How many bits have been used beyond the first 32? + // Define ID_EXTRA_BITFIELD_BITS to that number. + // + CLANG_FORMAT_COMMENT_ANCHOR; + +#if defined(TARGET_ARM) +#define ID_EXTRA_BITFIELD_BITS (16) +#elif defined(TARGET_ARM64) +#define ID_EXTRA_BITFIELD_BITS (17) +#elif defined(TARGET_XARCH) || defined(TARGET_LOONGARCH64) +#define ID_EXTRA_BITFIELD_BITS (14) +#else +#error Unsupported or unset target architecture +#endif + unsigned _idCnsReloc : 1; // LargeCns is an RVA and needs reloc tag unsigned _idDspReloc : 1; // LargeDsp is an RVA and needs reloc tag #define ID_EXTRA_RELOC_BITS (2) +#if EMIT_BACKWARDS_NAVIGATION + + // "Pointer" to previous instrDesc in this group. If zero, there is + // no previous instrDesc. If non-zero, then _idScaledPrevOffset * 4 + // is the size in bytes of the previous instrDesc; subtract that from + // the current instrDesc* to reach the previous one. + // All instrDesc types are <= 56 bytes, but we also need m_debugInfoSize, + // which is pointer sized, so 5 bits are required on 64-bit and 4 bits + // on 32-bit. + CLANG_FORMAT_COMMENT_ANCHOR; + +#ifdef HOST_64BIT + unsigned _idScaledPrevOffset : 5; +#define ID_EXTRA_PREV_OFFSET_BITS (5) +#else + unsigned _idScaledPrevOffset : 4; +#define ID_EXTRA_PREV_OFFSET_BITS (4) +#endif + +#else // !EMIT_BACKWARDS_NAVIGATION +#define ID_EXTRA_PREV_OFFSET_BITS (0) +#endif // !EMIT_BACKWARDS_NAVIGATION + //////////////////////////////////////////////////////////////////////// - // Space taken up to here: - // x86: 48 bits - // amd64: 48 bits - // arm: 50 bits - // arm64: 51 bits - // loongarch64: 48 bits + // Space taken up to here (with/without prev offset, assuming host==target): + // x86: 52/48 bits + // amd64: 53/48 bits + // arm: 54/50 bits + // arm64: 56/51 bits + // loongarch64: 53/48 bits CLANG_FORMAT_COMMENT_ANCHOR; -#define ID_EXTRA_BITS (ID_EXTRA_RELOC_BITS + ID_EXTRA_BITFIELD_BITS) +#define ID_EXTRA_BITS (ID_EXTRA_RELOC_BITS + ID_EXTRA_BITFIELD_BITS + ID_EXTRA_PREV_OFFSET_BITS) /* Use whatever bits are left over for small constants */ #define ID_BIT_SMALL_CNS (32 - ID_EXTRA_BITS) + C_ASSERT(ID_BIT_SMALL_CNS > 0); #define ID_MIN_SMALL_CNS 0 #define ID_MAX_SMALL_CNS (int)((1 << ID_BIT_SMALL_CNS) - 1U) //////////////////////////////////////////////////////////////////////// - // Small constant size: - // x86: 16 bits - // amd64: 16 bits - // arm: 14 bits - // arm64: 13 bits + // Small constant size (with/without prev offset, assuming host==target): + // x86: 12/16 bits + // amd64: 11/16 bits + // arm: 10/14 bits + // arm64: 8/13 bits + // loongarch64: 11/16 bits unsigned _idSmallCns : ID_BIT_SMALL_CNS; //////////////////////////////////////////////////////////////////////// // Space taken up to here: 64 bits, all architectures, by design. //////////////////////////////////////////////////////////////////////// + + // + // This is the end of the 'small' instrDesc which is the same on all platforms + // + // If you add lots more fields that need to be cleared (such + // as various flags), you might need to update the body of + // emitter::emitAllocInstr() to clear them. + // + // SMALL_IDSC_SIZE is this size, in bytes. + // CLANG_FORMAT_COMMENT_ANCHOR; +#define SMALL_IDSC_SIZE 8 + public: instrDescDebugInfo* idDebugOnlyInfo() const { @@ -843,21 +893,6 @@ class emitter private: CLANG_FORMAT_COMMENT_ANCHOR; -// -// This is the end of the 'small' instrDesc which is the same on all platforms -// Sizes (includes one pointer): -// x86: 2 DWORDs, 96 bits -// amd64: 4 DWORDs, 128 bits -// arm: 3 DWORDs, 96 bits -// arm64: 4 DWORDs, 128 bits -// There should no padding or alignment issues on any platform or configuration. -// -// If you add lots more fields that need to be cleared (such -// as various flags), you might need to update the body of -// emitter::emitAllocInstr() to clear them. - -#define SMALL_IDSC_SIZE 8 - void checkSizes(); union idAddrUnion { @@ -1366,6 +1401,29 @@ class emitter return idIsDspReloc() || idIsCnsReloc(); } + void idSetRelocFlags(emitAttr attr) + { + _idCnsReloc = (EA_IS_CNS_RELOC(attr) ? 1 : 0); + _idDspReloc = (EA_IS_DSP_RELOC(attr) ? 1 : 0); + } + +#if EMIT_BACKWARDS_NAVIGATION + + // Return the stored size of the previous instrDesc in bytes, or zero if there + // is no previous instrDesc in this group. + unsigned idPrevSize() + { + return _idScaledPrevOffset * 4; + } + void idSetPrevSize(unsigned prevInstrDescSizeInBytes) + { + assert(prevInstrDescSizeInBytes % 4 == 0); + _idScaledPrevOffset = prevInstrDescSizeInBytes / 4; + assert(idPrevSize() == prevInstrDescSizeInBytes); + } + +#endif // EMIT_BACKWARDS_NAVIGATION + unsigned idSmallCns() const { return _idSmallCns; @@ -1784,7 +1842,7 @@ class emitter void emitDispIGflags(unsigned flags); void emitDispIG(insGroup* ig, - insGroup* igPrev = nullptr, + bool displayFunc = false, bool displayInstructions = false, bool displayLocation = true); void emitDispIGlist(bool displayInstructions = false); @@ -2013,7 +2071,10 @@ class emitter /* The logic that creates and keeps track of instruction groups */ /************************************************************************/ - // SC_IG_BUFFER_SIZE defines the size, in bytes, of the single, global instruction group buffer. + // The IG buffer size is the size, in bytes, of the single, global instruction group buffer. + // It is computed dynamically based on SC_IG_BUFFER_NUM_SMALL_DESCS, SC_IG_BUFFER_NUM_LARGE_DESCS, + // and whether a debug info pointer is being saved. + // // When a label is reached, or the buffer is filled, the precise amount of the buffer that was // used is copied to a newly allocated, precisely sized buffer, and the global buffer is reset // for use with the next set of instructions (see emitSavIG). If the buffer was filled before @@ -2226,6 +2287,10 @@ class emitter instrDesc* emitLastIns; insGroup* emitLastInsIG; +#if EMIT_BACKWARDS_NAVIGATION + unsigned emitLastInsFullSize; +#endif // EMIT_BACKWARDS_NAVIGATION + // Check if a peephole optimization involving emitLastIns is safe. // // We must have a non-null emitLastIns to consult. @@ -2286,6 +2351,11 @@ class emitter #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 +#if EMIT_BACKWARDS_NAVIGATION + bool emitPrevID(insGroup*& ig, instrDesc*& id); + bool emitGetLastIns(insGroup** pig, instrDesc** pid); +#endif // EMIT_BACKWARDS_NAVIGATION + #ifdef TARGET_X86 void emitMarkStackLvl(unsigned stackLevel); #endif diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 6840bd601ab755..574282bdf9a994 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -600,7 +600,7 @@ void emitter::emitIns(instruction ins) * the negtive `offs` is special for optimizing the large offset which >2047. * when offs >2047 we can't encode one instruction to load/store the data, * if there are several load/store at this case, you have to repeat the similar - * large offs with reduntant instructions and maybe eat up the `SC_IG_BUFFER_SIZE`. + * large offs with reduntant instructions and maybe eat up the `emitIGbuffSize`. * * Before optimizing the following instructions: * lu12i.w x0, 0x0