Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit a0c6144

Browse files
committed
ARM64: Switch Expansion Using Jump Table
Fixes #3332 To validate various addressing in #4896, I just enable this. Previously, we only allow a load operation to JIT data (`ldr` or `IF_LARGELDC`). For switch expansion, jump table is also recorded into JIT data. In this case, we only get the address of jump table head, and load the right entry after computing offset. So, basically `adr` or `IF_LARGEADR` is used to not only load label within code but also refer to the location of JIT data. The typical code sequence for switch expansion is like this: ``` adr x8, [@rwd00] // load address of jump table head ldr w8, [x8, x0, LSL #2] // load jump entry from table addr + x0 * 4 adr x9, [G_M56320_IG02] // load address of current baisc block add x8, x8, x9 // Add them to compute the final target br x8 // Indirectly jump to the target ```
1 parent 3e98666 commit a0c6144

File tree

5 files changed

+136
-120
lines changed

5 files changed

+136
-120
lines changed

src/jit/codegenarm64.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4048,29 +4048,28 @@ void CodeGen::genCodeForCpBlk(GenTreeCpBlk* cpBlkNode)
40484048
void
40494049
CodeGen::genTableBasedSwitch(GenTree* treeNode)
40504050
{
4051-
NYI("Emit table based switch");
40524051
genConsumeOperands(treeNode->AsOp());
40534052
regNumber idxReg = treeNode->gtOp.gtOp1->gtRegNum;
40544053
regNumber baseReg = treeNode->gtOp.gtOp2->gtRegNum;
40554054

40564055
regNumber tmpReg = genRegNumFromMask(treeNode->gtRsvdRegs);
40574056

40584057
// load the ip-relative offset (which is relative to start of fgFirstBB)
4059-
//getEmitter()->emitIns_R_ARX(INS_mov, EA_4BYTE, baseReg, baseReg, idxReg, 4, 0);
4058+
getEmitter()->emitIns_R_R_R(INS_ldr, EA_4BYTE, baseReg, baseReg, idxReg, INS_OPTS_LSL);
40604059

40614060
// add it to the absolute address of fgFirstBB
40624061
compiler->fgFirstBB->bbFlags |= BBF_JMP_TARGET;
4063-
//getEmitter()->emitIns_R_L(INS_lea, EA_PTRSIZE, compiler->fgFirstBB, tmpReg);
4064-
//getEmitter()->emitIns_R_R(INS_add, EA_PTRSIZE, baseReg, tmpReg);
4062+
getEmitter()->emitIns_R_L(INS_adr, EA_PTRSIZE, compiler->fgFirstBB, tmpReg);
4063+
getEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, baseReg, baseReg, tmpReg);
4064+
40654065
// jmp baseReg
4066-
// getEmitter()->emitIns_R(INS_i_jmp, emitTypeSize(TYP_I_IMPL), baseReg);
4066+
getEmitter()->emitIns_R(INS_br, emitTypeSize(TYP_I_IMPL), baseReg);
40674067
}
40684068

40694069
// emits the table and an instruction to get the address of the first element
40704070
void
40714071
CodeGen::genJumpTable(GenTree* treeNode)
40724072
{
4073-
NYI("Emit Jump table");
40744073
noway_assert(compiler->compCurBB->bbJumpKind == BBJ_SWITCH);
40754074
assert(treeNode->OperGet() == GT_JMPTABLE);
40764075

@@ -4100,7 +4099,7 @@ CodeGen::genJumpTable(GenTree* treeNode)
41004099
// Access to inline data is 'abstracted' by a special type of static member
41014100
// (produced by eeFindJitDataOffs) which the emitter recognizes as being a reference
41024101
// to constant data, not a real static field.
4103-
getEmitter()->emitIns_R_C(INS_lea,
4102+
getEmitter()->emitIns_R_C(INS_adr,
41044103
emitTypeSize(TYP_I_IMPL),
41054104
treeNode->gtRegNum,
41064105
REG_NA,

src/jit/emit.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3804,10 +3804,9 @@ void emitter::emitJumpDistBind()
38043804
#if defined(_TARGET_ARM64_)
38053805
// JIT code and data will be allocated together for arm64 so the relative offset to JIT data is known.
38063806
// In case such offset can be encodeable for `ldr` (+-1MB), shorten it.
3807-
if (emitIsLoadConstant(jmp))
3807+
if (jmp->idAddr()->iiaIsJitDataOffset())
38083808
{
38093809
// Reference to JIT data
3810-
assert(jmp->idAddr()->iiaIsJitDataOffset());
38113810
assert(jmp->idIsBound());
38123811
UNATIVE_OFFSET srcOffs = jmpIG->igOffs + jmp->idjOffs;
38133812

@@ -4289,6 +4288,14 @@ void emitter::emitCheckFuncletBranch(instrDesc * jmp, insGroup *
42894288
}
42904289
#endif // _TARGET_ARMARCH_
42914290

4291+
#ifdef _TARGET_ARM64_
4292+
// No interest if it's not jmp.
4293+
if (emitIsLoadLabel(jmp) || emitIsLoadConstant(jmp))
4294+
{
4295+
return;
4296+
}
4297+
#endif // _TARGET_ARM64_
4298+
42924299
insGroup * tgtIG = jmp->idAddr()->iiaIGlabel;
42934300
assert(tgtIG);
42944301
if (tgtIG->igFuncIdx != jmpIG->igFuncIdx)

0 commit comments

Comments
 (0)