diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index ccf3ddff357099..5e172a0914a6de 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -7678,6 +7678,62 @@ void emitter::emitDispInsHelp( printf("\n"); } +/***************************************************************************** + * + * Handles printing of LARGEJMP pseudo-instruction. + */ + +void emitter::emitDispLargeJmp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* code, size_t sz, insGroup* ig) +{ + // Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very + // difficult to find bug. + + instrDescJmp idJmp; + instrDescJmp* pidJmp = &idJmp; + + memset(&idJmp, 0, sizeof(idJmp)); + + pidJmp->idIns(emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(id->idIns())))); // reverse the + // conditional + // instruction + pidJmp->idInsFmt(IF_T1_K); + pidJmp->idInsSize(emitInsSize(IF_T1_K)); + pidJmp->idjShort = 1; + pidJmp->idAddr()->iiaSetInstrCount(1); + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field + + size_t bcondSizeOrZero = (code == NULL) ? 0 : 2; // branch is 2 bytes + emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, code, bcondSizeOrZero, + NULL /* force display of pc-relative branch */); + + code += bcondSizeOrZero; + offset += 2; + + // Next, display the unconditional branch + + // Reset the local instrDesc + memset(&idJmp, 0, sizeof(idJmp)); + + pidJmp->idIns(INS_b); + pidJmp->idInsFmt(IF_T2_J2); + pidJmp->idInsSize(emitInsSize(IF_T2_J2)); + pidJmp->idjShort = 0; + if (id->idIsBound()) + { + pidJmp->idSetIsBound(); + pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel; + } + else + { + pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel; + } + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field + + size_t brSizeOrZero = (code == NULL) ? 0 : 4; // unconditional branch is 4 bytes + emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, code, brSizeOrZero, ig); +} + //-------------------------------------------------------------------- // emitDispIns: Dump the given instruction to jitstdout. // @@ -7714,53 +7770,7 @@ void emitter::emitDispIns( // // These instructions don't exist in the actual instruction stream, so we need to fake them // up to display them. - // - // Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very - // difficult to find bug. - - instrDescJmp idJmp; - instrDescJmp* pidJmp = &idJmp; - - memset(&idJmp, 0, sizeof(idJmp)); - - pidJmp->idIns(emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(id->idIns())))); // reverse the - // conditional - // instruction - pidJmp->idInsFmt(IF_T1_K); - pidJmp->idInsSize(emitInsSize(IF_T1_K)); - pidJmp->idjShort = 1; - pidJmp->idAddr()->iiaSetInstrCount(1); - pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field - - size_t bcondSizeOrZero = (code == NULL) ? 0 : 2; // branch is 2 bytes - emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, code, bcondSizeOrZero, - NULL /* force display of pc-relative branch */); - - code += bcondSizeOrZero; - offset += 2; - - // Next, display the unconditional branch - - // Reset the local instrDesc - memset(&idJmp, 0, sizeof(idJmp)); - - pidJmp->idIns(INS_b); - pidJmp->idInsFmt(IF_T2_J2); - pidJmp->idInsSize(emitInsSize(IF_T2_J2)); - pidJmp->idjShort = 0; - if (id->idIsBound()) - { - pidJmp->idSetIsBound(); - pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel; - } - else - { - pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel; - } - pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field - - size_t brSizeOrZero = (code == NULL) ? 0 : 4; // unconditional branch is 4 bytes - emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, code, brSizeOrZero, ig); + emitDispLargeJmp(id, isNew, doffs, asmfm, offset, code, sz, ig); } else { diff --git a/src/coreclr/jit/emitarm.h b/src/coreclr/jit/emitarm.h index 09133a1d88f02d..c40c5fb85f9c51 100644 --- a/src/coreclr/jit/emitarm.h +++ b/src/coreclr/jit/emitarm.h @@ -43,6 +43,14 @@ void emitDispAddrRR(regNumber reg1, regNumber reg2, emitAttr attr); void emitDispAddrRRI(regNumber reg1, regNumber reg2, int imm, emitAttr attr); void emitDispAddrPUW(regNumber reg, int imm, insOpts opt, emitAttr attr); void emitDispGC(emitAttr attr); +void emitDispLargeJmp(instrDesc* id, + bool isNew, + bool doffs, + bool asmfm, + unsigned offs = 0, + BYTE* code = 0, + size_t sz = 0, + insGroup* ig = NULL); void emitDispInsHelp(instrDesc* id, bool isNew, diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 3940f89302911a..5a69719f9a9526 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -12256,8 +12256,121 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) } } +/***************************************************************************** + * + * Handles printing of LARGEJMP pseudo-instruction. + */ + +void emitter::emitDispLargeJmp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig) +{ + // Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very + // difficult-to-find bug. + + instrDescJmp idJmp; + instrDescJmp* pidJmp = &idJmp; + + memset(&idJmp, 0, sizeof(idJmp)); + + const instruction ins = id->idIns(); + instruction reverseIns; + insFormat reverseFmt; + + // Reverse the conditional instruction. + switch (ins) + { + case INS_cbz: + reverseIns = INS_cbnz; + reverseFmt = IF_BI_1A; + break; + case INS_cbnz: + reverseIns = INS_cbz; + reverseFmt = IF_BI_1A; + break; + case INS_tbz: + reverseIns = INS_tbnz; + reverseFmt = IF_BI_1B; + break; + case INS_tbnz: + reverseIns = INS_tbz; + reverseFmt = IF_BI_1B; + break; + default: + reverseIns = emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(ins))); + reverseFmt = IF_BI_0B; + } + + pidJmp->idIns(reverseIns); + pidJmp->idInsFmt(reverseFmt); + pidJmp->idOpSize(id->idOpSize()); + pidJmp->idAddr()->iiaSetInstrCount(1); + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // Share the idDebugOnlyInfo() field. + + const size_t bcondSizeOrZero = (pCode == NULL) ? 0 : 4; // Branch is 4 bytes. + emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, pCode, bcondSizeOrZero, + NULL /* force display of pc-relative branch */); + + pCode += bcondSizeOrZero; + offset += 4; + + // Next, display the unconditional branch. + + // Reset the local instrDesc. + memset(&idJmp, 0, sizeof(idJmp)); + + pidJmp->idIns(INS_b); + pidJmp->idInsFmt(IF_LARGEJMP); + + if (id->idIsBound()) + { + pidJmp->idSetIsBound(); + pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel; + } + else + { + pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel; + } + + pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // Share the idDebugOnlyInfo() field. + + const size_t brSizeOrZero = (pCode == NULL) ? 0 : 4; // Unconditional branch is 4 bytes. + emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, pCode, brSizeOrZero, ig); +} + +/***************************************************************************** + * + * Wrapper for emitter::emitDispInsHelp() that handles special large jump + * pseudo-instruction. + */ + +void emitter::emitDispIns( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig) +{ + // Special case: IF_LARGEJMP + + if ((id->idInsFmt() == IF_LARGEJMP) && id->idIsBound()) + { + // This is a pseudo-instruction format representing a large conditional branch. See the comment + // in emitter::emitOutputLJ() for the full description. + // + // For this pseudo-instruction, we will actually generate: + // + // b L_not // 4 bytes. Note that we reverse the condition. + // b L_target // 4 bytes. + // L_not: + // + // These instructions don't exist in the actual instruction stream, so we need to fake them + // up to display them. + emitDispLargeJmp(id, isNew, doffs, asmfm, offset, pCode, sz, ig); + } + else + { + emitDispInsHelp(id, isNew, doffs, asmfm, offset, pCode, sz, ig); + } +} + //-------------------------------------------------------------------- -// emitDispIns: Dump the given instruction to jitstdout. +// emitDispInsHelp: Dump the given instruction to jitstdout. // // Arguments: // id - The instruction @@ -12272,7 +12385,7 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz) // sz - The size of the instruction, used to display the encoded bytes. // ig - The instruction group containing the instruction. // -void emitter::emitDispIns( +void emitter::emitDispInsHelp( instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig) { if (EMITVERBOSE) @@ -12284,7 +12397,9 @@ void emitter::emitDispIns( } if (pCode == NULL) + { sz = 0; + } if (!isNew && !asmfm && sz) { @@ -12394,23 +12509,34 @@ void emitter::emitDispIns( break; case IF_BI_1A: // BI_1A ......iiiiiiiiii iiiiiiiiiiittttt Rt simm19:00 + case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00 + { assert(insOptsNone(id->idInsOpt())); emitDispReg(id->idReg1(), size, true); - if (id->idIsBound()) + + if (fmt == IF_BI_1B) { - emitPrintLabel(id->idAddr()->iiaIGlabel); + emitDispImm(emitGetInsSC(id), true); } - else + + if (id->idAddr()->iiaHasInstrCount()) { - printf("L_M%03u_" FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum); - } - break; + int instrCount = id->idAddr()->iiaGetInstrCount(); - case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00 - assert(insOptsNone(id->idInsOpt())); - emitDispReg(id->idReg1(), size, true); - emitDispImm(emitGetInsSC(id), true); - if (id->idIsBound()) + if (ig == nullptr) + { + printf("pc%s%d instructions", (instrCount >= 0) ? "+" : "", instrCount); + } + else + { + unsigned insNum = emitFindInsNum(ig, id); + UNATIVE_OFFSET srcOffs = ig->igOffs + emitFindOffset(ig, insNum + 1); + UNATIVE_OFFSET dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount); + ssize_t relOffs = (ssize_t)(emitOffsetToPtr(dstOffs) - emitOffsetToPtr(srcOffs)); + printf("pc%s%d (%d instructions)", (relOffs >= 0) ? "+" : "", relOffs, instrCount); + } + } + else if (id->idIsBound()) { emitPrintLabel(id->idAddr()->iiaIGlabel); } @@ -12418,7 +12544,8 @@ void emitter::emitDispIns( { printf("L_M%03u_" FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum); } - break; + } + break; case IF_BR_1A: // BR_1A ................ ......nnnnn..... Rn assert(insOptsNone(id->idInsOpt())); diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h index c43f85292a4dc0..4068fe3c254085 100644 --- a/src/coreclr/jit/emitarm64.h +++ b/src/coreclr/jit/emitarm64.h @@ -23,6 +23,10 @@ static bool strictArmAsm; const char* emitVectorRegName(regNumber reg); +void emitDispInsHelp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig); +void emitDispLargeJmp( + instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig); void emitDispInst(instruction ins); void emitDispImm(ssize_t imm, bool addComma, bool alwaysHex = false); void emitDispFloatZero(); @@ -873,6 +877,8 @@ BYTE* emitOutputShortBranch(BYTE* dst, instruction ins, insFormat fmt, ssize_t d BYTE* emitOutputShortAddress(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, regNumber reg); BYTE* emitOutputShortConstant( BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, regNumber reg, emitAttr opSize); +BYTE* emitOutputVectorConstant( + BYTE* dst, ssize_t distVal, regNumber dstReg, regNumber addrReg, emitAttr opSize, emitAttr elemSize); /***************************************************************************** *