diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 98f74b755e1408..5401737c5f5aa3 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -71,20 +71,26 @@ int emitLocation::GetInsOffset() const return emitGetInsOfsFromCodePos(codePos); } -// Get the instruction offset in the current instruction group, which must be a funclet prolog group. +// 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. -// TODO-AMD64-Bug?: We only support a single main function prolog group, but allow for multiple funclet prolog -// groups (not that we actually use that flexibility, since the funclet prolog will be small). How to -// handle that? UNATIVE_OFFSET emitLocation::GetFuncletPrologOffset(emitter* emit) const { assert(ig->igFuncIdx != 0); assert((ig->igFlags & IGF_FUNCLET_PROLOG) != 0); - assert(ig == emit->emitCurIG); + assert((ig->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0); + assert(GetInsOffset() == 0); - return emit->emitCurIGsize; -} + 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. @@ -116,10 +122,142 @@ void emitLocation::Print(LONG compMethodID) const { unsigned insNum = emitGetInsNumFromCodePos(codePos); unsigned insOfs = emitGetInsOfsFromCodePos(codePos); - printf("(G_M%03u_IG%02u,ins#%d,ofs#%d)", compMethodID, ig->igNum, insNum, insOfs); + printf("(G_M%03u_IG%02u,ins#%d,ofs#%d)", compMethodID, ig->GetDisplayId(), insNum, insOfs); } #endif // DEBUG +//------------------------------------------------------------------------ +// InitializeNum: Initialize this IG's order/display number. +// +// Each subsequently allocated group should be assigned a monotonically +// increasing number. +// +// Arguments: +// num - The number +// +void insGroup::InitializeNum(unsigned num) +{ + igNum = num; +} + +//------------------------------------------------------------------------ +// GetDisplayId: Get the ID of this group used for display. +// +// Return Value: +// A unique ID for this group. +// +unsigned insGroup::GetDisplayId() const +{ + return igNum; +} + +//------------------------------------------------------------------------ +// IsBefore: Is this group before 'ig' in layout (IG list) order? +// +// Most groups are generated in-order, such that their 'numbers' reflect +// both the layout and IG linked list order. However, for prologs/epilogs, +// we can have extend groups that are generated after the IR-driven code, +// and this function accounts for that. +// +// Arguments: +// ig - The group to compare to +// +// Return Value: +// Whether 'this' is before 'ig'. +// +bool insGroup::IsBefore(const insGroup* ig) const +{ + assert(ig != nullptr); + + // All IGs are generated in order, except the extend groups that may hangs off prologs and epilogs. + // In turn, those groups themselves are generated in order within their respective regions. + unsigned positionOfThis; + if ((igFlags & IGF_OUT_OF_ORDER_MASK) != 0) + { + const insGroup* nextIG = igNext; + while (true) + { + if (nextIG == nullptr) + { + return false; + } + if (((nextIG->igFlags & IGF_OUT_OF_ORDER_MASK) == 0) || ((nextIG->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0)) + { + positionOfThis = nextIG->igNum - 1; // Position equal to the in-order 'head' of the region. + break; + } + if (nextIG == ig) + { + return true; + } + + nextIG = nextIG->igNext; + } + } + else + { + positionOfThis = igNum; + } + + unsigned positionOfIG; + if ((ig->igFlags & IGF_OUT_OF_ORDER_MASK) != 0) + { + const insGroup* nextIG = ig->igNext; + while (true) + { + if (nextIG == nullptr) + { + return true; + } + if (((nextIG->igFlags & IGF_OUT_OF_ORDER_MASK) == 0) || ((nextIG->igFlags & IGF_OUT_OF_ORDER_HEAD) != 0)) + { + positionOfIG = nextIG->igNum - 1; + break; + } + if (nextIG == this) + { + return false; + } + + nextIG = nextIG->igNext; + } + } + else + { + positionOfIG = ig->igNum; + } + + return positionOfThis < positionOfIG; +} + +//------------------------------------------------------------------------ +// IsBefore: Is this group before 'ig' in layout order, or equal to it? +// +// Arguments: +// ig - The group to compare to +// +// Return Value: +// Whether 'this' is before 'ig' or is equal to it. +// +bool insGroup::IsBeforeOrEqual(const insGroup* ig) const +{ + return !IsAfter(ig); +} + +//------------------------------------------------------------------------ +// IsBefore: Is this group after 'ig' in layout order? +// +// Arguments: +// ig - The group to compare to +// +// Return Value: +// Whether 'this' is after 'ig'. +// +bool insGroup::IsAfter(const insGroup* ig) const +{ + return ig->IsBefore(this); +} + /***************************************************************************** * * Return the name of an instruction format. @@ -788,9 +926,6 @@ void emitter::emitGenIG(insGroup* ig) { IMPL_LIMITATION("Too many arguments pushed on stack"); } - - // printf("Start IG #%02u [stk=%02u]\n", ig->igNum, emitCurStackLvl); - #endif if (emitNoGCIG) @@ -1223,9 +1358,9 @@ void emitter::emitBegFN(bool hasFramePtr emitIGbuffSize = 0; #if FEATURE_LOOP_ALIGN - emitLastAlignedIgNum = 0; - emitLastLoopStart = 0; - emitLastLoopEnd = 0; + emitLastAlignedIG = nullptr; + emitLastLoopStart = nullptr; + emitLastLoopEnd = nullptr; #endif /* Record stack frame info (the temp size is just an estimate) */ @@ -1444,8 +1579,6 @@ void emitter::perfScoreUnhandledInstruction(instrDesc* id, insExecutionCharacter pResult->insLatency = PERFSCORE_LATENCY_1C; } -#endif // defined(DEBUG) || defined(LATE_DISASM) - //---------------------------------------------------------------------------------------- // getCurrentBlockWeight: Return the block weight for the currently active block // @@ -1467,12 +1600,19 @@ weight_t emitter::getCurrentBlockWeight() { return m_compiler->compCurBB->getBBWeight(m_compiler); } - else // we have a null compCurBB + else if (emitCurIG != nullptr) + { + // Prolog or epilog case, use the weight of the head group or its extensions. + assert((emitCurIG->igFlags & IGF_OUT_OF_ORDER_MASK) != 0); + return emitCurIG->igWeight; + } + else { - // prolog or epilog case, so just use the standard weight + // This is the prolog case (when we're just initializing the IG list). return BB_UNITY_WEIGHT; } } +#endif // defined(DEBUG) || defined(LATE_DISASM) #if defined(TARGET_LOONGARCH64) void emitter::dispIns(instrDesc* id) @@ -1585,16 +1725,8 @@ void* emitter::emitAllocAnyInstr(size_t sz, emitAttr opsz) { #ifdef DEBUG // Under STRESS_EMITTER, put every instruction in its own instruction group. - // We can't do this for a prolog, epilog, funclet prolog, or funclet epilog, - // because those are generated out of order. We currently have a limitation - // where the jump shortening pass uses the instruction group number to determine - // if something is earlier or later in the code stream. This implies that - // these groups cannot be more than a single instruction group. Note that - // the prolog/epilog placeholder groups ARE generated in order, and are - // re-used. But generating additional groups would not work. if (m_compiler->compStressCompile(Compiler::STRESS_EMITTER, 1) && emitCurIGinsCnt && !emitIGisInProlog(emitCurIG) && - !emitIGisInEpilog(emitCurIG) && !emitCurIG->endsWithAlignInstr() && !emitIGisInFuncletProlog(emitCurIG) && - !emitIGisInFuncletEpilog(emitCurIG)) + !emitIGisInFuncletProlog(emitCurIG) && !emitCurIG->endsWithAlignInstr()) { emitNxtIG(true); } @@ -1775,7 +1907,7 @@ void emitter::emitCheckIGList() if (currIG->igOffs != currentOffset) { - printf("IG%02u has offset %08X, expected %08X\n", currIG->igNum, currIG->igOffs, currentOffset); + printf("IG%02u has offset %08X, expected %08X\n", currIG->GetDisplayId(), currIG->igOffs, currentOffset); assert(!"bad block offset"); } @@ -2090,6 +2222,7 @@ void emitter::emitCreatePlaceholderIG(insGroupPlaceholderType igType, { igPh->igFlags |= IGF_FUNCLET_EPILOG; } + igPh->igFlags |= IGF_OUT_OF_ORDER_HEAD; /* Link it into the placeholder list */ @@ -2331,7 +2464,7 @@ void emitter::emitBegPrologEpilog(insGroup* igPh) m_compiler->funSetCurrentFunc(ig->igFuncIdx); /* Set the new IG as the place to generate code */ - + emitCurCodeOffset = ig->igOffs; emitGenIG(ig); #if EMIT_TRACK_STACK_DEPTH @@ -2851,7 +2984,7 @@ void* emitter::emitAddInlineLabel() // void emitter::emitPrintLabel(const insGroup* ig) const { - printf("G_M%03u_IG%02u", m_compiler->compMethodID, ig->igNum); + printf("G_M%03u_IG%02u", m_compiler->compMethodID, ig->GetDisplayId()); } //----------------------------------------------------------------------------- @@ -2869,7 +3002,7 @@ const char* emitter::emitLabelString(const insGroup* ig) const static char buf[4][TEMP_BUFFER_LEN]; const char* retbuf; - sprintf_s(buf[curBuf], TEMP_BUFFER_LEN, "G_M%03u_IG%02u", m_compiler->compMethodID, ig->igNum); + sprintf_s(buf[curBuf], TEMP_BUFFER_LEN, "G_M%03u_IG%02u", m_compiler->compMethodID, ig->GetDisplayId()); retbuf = buf[curBuf]; curBuf = (curBuf + 1) % 4; return retbuf; @@ -2956,7 +3089,7 @@ void emitter::emitSplit(emitLocation* startLoc, { #ifdef DEBUG if (EMITVERBOSE) - printf("emitSplit: can't split at IG%02u; we don't have a candidate to report\n", ig->igNum); + printf("emitSplit: can't split at IG%02u; we don't have a candidate to report\n", ig->GetDisplayId()); #endif return; } @@ -2967,7 +3100,7 @@ void emitter::emitSplit(emitLocation* startLoc, { #ifdef DEBUG if (EMITVERBOSE) - printf("emitSplit: can't split at IG%02u; we already reported it\n", igLastCandidate->igNum); + printf("emitSplit: can't split at IG%02u; we already reported it\n", igLastCandidate->GetDisplayId()); #endif return; } @@ -2980,7 +3113,7 @@ void emitter::emitSplit(emitLocation* startLoc, { #ifdef DEBUG if (EMITVERBOSE) - printf("emitSplit: can't split at IG%02u; zero-sized candidate\n", igLastCandidate->igNum); + printf("emitSplit: can't split at IG%02u; zero-sized candidate\n", igLastCandidate->GetDisplayId()); #endif return; } @@ -2991,7 +3124,7 @@ void emitter::emitSplit(emitLocation* startLoc, if (EMITVERBOSE) { printf("emitSplit: split at IG%02u is size %x, %s than requested maximum size of %x\n", - igLastCandidate->igNum, candidateSize, (candidateSize >= maxSplitSize) ? "larger" : "less", + igLastCandidate->GetDisplayId(), candidateSize, (candidateSize >= maxSplitSize) ? "larger" : "less", maxSplitSize); } #endif @@ -3040,7 +3173,7 @@ void emitter::emitSplit(emitLocation* startLoc, if ((igLastCandidate != nullptr) && (curSize == candidateSize)) { JITDUMP("emitSplit: can't split at last candidate IG%02u because it would create a zero-sized fragment\n", - igLastCandidate->igNum); + igLastCandidate->GetDisplayId()); } else { @@ -4011,7 +4144,7 @@ void emitter::emitDispIG(insGroup* ig, bool displayFunc, bool displayInstruction printf("%s placeholder, next placeholder=", pszType); if (igPh->igPhData->igPhNext) { - printf("IG%02u ", igPh->igPhData->igPhNext->igNum); + printf("IG%02u ", igPh->igPhData->igPhNext->GetDisplayId()); } else { @@ -4113,7 +4246,7 @@ void emitter::emitDispIG(insGroup* ig, bool displayFunc, bool displayInstruction #if FEATURE_LOOP_ALIGN if (ig->igLoopBackEdge != nullptr) { - printf("%sloop=IG%02u", separator, ig->igLoopBackEdge->igNum); + printf("%sloop=IG%02u", separator, ig->igLoopBackEdge->GetDisplayId()); separator = ", "; } #endif // FEATURE_LOOP_ALIGN @@ -4234,7 +4367,7 @@ void emitter::emitDispJumpList() unsigned int jmpCount = 0; for (instrDescJmp* jmp = emitJumpList; jmp != nullptr; jmp = jmp->idjNext) { - printf("IG%02u IN%04x %3s[%u]", jmp->idjIG->igNum, jmp->idDebugOnlyInfo()->idNum, + printf("IG%02u IN%04x %3s[%u]", jmp->idjIG->GetDisplayId(), jmp->idDebugOnlyInfo()->idNum, codeGen->genInsDisplayName(jmp), jmp->idCodeSize()); if (!jmp->idIsBound()) @@ -4255,7 +4388,7 @@ void emitter::emitDispJumpList() } else { - printf(" -> IG%02u", targetGroup->igNum); + printf(" -> IG%02u", targetGroup->GetDisplayId()); } } @@ -4377,7 +4510,7 @@ size_t emitter::emitIssue1Instr(insGroup* ig, instrDesc* id, BYTE** dp) #if FEATURE_LOOP_ALIGN // Should never over-estimate align instruction or any instruction before the last align instruction of a method - assert(id->idIns() != INS_align && emitCurIG->igNum > emitLastAlignedIgNum); + assert(id->idIns() != INS_align && ((emitLastAlignedIG == nullptr) || emitCurIG->IsAfter(emitLastAlignedIG))); #endif #if DEBUG_EMIT @@ -4593,8 +4726,8 @@ void emitter::emitRemoveJumpToNextInst() instrDescJmp* jmp = emitJumpList; instrDescJmp* previousJmp = nullptr; #if DEBUG - UNATIVE_OFFSET previousJumpIgNum = (UNATIVE_OFFSET)-1; - unsigned int previousJumpInsNum = -1; + insGroup* previousJumpIG = nullptr; + unsigned int previousJumpInsNum = -1; #endif // DEBUG while (jmp) @@ -4607,9 +4740,9 @@ void emitter::emitRemoveJumpToNextInst() #if DEBUG assert(jmp->idInsFmt() == IF_LABEL); assert(emitIsUncondJump(jmp)); - assert((jmpGroup->igNum > previousJumpIgNum) || (previousJumpIgNum == (UNATIVE_OFFSET)-1) || - ((jmpGroup->igNum == previousJumpIgNum) && (jmp->idDebugOnlyInfo()->idNum > previousJumpInsNum))); - previousJumpIgNum = jmpGroup->igNum; + assert((previousJumpIG == nullptr) || jmpGroup->IsAfter(previousJumpIG) || + ((jmpGroup == previousJumpIG) && (jmp->idDebugOnlyInfo()->idNum > previousJumpInsNum))); + previousJumpIG = jmpGroup; previousJumpInsNum = jmp->idDebugOnlyInfo()->idNum; #endif // DEBUG @@ -4651,7 +4784,7 @@ void emitter::emitRemoveJumpToNextInst() JITDUMP("IG%02u IN%04x is the last instruction in the group and jumps to the next instruction group " "IG%02u %s, removing.\n", - jmpGroup->igNum, jmp->idDebugOnlyInfo()->idNum, targetGroup->igNum, + jmpGroup->GetDisplayId(), jmp->idDebugOnlyInfo()->idNum, targetGroup->GetDisplayId(), emitLabelString(targetGroup)); #endif // DEBUG @@ -4708,24 +4841,24 @@ void emitter::emitRemoveJumpToNextInst() #if DEBUG if (targetGroup == nullptr) { - JITDUMP("IG%02u IN%04x jump target is not set!, keeping.\n", jmpGroup->igNum, + JITDUMP("IG%02u IN%04x jump target is not set!, keeping.\n", jmpGroup->GetDisplayId(), jmp->idDebugOnlyInfo()->idNum); } else if (jmpGroup->igNext != targetGroup) { - JITDUMP("IG%02u IN%04x does not jump to the next instruction group, keeping.\n", jmpGroup->igNum, - jmp->idDebugOnlyInfo()->idNum); + JITDUMP("IG%02u IN%04x does not jump to the next instruction group, keeping.\n", + jmpGroup->GetDisplayId(), jmp->idDebugOnlyInfo()->idNum); } else if ((jmpGroup->igFlags & IGF_HAS_REMOVABLE_JMP) == 0) { JITDUMP("IG%02u IN%04x containing instruction group is not marked with IGF_HAS_REMOVABLE_JMP, " "keeping.\n", - jmpGroup->igNum, jmp->idDebugOnlyInfo()->idNum); + jmpGroup->GetDisplayId(), jmp->idDebugOnlyInfo()->idNum); } else if (jmpGroup->endsWithAlignInstr()) { - JITDUMP("IG%02u IN%04x containing instruction group has alignment, keeping.\n", jmpGroup->igNum, - jmp->idDebugOnlyInfo()->idNum); + JITDUMP("IG%02u IN%04x containing instruction group has alignment, keeping.\n", + jmpGroup->GetDisplayId(), jmp->idDebugOnlyInfo()->idNum); } #endif // DEBUG } @@ -4740,9 +4873,9 @@ void emitter::emitRemoveJumpToNextInst() { insGroup* adjOffIG = jmpGroup->igNext; insGroup* adjOffUptoIG = nextJmp != nullptr ? nextJmp->idjIG : emitIGlast; - while ((adjOffIG != nullptr) && (adjOffIG->igNum <= adjOffUptoIG->igNum)) + while ((adjOffIG != nullptr) && adjOffIG->IsBeforeOrEqual(adjOffUptoIG)) { - JITDUMP("Adjusted offset of IG%02u from %04X to %04X\n", adjOffIG->igNum, adjOffIG->igOffs, + JITDUMP("Adjusted offset of IG%02u from %04X to %04X\n", adjOffIG->GetDisplayId(), adjOffIG->igOffs, (adjOffIG->igOffs - totalRemovedSize)); adjOffIG->igOffs -= totalRemovedSize; adjOffIG = adjOffIG->igNext; @@ -5013,8 +5146,7 @@ void emitter::emitJumpDistBind() assert(lastLJ == nullptr || lastIG != jmp->idjIG || lastLJ->idjOffs < jmp->idjOffs); lastLJ = (lastIG == jmp->idjIG) ? jmp : nullptr; - assert(lastIG == nullptr || lastIG->igNum <= jmp->idjIG->igNum || jmp->idjIG == prologIG || - emitNxtIGnum > unsigned(0xFFFF)); // igNum might overflow + assert(lastIG == nullptr || lastIG->IsBeforeOrEqual(jmp->idjIG) || jmp->idjIG == prologIG); lastIG = jmp->idjIG; #endif // DEBUG @@ -5043,8 +5175,8 @@ void emitter::emitJumpDistBind() #ifdef DEBUG if (EMITVERBOSE) { - printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->igNum, lstIG->igOffs, - lstIG->igOffs - adjIG); + printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->GetDisplayId(), + lstIG->igOffs, lstIG->igOffs - adjIG); } #endif // DEBUG lstIG->igOffs -= adjIG; @@ -5219,7 +5351,7 @@ void emitter::emitJumpDistBind() srcEncodingOffs = srcInstrOffs + ssz; // Encoding offset of relative offset for small branch #endif - if (jmpIG->igNum < tgtIG->igNum) + if (jmpIG->IsBefore(tgtIG)) { /* Forward jump */ @@ -5337,7 +5469,7 @@ void emitter::emitJumpDistBind() if (emitIsCmpJump(jmp)) { - if (jmpIG->igNum < tgtIG->igNum) + if (jmpIG->IsBefore(tgtIG)) { /* Forward jump */ @@ -5528,7 +5660,7 @@ void emitter::emitJumpDistBind() #ifdef DEBUG if (EMITVERBOSE) { - printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->igNum, lstIG->igOffs, + printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->GetDisplayId(), lstIG->igOffs, lstIG->igOffs - adjIG); } #endif // DEBUG @@ -5732,8 +5864,8 @@ void emitter::emitLongLoopAlign(unsigned alignmentBoundary DEBUG_ARG(bool isPlac // void emitter::emitConnectAlignInstrWithCurIG() { - JITDUMP("Mapping 'align' instruction in IG%02u to target IG%02u\n", emitAlignLastGroup->idaIG->igNum, - emitCurIG->igNum); + JITDUMP("Mapping 'align' instruction in IG%02u to target IG%02u\n", emitAlignLastGroup->idaIG->GetDisplayId(), + emitCurIG->GetDisplayId()); // Since we never align overlapping instructions, it is always guaranteed that // the emitAlignLastGroup points to the loop that is in process of getting aligned. @@ -5806,17 +5938,15 @@ bool emitter::emitEndsWithAlignInstr() // isAlignAdjusted - DEBUG only. Determine if adjustments are done to the align instructions or not. // During generating code, it is 'false' (because we haven't adjusted the size yet). // During outputting code, it is 'true'. -// containingIGNum - DEBUG only. IG number of IG that contains the current align instruction we are processing. -// loopHeadPredIGNum - DEBUG only. IG number of IG that precedes the IG that we are aligning with current align +// containingIG - DEBUG only. IG that contains the current align instruction we are processing. +// loopHeadPredIG - DEBUG only. IG that precedes the IG that we are aligning with current align // instruction. // // Returns: size of a loop in bytes. // -unsigned emitter::getLoopSize(insGroup* igLoopHeader, - unsigned maxLoopSize // - DEBUG_ARG(bool isAlignAdjusted) // - DEBUG_ARG(UNATIVE_OFFSET containingIGNum) // - DEBUG_ARG(UNATIVE_OFFSET loopHeadPredIGNum)) +unsigned emitter::getLoopSize(insGroup* igLoopHeader, + unsigned maxLoopSize DEBUGARG(bool isAlignAdjusted) DEBUGARG(insGroup* containingIG) + DEBUGARG(insGroup* loopHeadPredIG)) { unsigned loopSize = 0; @@ -5873,12 +6003,12 @@ unsigned emitter::getLoopSize(insGroup* igLoopHeader, { char buffer[5000]; int written = sprintf_s(buffer, 35, "Mismatch in align instruction.\n"); - written += sprintf_s(buffer + written, 100, "Containing IG: IG%02u\n", containingIGNum); - written += sprintf_s(buffer + written, 100, "loopHeadPredIG: IG%02u\n", loopHeadPredIGNum); - written += sprintf_s(buffer + written, 100, "loopHeadIG: IG%02u\n", igLoopHeader->igNum); - written += sprintf_s(buffer + written, 100, "igInLoop: IG%02u\n", igInLoop->igNum); + written += sprintf_s(buffer + written, 100, "Containing IG: IG%02u\n", containingIG->GetDisplayId()); + written += sprintf_s(buffer + written, 100, "loopHeadPredIG: IG%02u\n", loopHeadPredIG->GetDisplayId()); + written += sprintf_s(buffer + written, 100, "loopHeadIG: IG%02u\n", igLoopHeader->GetDisplayId()); + written += sprintf_s(buffer + written, 100, "igInLoop: IG%02u\n", igInLoop->GetDisplayId()); written += sprintf_s(buffer + written, 100, "igInLoop->igLoopBackEdge: IG%02u\n", - igInLoop->igLoopBackEdge->igNum); + igInLoop->igLoopBackEdge->GetDisplayId()); #if EMIT_BACKWARDS_NAVIGATION if (igInLoop->endsWithAlignInstr()) @@ -5887,7 +6017,7 @@ unsigned emitter::getLoopSize(insGroup* igLoopHeader, instrDescAlign* alignInstr = (instrDescAlign*)igInLoop->igLastIns; assert(alignInstr->idaIG == igInLoop); written += sprintf_s(buffer + written, 100, "igInLoop has align instruction for : IG%02u\n", - alignInstr->idaLoopHeadPredIG->igNext->igNum); + alignInstr->idaLoopHeadPredIG->igNext->GetDisplayId()); } #endif // EMIT_BACKWARDS_NAVIGATION @@ -5896,12 +6026,12 @@ unsigned emitter::getLoopSize(insGroup* igLoopHeader, for (igIter = igLoopHeader; (igIter != nullptr) && (igIter->igLoopBackEdge != igLoopHeader); igIter = igIter->igNext) { - written += sprintf_s(buffer + written, 100, "\tIG%02u\n", igIter->igNum); + written += sprintf_s(buffer + written, 100, "\tIG%02u\n", igIter->GetDisplayId()); } if (igIter == nullptr) { written += sprintf_s(buffer + written, 100, "Did not find IG with back edge to IG%02u\n", - igLoopHeader->igNum); + igLoopHeader->GetDisplayId()); } printf("\n\n%s", buffer); assert(false && !"Mismatch in align instruction"); @@ -5916,7 +6046,7 @@ unsigned emitter::getLoopSize(insGroup* igLoopHeader, // Find the alignInstr for igInLoop IG. for (; alignInstr != nullptr; alignInstr = alignInstr->idaNext) { - if (alignInstr->idaIG->igNum == igInLoop->igNum) + if (alignInstr->idaIG == igInLoop) { foundAlignInstr = true; break; @@ -6008,11 +6138,11 @@ bool emitter::emitSetLoopBackEdge(const BasicBlock* loopTopBlock) return false; } - if (dstIG->igNum > emitCurIG->igNum) + if (dstIG->IsAfter(emitCurIG)) { // Is this possible? - JITDUMP("ALIGN: found forward branch from IG%02u to IG%02u; not marking IG back edge.\n", emitCurIG->igNum, - dstIG->igNum); + JITDUMP("ALIGN: found forward branch from IG%02u to IG%02u; not marking IG back edge.\n", + emitCurIG->GetDisplayId(), dstIG->GetDisplayId()); return false; } @@ -6020,17 +6150,18 @@ bool emitter::emitSetLoopBackEdge(const BasicBlock* loopTopBlock) bool alignCurrentLoop = true; bool alignLastLoop = true; - unsigned currLoopStart = dstIG->igNum; - unsigned currLoopEnd = emitCurIG->igNum; + insGroup* currLoopStart = dstIG; + insGroup* currLoopEnd = emitCurIG; // Only mark back-edge if current loop starts after the last inner loop ended. - if (emitLastLoopEnd < currLoopStart) + if ((emitLastLoopEnd == nullptr) || emitLastLoopEnd->IsBefore(currLoopStart)) { assert(emitCurIG->igLoopBackEdge == nullptr); emitCurIG->igLoopBackEdge = dstIG; backEdgeSet = true; - JITDUMP("** IG%02u jumps back to IG%02u forming a loop.\n", currLoopEnd, currLoopStart); + JITDUMP("** IG%02u jumps back to IG%02u forming a loop.\n", currLoopEnd->GetDisplayId(), + currLoopStart->GetDisplayId()); emitLastLoopStart = currLoopStart; emitLastLoopEnd = currLoopEnd; @@ -6048,13 +6179,13 @@ bool emitter::emitSetLoopBackEdge(const BasicBlock* loopTopBlock) // |-----. // } - else if ((currLoopStart < emitLastLoopStart) && (emitLastLoopEnd < currLoopEnd)) + else if (currLoopStart->IsBefore(emitLastLoopStart) && emitLastLoopEnd->IsBefore(currLoopEnd)) { // if current loop completely encloses last loop, // then current loop should not be aligned. alignCurrentLoop = false; } - else if ((emitLastLoopStart < currLoopStart) && (currLoopEnd < emitLastLoopEnd)) + else if (emitLastLoopStart->IsBefore(currLoopStart) && currLoopEnd->IsBefore(emitLastLoopEnd)) { // if last loop completely encloses current loop, // then last loop should not be aligned. @@ -6088,12 +6219,13 @@ bool emitter::emitSetLoopBackEdge(const BasicBlock* loopTopBlock) markedCurrLoop = true; JITDUMP(";; Skip alignment for current loop IG%02u ~ IG%02u because it encloses an aligned loop " "IG%02u ~ IG%02u.\n", - currLoopStart, currLoopEnd, emitLastLoopStart, emitLastLoopEnd); + currLoopStart->GetDisplayId(), currLoopEnd->GetDisplayId(), emitLastLoopStart->GetDisplayId(), + emitLastLoopEnd->GetDisplayId()); } // Find the IG that has 'align' instruction to align the last loop // and clear the IGF_HAS_ALIGN flag. - if (!alignLastLoop && (loopHeadIG != nullptr) && (loopHeadIG->igNum == emitLastLoopStart)) + if (!alignLastLoop && (loopHeadIG != nullptr) && (loopHeadIG == emitLastLoopStart)) { assert(!markedLastLoop); assert(alignInstr->idaIG->endsWithAlignInstr() || alignInstr->idaIG->hadAlignInstr()); @@ -6104,7 +6236,8 @@ bool emitter::emitSetLoopBackEdge(const BasicBlock* loopTopBlock) markedLastLoop = true; JITDUMP(";; Skip alignment for aligned loop IG%02u ~ IG%02u because it encloses the current loop " "IG%02u ~ IG%02u.\n", - emitLastLoopStart, emitLastLoopEnd, currLoopStart, currLoopEnd); + emitLastLoopStart->GetDisplayId(), emitLastLoopEnd->GetDisplayId(), + currLoopStart->GetDisplayId(), currLoopEnd->GetDisplayId()); } if (markedLastLoop && markedCurrLoop) @@ -6160,8 +6293,8 @@ void emitter::emitLoopAlignAdjustments() insGroup* loopHeadIG = alignInstr->loopHeadIG(); insGroup* containingIG = alignInstr->idaIG; - JITDUMP(" Adjusting 'align' instruction in IG%02u that is targeted for IG%02u \n", containingIG->igNum, - loopHeadIG->igNum); + JITDUMP(" Adjusting 'align' instruction in IG%02u that is targeted for IG%02u \n", + containingIG->GetDisplayId(), loopHeadIG->GetDisplayId()); // Since we only adjust the padding up to the next align instruction which is behind the jump, we make sure // that we take into account all the alignBytes we removed until that point. Hence " - alignBytesRemoved" @@ -6176,9 +6309,8 @@ void emitter::emitLoopAlignAdjustments() unsigned actualPaddingNeeded = containingIG->endsWithAlignInstr() - ? emitCalculatePaddingForLoopAlignment(loopHeadIG, - loopIGOffset DEBUG_ARG(false) DEBUG_ARG(containingIG->igNum) - DEBUG_ARG(loopHeadPredIG->igNum)) + ? emitCalculatePaddingForLoopAlignment(loopHeadIG, loopIGOffset DEBUGARG(false) DEBUGARG(containingIG) + DEBUGARG(loopHeadPredIG)) : 0; assert(estimatedPaddingNeeded >= actualPaddingNeeded); @@ -6258,7 +6390,7 @@ void emitter::emitLoopAlignAdjustments() insGroup* adjOffIG = containingIG->igNext; instrDescAlign* nextAlign = emitAlignInNextIG(alignInstr); insGroup* adjOffUptoIG = nextAlign != nullptr ? nextAlign->idaIG : emitIGlast; - while ((adjOffIG != nullptr) && (adjOffIG->igNum <= adjOffUptoIG->igNum)) + while ((adjOffIG != nullptr) && adjOffIG->IsBeforeOrEqual(adjOffUptoIG)) { JITDUMP("Adjusted offset of %s from %04X to %04X\n", emitLabelString(adjOffIG), adjOffIG->igOffs, (adjOffIG->igOffs - alignBytesRemoved)); @@ -6271,9 +6403,9 @@ void emitter::emitLoopAlignAdjustments() if (actualPaddingNeeded > 0) { // Record the last loop IG that will be aligned. No overestimation - // adjustment will be done after emitLastAlignedIgNum. + // adjustment will be done after emitLastAlignedIG. JITDUMP("Recording last aligned IG: %s\n", emitLabelString(loopHeadPredIG)); - emitLastAlignedIgNum = loopHeadPredIG->igNum; + emitLastAlignedIG = loopHeadPredIG; } } @@ -6292,8 +6424,8 @@ void emitter::emitLoopAlignAdjustments() // isAlignAdjusted - Determine if adjustments are done to the align instructions or not. // During generating code, it is 'false' (because we haven't adjusted the size yet). // During outputting code, it is 'true'. -// containingIGNum - IG number of IG that contains the current align instruction we are processing. -// loopHeadPredIGNum - IG number of IG that preceds the IG that we are aligning with current align instruction. +// containingIG - IG that contains the current align instruction we are processing. +// loopHeadPredIG - IG that preceds the IG that we are aligning with current align instruction. // // Returns: Padding amount. // 0 means no padding is needed, either because loop is already aligned or it @@ -6318,9 +6450,9 @@ void emitter::emitLoopAlignAdjustments() // 3c. return paddingNeeded. // unsigned emitter::emitCalculatePaddingForLoopAlignment(insGroup* loopHeadIG, - size_t offset DEBUG_ARG(bool isAlignAdjusted) - DEBUG_ARG(UNATIVE_OFFSET containingIGNum) - DEBUG_ARG(UNATIVE_OFFSET loopHeadPredIGNum)) + size_t offset DEBUGARG(bool isAlignAdjusted) + DEBUGARG(insGroup* containingIG) + DEBUGARG(insGroup* loopHeadPredIG)) { unsigned alignmentBoundary = m_compiler->opts.compJitAlignLoopBoundary; @@ -6347,8 +6479,8 @@ unsigned emitter::emitCalculatePaddingForLoopAlignment(insGroup* loopHeadIG, maxLoopSize = m_compiler->opts.compJitAlignLoopMaxCodeSize; } - unsigned loopSize = getLoopSize(loopHeadIG, maxLoopSize DEBUG_ARG(isAlignAdjusted) DEBUG_ARG(containingIGNum) - DEBUG_ARG(loopHeadPredIGNum)); + unsigned loopSize = + getLoopSize(loopHeadIG, maxLoopSize DEBUGARG(isAlignAdjusted) DEBUGARG(containingIG) DEBUGARG(loopHeadPredIG)); // No padding if loop is big if (loopSize > maxLoopSize) @@ -7113,12 +7245,6 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, #endif } - /* Are we overflowing? */ - if (ig->igNext && (ig->igNum + 1 != ig->igNext->igNum)) - { - NO_WAY("Too many instruction groups"); - } - instrDesc* id = emitFirstInstrDesc(ig->igData); #ifdef DEBUG @@ -9416,8 +9542,6 @@ UNATIVE_OFFSET emitter::emitCodeOffset(void* blockPtr, unsigned codePos) of = emitGetInsOfsFromCodePos(codePos); - // printf("[IG=%02u;ID=%03u;OF=%04X] <= %08X\n", ig->igNum, emitGetInsNumFromCodePos(codePos), of, codePos); - /* Make sure the offset estimate is accurate */ assert(of == emitFindOffset(ig, emitGetInsNumFromCodePos(codePos))); } @@ -9773,7 +9897,7 @@ void emitter::emitInitIG(insGroup* ig) { /* Assign the next available index to the instruction group */ - ig->igNum = emitNxtIGnum; + ig->InitializeNum(emitNxtIGnum); emitNxtIGnum++; diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index 039e2ccaad169e..d02f677ab07b08 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -280,7 +280,10 @@ struct insGroup size_t igDataSize; // size of instrDesc data pointed to by 'igData' #endif - UNATIVE_OFFSET igNum; // for ordering (and display) purposes +private: + unsigned igNum; // for ordering (and display) purposes + +public: UNATIVE_OFFSET igOffs; // offset of this group within method unsigned int igFuncIdx; // Which function/funclet does this belong to? (Index into Compiler::compFuncInfos array.) unsigned short igFlags; // see IGF_xxx below @@ -311,6 +314,7 @@ struct insGroup #ifdef TARGET_ARM64 #define IGF_HAS_REMOVED_INSTR 0x1000 // 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 // 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 @@ -320,6 +324,7 @@ struct insGroup #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) // Try to do better packing based on how large regMaskSmall is (8, 16, or 64 bits). @@ -390,6 +395,11 @@ struct insGroup return (igFlags & IGF_REMOVED_ALIGN) != 0; } + void InitializeNum(unsigned num); + unsigned GetDisplayId() const; + bool IsBefore(const insGroup* ig) const; + bool IsBeforeOrEqual(const insGroup* ig) const; + bool IsAfter(const insGroup* ig) const; }; // end of struct insGroup // For AMD64 the maximum prolog/epilog size supported on the OS is 256 bytes @@ -2901,28 +2911,28 @@ class emitter void emitRemoveJumpToNextInst(); // try to remove unconditional jumps to the next instruction #if FEATURE_LOOP_ALIGN - instrDescAlign* emitCurIGAlignList; // list of align instructions in current IG - unsigned emitLastLoopStart; // Start IG of last inner loop - unsigned emitLastLoopEnd; // End IG of last inner loop - unsigned emitLastAlignedIgNum; // last IG that has align instruction - instrDescAlign* emitAlignList; // list of all align instructions in method - instrDescAlign* emitAlignLast; // last align instruction in method + instrDescAlign* emitCurIGAlignList; // list of align instructions in current IG + insGroup* emitLastLoopStart; // Start IG of last inner loop + insGroup* emitLastLoopEnd; // End IG of last inner loop + insGroup* emitLastAlignedIG; // last IG that has align instruction + instrDescAlign* emitAlignList; // list of all align instructions in method + instrDescAlign* emitAlignLast; // last align instruction in method // Points to the most recent added align instruction. If there are multiple align instructions like in arm64 or // non-adaptive alignment on xarch, this points to the first align instruction of the series of align instructions. instrDescAlign* emitAlignLastGroup; unsigned getLoopSize(insGroup* igLoopHeader, - unsigned maxLoopSize DEBUG_ARG(bool isAlignAdjusted) DEBUG_ARG(UNATIVE_OFFSET containingIGNum) - DEBUG_ARG(UNATIVE_OFFSET loopHeadPredIGNum)); // Get the smallest loop size + unsigned maxLoopSize DEBUGARG(bool isAlignAdjusted) DEBUGARG(insGroup* containingIG) + DEBUGARG(insGroup* loopHeadPredIG)); // Get the smallest loop size void emitLoopAlignment(DEBUG_ARG1(bool isPlacedBehindJmp)); bool emitEndsWithAlignInstr(); // Validate if newLabel is appropriate bool emitSetLoopBackEdge(const BasicBlock* loopTopBlock); void emitLoopAlignAdjustments(); // Predict if loop alignment is needed and make appropriate adjustments unsigned emitCalculatePaddingForLoopAlignment(insGroup* ig, - size_t offset DEBUG_ARG(bool isAlignAdjusted) - DEBUG_ARG(UNATIVE_OFFSET containingIGNum) - DEBUG_ARG(UNATIVE_OFFSET loopHeadPredIGNum)); + size_t offset DEBUGARG(bool isAlignAdjusted) + DEBUGARG(insGroup* containingIG) + DEBUGARG(insGroup* loopHeadPredIG)); void emitLoopAlign(unsigned paddingBytes, bool isFirstAlign DEBUG_ARG(bool isPlacedBehindJmp)); void emitLongLoopAlign(unsigned alignmentBoundary DEBUG_ARG(bool isPlacedBehindJmp)); diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 2056d8dabee674..1e3aed15c263aa 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -14802,7 +14802,7 @@ void emitter::emitDispInsHelp( // targetIG is only set for 1st of the series of align instruction if ((alignInstrId->idaLoopHeadPredIG != nullptr) && (alignInstrId->loopHeadIG() != nullptr)) { - printf(" for IG%02u", alignInstrId->loopHeadIG()->igNum); + printf(" for IG%02u", alignInstrId->loopHeadIG()->GetDisplayId()); } printf("]"); } diff --git a/src/coreclr/jit/emitloongarch64.cpp b/src/coreclr/jit/emitloongarch64.cpp index 9ec429118953eb..8dcb79222c28b1 100644 --- a/src/coreclr/jit/emitloongarch64.cpp +++ b/src/coreclr/jit/emitloongarch64.cpp @@ -2884,8 +2884,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->igNum <= jmp->idjIG->igNum || jmp->idjIG == prologIG || - emitNxtIGnum > unsigned(0xFFFF)); // igNum might overflow + assert(lastIG == nullptr || lastIG->IsBeforeOrEqual(jmp->idjIG) || jmp->idjIG == prologIG); lastIG = jmp->idjIG; #endif // DEBUG @@ -2914,8 +2913,8 @@ void emitter::emitJumpDistBind() #ifdef DEBUG if (EMITVERBOSE) { - printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->igNum, lstIG->igOffs, - lstIG->igOffs + adjIG); + printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->GetDisplayId(), + lstIG->igOffs, lstIG->igOffs + adjIG); } #endif // DEBUG lstIG->igOffs += adjIG; @@ -2999,7 +2998,7 @@ void emitter::emitJumpDistBind() srcEncodingOffs = srcInstrOffs + ssz; // Encoding offset of relative offset for small branch - if (jmpIG->igNum < tgtIG->igNum) + if (jmpIG->IsBefore(tgtIG)) { /* Forward jump */ @@ -3200,7 +3199,7 @@ void emitter::emitJumpDistBind() #ifdef DEBUG if (EMITVERBOSE) { - printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->igNum, lstIG->igOffs, + printf("Adjusted offset of " FMT_BB " from %04X to %04X\n", lstIG->GetDisplayId(), lstIG->igOffs, lstIG->igOffs + adjIG); } #endif // DEBUG diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index c4ddbfd26bc6d9..85edab0c65fbd9 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -14067,7 +14067,7 @@ void emitter::emitDispIns( // targetIG is only set for 1st of the series of align instruction if ((alignInstrId->idaLoopHeadPredIG != nullptr) && (alignInstrId->loopHeadIG() != nullptr)) { - printf(" for IG%02u", alignInstrId->loopHeadIG()->igNum); + printf(" for IG%02u", alignInstrId->loopHeadIG()->GetDisplayId()); } printf("]"); } @@ -20090,9 +20090,8 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) #endif #if FEATURE_LOOP_ALIGN - // Only compensate over-estimated instructions if emitCurIG is before - // the last IG that needs alignment. - if (emitCurIG->igNum <= emitLastAlignedIgNum) + // Only compensate over-estimated instructions if emitCurIG is before the last IG that needs alignment. + if ((emitLastAlignedIG != nullptr) && emitCurIG->IsBeforeOrEqual(emitLastAlignedIG)) { int diff = id->idCodeSize() - ((UNATIVE_OFFSET)(dst - *dp)); assert(diff >= 0); diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 2ab508a5fb53c8..ef59dbfe87afb2 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -41,7 +41,7 @@ int main(const int argc, const char *argv[]) const long timeout_mins = strtol(argv[1], nullptr, 10); int exit_code = run_timed_process(timeout_mins * 60000L, argc-2, &argv[2]); - printf("App Exit Code: %d\n", exit_code); + printf("Exit Code: %d\n", exit_code); return exit_code; } @@ -58,7 +58,6 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr STARTUPINFOA startup_info; PROCESS_INFORMATION proc_info; - unsigned long exit_code; ZeroMemory(&startup_info, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); @@ -72,7 +71,11 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr return error_code; } - WaitForSingleObject(proc_info.hProcess, timeout_ms); + if (WaitForSingleObject(proc_info.hProcess, timeout_ms) == WAIT_TIMEOUT) + { + printf("Child process took too long. Timed out...\n"); + } + DWORD exit_code; GetExitCodeProcess(proc_info.hProcess, &exit_code); CloseHandle(proc_info.hProcess);