Skip to content

Commit 27b79c7

Browse files
author
Aman Khalid
committed
Fix #70849: Print LARGEJMP instruction on ARM64
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 fb9be0a commit 27b79c7

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
@@ -12256,8 +12256,121 @@ void emitter::emitDispInsHex(instrDesc* id, BYTE* code, size_t sz)
1225612256
}
1225712257
}
1225812258

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

1228612399
if (pCode == NULL)
12400+
{
1228712401
sz = 0;
12402+
}
1228812403

1228912404
if (!isNew && !asmfm && sz)
1229012405
{
@@ -12394,31 +12509,43 @@ void emitter::emitDispIns(
1239412509
break;
1239512510

1239612511
case IF_BI_1A: // BI_1A ......iiiiiiiiii iiiiiiiiiiittttt Rt simm19:00
12512+
case IF_BI_1B: // BI_1B B.......bbbbbiii iiiiiiiiiiittttt Rt imm6, simm14:00
12513+
{
1239712514
assert(insOptsNone(id->idInsOpt()));
1239812515
emitDispReg(id->idReg1(), size, true);
12399-
if (id->idIsBound())
12516+
12517+
if (fmt == IF_BI_1B)
1240012518
{
12401-
emitPrintLabel(id->idAddr()->iiaIGlabel);
12519+
emitDispImm(emitGetInsSC(id), true);
1240212520
}
12403-
else
12521+
12522+
if (id->idAddr()->iiaHasInstrCount())
1240412523
{
12405-
printf("L_M%03u_" FMT_BB, emitComp->compMethodID, id->idAddr()->iiaBBlabel->bbNum);
12406-
}
12407-
break;
12524+
int instrCount = id->idAddr()->iiaGetInstrCount();
1240812525

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

1242312550
case IF_BR_1A: // BR_1A ................ ......nnnnn..... Rn
1242412551
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)