Skip to content

Commit 20f544d

Browse files
authored
[RISCV][GISel] Instruction selection for G_JUMP_TABLE and G_BRJT. (#71987)
1 parent 8ad4df8 commit 20f544d

File tree

7 files changed

+1257
-0
lines changed

7 files changed

+1257
-0
lines changed

llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
2121
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
2222
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23+
#include "llvm/CodeGen/MachineJumpTableInfo.h"
2324
#include "llvm/IR/IntrinsicsRISCV.h"
2425
#include "llvm/Support/Debug.h"
2526

@@ -64,6 +65,8 @@ class RISCVInstructionSelector : public InstructionSelector {
6465
bool materializeImm(Register Reg, int64_t Imm, MachineIRBuilder &MIB) const;
6566
bool selectGlobalValue(MachineInstr &MI, MachineIRBuilder &MIB,
6667
MachineRegisterInfo &MRI) const;
68+
bool selectJumpTable(MachineInstr &MI, MachineIRBuilder &MIB,
69+
MachineRegisterInfo &MRI) const;
6770
bool selectSExtInreg(MachineInstr &MI, MachineIRBuilder &MIB) const;
6871
bool selectSelect(MachineInstr &MI, MachineIRBuilder &MIB,
6972
MachineRegisterInfo &MRI) const;
@@ -483,6 +486,8 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
483486
}
484487
case TargetOpcode::G_GLOBAL_VALUE:
485488
return selectGlobalValue(MI, MIB, MRI);
489+
case TargetOpcode::G_JUMP_TABLE:
490+
return selectJumpTable(MI, MIB, MRI);
486491
case TargetOpcode::G_BRCOND: {
487492
Register LHS, RHS;
488493
RISCVCC::CondCode CC;
@@ -493,6 +498,58 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
493498
MI.eraseFromParent();
494499
return constrainSelectedInstRegOperands(*Bcc, TII, TRI, RBI);
495500
}
501+
case TargetOpcode::G_BRJT: {
502+
// FIXME: Move to legalization?
503+
const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
504+
unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout());
505+
assert((EntrySize == 4 || (Subtarget->is64Bit() && EntrySize == 8)) &&
506+
"Unsupported jump-table entry size");
507+
assert(
508+
(MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 ||
509+
MJTI->getEntryKind() == MachineJumpTableInfo::EK_Custom32 ||
510+
MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress) &&
511+
"Unexpected jump-table entry kind");
512+
513+
auto SLL =
514+
MIB.buildInstr(RISCV::SLLI, {&RISCV::GPRRegClass}, {MI.getOperand(2)})
515+
.addImm(Log2_32(EntrySize));
516+
if (!SLL.constrainAllUses(TII, TRI, RBI))
517+
return false;
518+
519+
// TODO: Use SHXADD. Moving to legalization would fix this automatically.
520+
auto ADD = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass},
521+
{MI.getOperand(0), SLL.getReg(0)});
522+
if (!ADD.constrainAllUses(TII, TRI, RBI))
523+
return false;
524+
525+
unsigned LdOpc = EntrySize == 8 ? RISCV::LD : RISCV::LW;
526+
auto Dest =
527+
MIB.buildInstr(LdOpc, {&RISCV::GPRRegClass}, {ADD.getReg(0)})
528+
.addImm(0)
529+
.addMemOperand(MF.getMachineMemOperand(
530+
MachinePointerInfo::getJumpTable(MF), MachineMemOperand::MOLoad,
531+
EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout()))));
532+
if (!Dest.constrainAllUses(TII, TRI, RBI))
533+
return false;
534+
535+
// If the Kind is EK_LabelDifference32, the table stores an offset from
536+
// the location of the table. Add the table address to get an absolute
537+
// address.
538+
if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32) {
539+
Dest = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass},
540+
{Dest.getReg(0), MI.getOperand(0)});
541+
if (!Dest.constrainAllUses(TII, TRI, RBI))
542+
return false;
543+
}
544+
545+
auto Branch =
546+
MIB.buildInstr(RISCV::PseudoBRIND, {}, {Dest.getReg(0)}).addImm(0);
547+
if (!Branch.constrainAllUses(TII, TRI, RBI))
548+
return false;
549+
550+
MI.eraseFromParent();
551+
return true;
552+
}
496553
case TargetOpcode::G_SEXT_INREG:
497554
return selectSExtInreg(MI, MIB);
498555
case TargetOpcode::G_FRAME_INDEX: {
@@ -784,6 +841,97 @@ bool RISCVInstructionSelector::selectGlobalValue(
784841
return false;
785842
}
786843

844+
// FIXME: This is very similar to selectGlobalValue. Merge somehow?
845+
bool RISCVInstructionSelector::selectJumpTable(MachineInstr &MI,
846+
MachineIRBuilder &MIB,
847+
MachineRegisterInfo &MRI) const {
848+
assert(MI.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
849+
"Expected G_JUMP_TABLE");
850+
851+
int Idx = MI.getOperand(1).getIndex();
852+
853+
Register DefReg = MI.getOperand(0).getReg();
854+
const LLT DefTy = MRI.getType(DefReg);
855+
MachineInstr *Result = nullptr;
856+
857+
// When HWASAN is used and tagging of global variables is enabled
858+
// they should be accessed via the GOT, since the tagged address of a global
859+
// is incompatible with existing code models. This also applies to non-pic
860+
// mode.
861+
if (TM.isPositionIndependent() || Subtarget->allowTaggedGlobals()) {
862+
if (!Subtarget->allowTaggedGlobals()) {
863+
// Use PC-relative addressing to access the symbol. This generates the
864+
// pattern (PseudoLLA sym), which expands to (addi (auipc %pcrel_hi(sym))
865+
// %pcrel_lo(auipc)).
866+
Result =
867+
MIB.buildInstr(RISCV::PseudoLLA, {DefReg}, {}).addJumpTableIndex(Idx);
868+
} else {
869+
// Use PC-relative addressing to access the GOT for this symbol, then
870+
// load the address from the GOT. This generates the pattern (PseudoLGA
871+
// sym), which expands to (ld (addi (auipc %got_pcrel_hi(sym))
872+
// %pcrel_lo(auipc))).
873+
MachineFunction &MF = *MI.getParent()->getParent();
874+
MachineMemOperand *MemOp = MF.getMachineMemOperand(
875+
MachinePointerInfo::getGOT(MF),
876+
MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
877+
MachineMemOperand::MOInvariant,
878+
DefTy, Align(DefTy.getSizeInBits() / 8));
879+
880+
Result = MIB.buildInstr(RISCV::PseudoLGA, {DefReg}, {})
881+
.addJumpTableIndex(Idx)
882+
.addMemOperand(MemOp);
883+
}
884+
885+
if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
886+
return false;
887+
888+
MI.eraseFromParent();
889+
return true;
890+
}
891+
892+
switch (TM.getCodeModel()) {
893+
default: {
894+
reportGISelFailure(const_cast<MachineFunction &>(*MF), *TPC, *MORE,
895+
getName(), "Unsupported code model for lowering", MI);
896+
return false;
897+
}
898+
case CodeModel::Small: {
899+
// Must lie within a single 2 GiB address range and must lie between
900+
// absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi
901+
// (lui %hi(sym)) %lo(sym)).
902+
Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);
903+
MachineInstr *AddrHi = MIB.buildInstr(RISCV::LUI, {AddrHiDest}, {})
904+
.addJumpTableIndex(Idx, RISCVII::MO_HI);
905+
906+
if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))
907+
return false;
908+
909+
Result = MIB.buildInstr(RISCV::ADDI, {DefReg}, {AddrHiDest})
910+
.addJumpTableIndex(Idx, RISCVII::MO_LO);
911+
912+
if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
913+
return false;
914+
915+
MI.eraseFromParent();
916+
return true;
917+
}
918+
case CodeModel::Medium: {
919+
// Generate a sequence for accessing addresses within any 2GiB range
920+
// within the address space. This generates the pattern (PseudoLLA sym),
921+
// which expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
922+
Result =
923+
MIB.buildInstr(RISCV::PseudoLLA, {DefReg}, {}).addJumpTableIndex(Idx);
924+
925+
if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
926+
return false;
927+
928+
MI.eraseFromParent();
929+
return true;
930+
}
931+
}
932+
return false;
933+
}
934+
787935
bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI,
788936
MachineIRBuilder &MIB) const {
789937
if (!STI.isRV64())
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=riscv64 -run-pass=instruction-select %s -o - \
3+
# RUN: -code-model=medium | FileCheck %s
4+
5+
--- |
6+
define i32 @jt_test(i32 signext %in) {
7+
entry:
8+
%0 = sext i32 %in to i64
9+
switch i64 %0, label %default [
10+
i64 1, label %bb1
11+
i64 2, label %bb2
12+
i64 3, label %bb3
13+
i64 4, label %bb4
14+
i64 5, label %bb5
15+
i64 6, label %bb6
16+
]
17+
18+
bb1: ; preds = %entry
19+
ret i32 4
20+
21+
bb2: ; preds = %entry
22+
ret i32 3
23+
24+
bb3: ; preds = %entry
25+
ret i32 2
26+
27+
bb4: ; preds = %entry
28+
ret i32 1
29+
30+
bb5: ; preds = %entry
31+
ret i32 100
32+
33+
bb6: ; preds = %entry
34+
ret i32 200
35+
36+
default: ; preds = %entry
37+
ret i32 1000
38+
}
39+
40+
...
41+
---
42+
name: jt_test
43+
legalized: true
44+
regBankSelected: true
45+
tracksRegLiveness: true
46+
jumpTable:
47+
kind: block-address
48+
entries:
49+
- id: 0
50+
blocks: [ '%bb.2', '%bb.3', '%bb.4', '%bb.5', '%bb.6', '%bb.7' ]
51+
body: |
52+
; CHECK-LABEL: name: jt_test
53+
; CHECK: bb.0.entry:
54+
; CHECK-NEXT: successors: %bb.8(0x40000000), %bb.1(0x40000000)
55+
; CHECK-NEXT: liveins: $x10
56+
; CHECK-NEXT: {{ $}}
57+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
58+
; CHECK-NEXT: [[ADDI:%[0-9]+]]:gpr = ADDI $x0, 5
59+
; CHECK-NEXT: [[ADDIW:%[0-9]+]]:gpr = ADDIW [[COPY]], 0
60+
; CHECK-NEXT: [[ADDI1:%[0-9]+]]:gpr = ADDI [[ADDIW]], -1
61+
; CHECK-NEXT: BLTU [[ADDI]], [[ADDI1]], %bb.8
62+
; CHECK-NEXT: {{ $}}
63+
; CHECK-NEXT: bb.1.entry:
64+
; CHECK-NEXT: successors: %bb.2(0x15555555), %bb.3(0x15555555), %bb.4(0x15555555), %bb.5(0x15555555), %bb.6(0x15555555), %bb.7(0x15555555)
65+
; CHECK-NEXT: {{ $}}
66+
; CHECK-NEXT: [[PseudoLLA:%[0-9]+]]:gpr = PseudoLLA %jump-table.0
67+
; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[ADDI1]], 3
68+
; CHECK-NEXT: [[ADD:%[0-9]+]]:gpr = ADD [[PseudoLLA]], [[SLLI]]
69+
; CHECK-NEXT: [[LD:%[0-9]+]]:gprjalr = LD [[ADD]], 0 :: (load (s64) from jump-table)
70+
; CHECK-NEXT: PseudoBRIND [[LD]], 0
71+
; CHECK-NEXT: {{ $}}
72+
; CHECK-NEXT: bb.2.bb1:
73+
; CHECK-NEXT: [[ADDI2:%[0-9]+]]:gpr = ADDI $x0, 4
74+
; CHECK-NEXT: $x10 = COPY [[ADDI2]]
75+
; CHECK-NEXT: PseudoRET implicit $x10
76+
; CHECK-NEXT: {{ $}}
77+
; CHECK-NEXT: bb.3.bb2:
78+
; CHECK-NEXT: [[ADDI3:%[0-9]+]]:gpr = ADDI $x0, 3
79+
; CHECK-NEXT: $x10 = COPY [[ADDI3]]
80+
; CHECK-NEXT: PseudoRET implicit $x10
81+
; CHECK-NEXT: {{ $}}
82+
; CHECK-NEXT: bb.4.bb3:
83+
; CHECK-NEXT: [[ADDI4:%[0-9]+]]:gpr = ADDI $x0, 2
84+
; CHECK-NEXT: $x10 = COPY [[ADDI4]]
85+
; CHECK-NEXT: PseudoRET implicit $x10
86+
; CHECK-NEXT: {{ $}}
87+
; CHECK-NEXT: bb.5.bb4:
88+
; CHECK-NEXT: [[ADDI5:%[0-9]+]]:gpr = ADDI $x0, 1
89+
; CHECK-NEXT: $x10 = COPY [[ADDI5]]
90+
; CHECK-NEXT: PseudoRET implicit $x10
91+
; CHECK-NEXT: {{ $}}
92+
; CHECK-NEXT: bb.6.bb5:
93+
; CHECK-NEXT: [[ADDI6:%[0-9]+]]:gpr = ADDI $x0, 100
94+
; CHECK-NEXT: $x10 = COPY [[ADDI6]]
95+
; CHECK-NEXT: PseudoRET implicit $x10
96+
; CHECK-NEXT: {{ $}}
97+
; CHECK-NEXT: bb.7.bb6:
98+
; CHECK-NEXT: [[ADDI7:%[0-9]+]]:gpr = ADDI $x0, 200
99+
; CHECK-NEXT: $x10 = COPY [[ADDI7]]
100+
; CHECK-NEXT: PseudoRET implicit $x10
101+
; CHECK-NEXT: {{ $}}
102+
; CHECK-NEXT: bb.8.default:
103+
; CHECK-NEXT: [[ADDI8:%[0-9]+]]:gpr = ADDI $x0, 1000
104+
; CHECK-NEXT: $x10 = COPY [[ADDI8]]
105+
; CHECK-NEXT: PseudoRET implicit $x10
106+
bb.1.entry:
107+
successors: %bb.8, %bb.9
108+
liveins: $x10
109+
110+
%1:gprb(s64) = COPY $x10
111+
%2:gprb(s64) = G_ASSERT_SEXT %1, 32
112+
%7:gprb(s64) = G_CONSTANT i64 5
113+
%3:gprb(s64) = G_SEXT_INREG %2, 32
114+
%4:gprb(s64) = G_CONSTANT i64 1
115+
%5:gprb(s64) = G_SUB %3, %4
116+
%26:gprb(s64) = G_ICMP intpred(ugt), %5(s64), %7
117+
G_BRCOND %26(s64), %bb.8
118+
119+
bb.9.entry:
120+
successors: %bb.2, %bb.3, %bb.4, %bb.5, %bb.6, %bb.7
121+
122+
%10:gprb(p0) = G_JUMP_TABLE %jump-table.0
123+
G_BRJT %10(p0), %jump-table.0, %5(s64)
124+
125+
bb.2.bb1:
126+
%22:gprb(s64) = G_CONSTANT i64 4
127+
$x10 = COPY %22(s64)
128+
PseudoRET implicit $x10
129+
130+
bb.3.bb2:
131+
%20:gprb(s64) = G_CONSTANT i64 3
132+
$x10 = COPY %20(s64)
133+
PseudoRET implicit $x10
134+
135+
bb.4.bb3:
136+
%18:gprb(s64) = G_CONSTANT i64 2
137+
$x10 = COPY %18(s64)
138+
PseudoRET implicit $x10
139+
140+
bb.5.bb4:
141+
%16:gprb(s64) = G_CONSTANT i64 1
142+
$x10 = COPY %16(s64)
143+
PseudoRET implicit $x10
144+
145+
bb.6.bb5:
146+
%14:gprb(s64) = G_CONSTANT i64 100
147+
$x10 = COPY %14(s64)
148+
PseudoRET implicit $x10
149+
150+
bb.7.bb6:
151+
%12:gprb(s64) = G_CONSTANT i64 200
152+
$x10 = COPY %12(s64)
153+
PseudoRET implicit $x10
154+
155+
bb.8.default:
156+
%24:gprb(s64) = G_CONSTANT i64 1000
157+
$x10 = COPY %24(s64)
158+
PseudoRET implicit $x10
159+
160+
...

0 commit comments

Comments
 (0)