Skip to content

Commit c1d4494

Browse files
author
Aman Khalid
authored
Print LARGEJMP instruction on ARM64 (#71094)
emitter::emitDispIns supports printing LARGEJMP pseudo-instructions on ARM32, but not on ARM64. This method has been re-architected on ARM64 to support printing LARGEJMP instructions on ARM64.
1 parent c9007c8 commit c1d4494

File tree

4 files changed

+212
-61
lines changed

4 files changed

+212
-61
lines changed

src/coreclr/jit/emitarm.cpp

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7678,6 +7678,62 @@ void emitter::emitDispInsHelp(
76787678
printf("\n");
76797679
}
76807680

7681+
/*****************************************************************************
7682+
*
7683+
* Handles printing of LARGEJMP pseudo-instruction.
7684+
*/
7685+
7686+
void emitter::emitDispLargeJmp(
7687+
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* code, size_t sz, insGroup* ig)
7688+
{
7689+
// Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very
7690+
// difficult to find bug.
7691+
7692+
instrDescJmp idJmp;
7693+
instrDescJmp* pidJmp = &idJmp;
7694+
7695+
memset(&idJmp, 0, sizeof(idJmp));
7696+
7697+
pidJmp->idIns(emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(id->idIns())))); // reverse the
7698+
// conditional
7699+
// instruction
7700+
pidJmp->idInsFmt(IF_T1_K);
7701+
pidJmp->idInsSize(emitInsSize(IF_T1_K));
7702+
pidJmp->idjShort = 1;
7703+
pidJmp->idAddr()->iiaSetInstrCount(1);
7704+
pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field
7705+
7706+
size_t bcondSizeOrZero = (code == NULL) ? 0 : 2; // branch is 2 bytes
7707+
emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, code, bcondSizeOrZero,
7708+
NULL /* force display of pc-relative branch */);
7709+
7710+
code += bcondSizeOrZero;
7711+
offset += 2;
7712+
7713+
// Next, display the unconditional branch
7714+
7715+
// Reset the local instrDesc
7716+
memset(&idJmp, 0, sizeof(idJmp));
7717+
7718+
pidJmp->idIns(INS_b);
7719+
pidJmp->idInsFmt(IF_T2_J2);
7720+
pidJmp->idInsSize(emitInsSize(IF_T2_J2));
7721+
pidJmp->idjShort = 0;
7722+
if (id->idIsBound())
7723+
{
7724+
pidJmp->idSetIsBound();
7725+
pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel;
7726+
}
7727+
else
7728+
{
7729+
pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel;
7730+
}
7731+
pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field
7732+
7733+
size_t brSizeOrZero = (code == NULL) ? 0 : 4; // unconditional branch is 4 bytes
7734+
emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, code, brSizeOrZero, ig);
7735+
}
7736+
76817737
//--------------------------------------------------------------------
76827738
// emitDispIns: Dump the given instruction to jitstdout.
76837739
//
@@ -7714,53 +7770,7 @@ void emitter::emitDispIns(
77147770
//
77157771
// These instructions don't exist in the actual instruction stream, so we need to fake them
77167772
// up to display them.
7717-
//
7718-
// Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very
7719-
// difficult to find bug.
7720-
7721-
instrDescJmp idJmp;
7722-
instrDescJmp* pidJmp = &idJmp;
7723-
7724-
memset(&idJmp, 0, sizeof(idJmp));
7725-
7726-
pidJmp->idIns(emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(id->idIns())))); // reverse the
7727-
// conditional
7728-
// instruction
7729-
pidJmp->idInsFmt(IF_T1_K);
7730-
pidJmp->idInsSize(emitInsSize(IF_T1_K));
7731-
pidJmp->idjShort = 1;
7732-
pidJmp->idAddr()->iiaSetInstrCount(1);
7733-
pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field
7734-
7735-
size_t bcondSizeOrZero = (code == NULL) ? 0 : 2; // branch is 2 bytes
7736-
emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, code, bcondSizeOrZero,
7737-
NULL /* force display of pc-relative branch */);
7738-
7739-
code += bcondSizeOrZero;
7740-
offset += 2;
7741-
7742-
// Next, display the unconditional branch
7743-
7744-
// Reset the local instrDesc
7745-
memset(&idJmp, 0, sizeof(idJmp));
7746-
7747-
pidJmp->idIns(INS_b);
7748-
pidJmp->idInsFmt(IF_T2_J2);
7749-
pidJmp->idInsSize(emitInsSize(IF_T2_J2));
7750-
pidJmp->idjShort = 0;
7751-
if (id->idIsBound())
7752-
{
7753-
pidJmp->idSetIsBound();
7754-
pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel;
7755-
}
7756-
else
7757-
{
7758-
pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel;
7759-
}
7760-
pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // share the idDebugOnlyInfo() field
7761-
7762-
size_t brSizeOrZero = (code == NULL) ? 0 : 4; // unconditional branch is 4 bytes
7763-
emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, code, brSizeOrZero, ig);
7773+
emitDispLargeJmp(id, isNew, doffs, asmfm, offset, code, sz, ig);
77647774
}
77657775
else
77667776
{

src/coreclr/jit/emitarm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ void emitDispAddrRR(regNumber reg1, regNumber reg2, emitAttr attr);
4343
void emitDispAddrRRI(regNumber reg1, regNumber reg2, int imm, emitAttr attr);
4444
void emitDispAddrPUW(regNumber reg, int imm, insOpts opt, emitAttr attr);
4545
void emitDispGC(emitAttr attr);
46+
void emitDispLargeJmp(instrDesc* id,
47+
bool isNew,
48+
bool doffs,
49+
bool asmfm,
50+
unsigned offs = 0,
51+
BYTE* code = 0,
52+
size_t sz = 0,
53+
insGroup* ig = NULL);
4654

4755
void emitDispInsHelp(instrDesc* id,
4856
bool isNew,

src/coreclr/jit/emitarm64.cpp

Lines changed: 141 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12258,8 +12258,121 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz)
1225812258
}
1225912259
}
1226012260

12261+
/*****************************************************************************
12262+
*
12263+
* Handles printing of LARGEJMP pseudo-instruction.
12264+
*/
12265+
12266+
void emitter::emitDispLargeJmp(
12267+
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig)
12268+
{
12269+
// Note: don't touch the actual instrDesc. If we accidentally messed it up, it would create a very
12270+
// difficult-to-find bug.
12271+
12272+
instrDescJmp idJmp;
12273+
instrDescJmp* pidJmp = &idJmp;
12274+
12275+
memset(&idJmp, 0, sizeof(idJmp));
12276+
12277+
const instruction ins = id->idIns();
12278+
instruction reverseIns;
12279+
insFormat reverseFmt;
12280+
12281+
// Reverse the conditional instruction.
12282+
switch (ins)
12283+
{
12284+
case INS_cbz:
12285+
reverseIns = INS_cbnz;
12286+
reverseFmt = IF_BI_1A;
12287+
break;
12288+
case INS_cbnz:
12289+
reverseIns = INS_cbz;
12290+
reverseFmt = IF_BI_1A;
12291+
break;
12292+
case INS_tbz:
12293+
reverseIns = INS_tbnz;
12294+
reverseFmt = IF_BI_1B;
12295+
break;
12296+
case INS_tbnz:
12297+
reverseIns = INS_tbz;
12298+
reverseFmt = IF_BI_1B;
12299+
break;
12300+
default:
12301+
reverseIns = emitJumpKindToIns(emitReverseJumpKind(emitInsToJumpKind(ins)));
12302+
reverseFmt = IF_BI_0B;
12303+
}
12304+
12305+
pidJmp->idIns(reverseIns);
12306+
pidJmp->idInsFmt(reverseFmt);
12307+
pidJmp->idOpSize(id->idOpSize());
12308+
pidJmp->idAddr()->iiaSetInstrCount(1);
12309+
pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // Share the idDebugOnlyInfo() field.
12310+
12311+
const size_t bcondSizeOrZero = (pCode == NULL) ? 0 : 4; // Branch is 4 bytes.
12312+
emitDispInsHelp(pidJmp, false, doffs, asmfm, offset, pCode, bcondSizeOrZero,
12313+
NULL /* force display of pc-relative branch */);
12314+
12315+
pCode += bcondSizeOrZero;
12316+
offset += 4;
12317+
12318+
// Next, display the unconditional branch.
12319+
12320+
// Reset the local instrDesc.
12321+
memset(&idJmp, 0, sizeof(idJmp));
12322+
12323+
pidJmp->idIns(INS_b);
12324+
pidJmp->idInsFmt(IF_LARGEJMP);
12325+
12326+
if (id->idIsBound())
12327+
{
12328+
pidJmp->idSetIsBound();
12329+
pidJmp->idAddr()->iiaIGlabel = id->idAddr()->iiaIGlabel;
12330+
}
12331+
else
12332+
{
12333+
pidJmp->idAddr()->iiaBBlabel = id->idAddr()->iiaBBlabel;
12334+
}
12335+
12336+
pidJmp->idDebugOnlyInfo(id->idDebugOnlyInfo()); // Share the idDebugOnlyInfo() field.
12337+
12338+
const size_t brSizeOrZero = (pCode == NULL) ? 0 : 4; // Unconditional branch is 4 bytes.
12339+
emitDispInsHelp(pidJmp, isNew, doffs, asmfm, offset, pCode, brSizeOrZero, ig);
12340+
}
12341+
12342+
/*****************************************************************************
12343+
*
12344+
* Wrapper for emitter::emitDispInsHelp() that handles special large jump
12345+
* pseudo-instruction.
12346+
*/
12347+
12348+
void emitter::emitDispIns(
12349+
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig)
12350+
{
12351+
// Special case: IF_LARGEJMP
12352+
12353+
if ((id->idInsFmt() == IF_LARGEJMP) && id->idIsBound())
12354+
{
12355+
// This is a pseudo-instruction format representing a large conditional branch. See the comment
12356+
// in emitter::emitOutputLJ() for the full description.
12357+
//
12358+
// For this pseudo-instruction, we will actually generate:
12359+
//
12360+
// b<!cond> L_not // 4 bytes. Note that we reverse the condition.
12361+
// b L_target // 4 bytes.
12362+
// L_not:
12363+
//
12364+
// These instructions don't exist in the actual instruction stream, so we need to fake them
12365+
// up to display them.
12366+
emitDispLargeJmp(id, isNew, doffs, asmfm, offset, pCode, sz, ig);
12367+
}
12368+
else
12369+
{
12370+
emitDispInsHelp(id, isNew, doffs, asmfm, offset, pCode, sz, ig);
12371+
}
12372+
}
12373+
1226112374
//--------------------------------------------------------------------
12262-
// emitDispIns: Dump the given instruction to jitstdout.
12375+
// emitDispInsHelp: Dump the given instruction to jitstdout.
1226312376
//
1226412377
// Arguments:
1226512378
// id - The instruction
@@ -12274,7 +12387,7 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz)
1227412387
// sz - The size of the instruction, used to display the encoded bytes.
1227512388
// ig - The instruction group containing the instruction.
1227612389
//
12277-
void emitter::emitDispIns(
12390+
void emitter::emitDispInsHelp(
1227812391
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig)
1227912392
{
1228012393
if (EMITVERBOSE)
@@ -12286,7 +12399,9 @@ void emitter::emitDispIns(
1228612399
}
1228712400

1228812401
if (pCode == NULL)
12402+
{
1228912403
sz = 0;
12404+
}
1229012405

1229112406
if (!isNew && !asmfm && sz)
1229212407
{
@@ -12396,31 +12511,43 @@ void emitter::emitDispIns(
1239612511
break;
1239712512

1239812513
case IF_BI_1A: // BI_1A ......iiiiiiiiii iiiiiiiiiiittttt Rt simm19:00
12514+
case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00
12515+
{
1239912516
assert(insOptsNone(id->idInsOpt()));
1240012517
emitDispReg(id->idReg1(), size, true);
12401-
if (id->idIsBound())
12518+
12519+
if (fmt == IF_BI_1B)
1240212520
{
12403-
emitPrintLabel(id->idAddr()->iiaIGlabel);
12521+
emitDispImm(emitGetInsSC(id), true);
1240412522
}
12405-
else
12523+
12524+
if (id->idAddr()->iiaHasInstrCount())
1240612525
{
12407-
printf("L_M%03u_" FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum);
12408-
}
12409-
break;
12526+
int instrCount = id->idAddr()->iiaGetInstrCount();
1241012527

12411-
case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00
12412-
assert(insOptsNone(id->idInsOpt()));
12413-
emitDispReg(id->idReg1(), size, true);
12414-
emitDispImm(emitGetInsSC(id), true);
12415-
if (id->idIsBound())
12528+
if (ig == nullptr)
12529+
{
12530+
printf("pc%s%d instructions", (instrCount >= 0) ? "+" : "", instrCount);
12531+
}
12532+
else
12533+
{
12534+
unsigned insNum = emitFindInsNum(ig, id);
12535+
UNATIVE_OFFSET srcOffs = ig->igOffs + emitFindOffset(ig, insNum + 1);
12536+
UNATIVE_OFFSET dstOffs = ig->igOffs + emitFindOffset(ig, insNum + 1 + instrCount);
12537+
ssize_t relOffs = (ssize_t)(emitOffsetToPtr(dstOffs) - emitOffsetToPtr(srcOffs));
12538+
printf("pc%s%d (%d instructions)", (relOffs >= 0) ? "+" : "", relOffs, instrCount);
12539+
}
12540+
}
12541+
else if (id->idIsBound())
1241612542
{
1241712543
emitPrintLabel(id->idAddr()->iiaIGlabel);
1241812544
}
1241912545
else
1242012546
{
1242112547
printf("L_M%03u_" FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum);
1242212548
}
12423-
break;
12549+
}
12550+
break;
1242412551

1242512552
case IF_BR_1A: // BR_1A ................ ......nnnnn..... Rn
1242612553
assert(insOptsNone(id->idInsOpt()));

src/coreclr/jit/emitarm64.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ static bool strictArmAsm;
2323

2424
const char* emitVectorRegName(regNumber reg);
2525

26+
void emitDispInsHelp(
27+
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig);
28+
void emitDispLargeJmp(
29+
instrDesc* id, bool isNew, bool doffs, bool asmfm, unsigned offset, BYTE* pCode, size_t sz, insGroup* ig);
2630
void emitDispInst(instruction ins);
2731
void emitDispImm(ssize_t imm, bool addComma, bool alwaysHex = false);
2832
void emitDispFloatZero();
@@ -873,6 +877,8 @@ BYTE* emitOutputShortBranch(BYTE* dst, instruction ins, insFormat fmt, ssize_t d
873877
BYTE* emitOutputShortAddress(BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, regNumber reg);
874878
BYTE* emitOutputShortConstant(
875879
BYTE* dst, instruction ins, insFormat fmt, ssize_t distVal, regNumber reg, emitAttr opSize);
880+
BYTE* emitOutputVectorConstant(
881+
BYTE* dst, ssize_t distVal, regNumber dstReg, regNumber addrReg, emitAttr opSize, emitAttr elemSize);
876882

877883
/*****************************************************************************
878884
*

0 commit comments

Comments
 (0)