Skip to content

Commit a356b83

Browse files
committed
[RISCV][GISel] Instruction selection for G_JUMP_TABLE and G_BRJT.
1 parent b034da7 commit a356b83

File tree

7 files changed

+1249
-0
lines changed

7 files changed

+1249
-0
lines changed

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

Lines changed: 140 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,50 @@ 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+
unsigned EntrySize =
504+
MF.getJumpTableInfo()->getEntrySize(MF.getDataLayout());
505+
assert((EntrySize == 4 || (Subtarget->is64Bit() && EntrySize == 8)) &&
506+
"Unsupported jump-table entry size");
507+
508+
auto SLL =
509+
MIB.buildInstr(RISCV::SLLI, {&RISCV::GPRRegClass}, {MI.getOperand(2)})
510+
.addImm(Log2_32(EntrySize));
511+
if (!SLL.constrainAllUses(TII, TRI, RBI))
512+
return false;
513+
514+
// TODO: Use SHXADD. Moving to legalization would fix this automatically.
515+
auto ADD = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass},
516+
{MI.getOperand(0), SLL.getReg(0)});
517+
if (!ADD.constrainAllUses(TII, TRI, RBI))
518+
return false;
519+
520+
unsigned LdOpc = EntrySize == 8 ? RISCV::LD : RISCV::LW;
521+
auto Dest =
522+
MIB.buildInstr(LdOpc, {&RISCV::GPRRegClass}, {ADD.getReg(0)})
523+
.addImm(0)
524+
.addMemOperand(MF.getMachineMemOperand(
525+
MachinePointerInfo::getJumpTable(MF), MachineMemOperand::MOLoad,
526+
EntrySize, Align(EntrySize)));
527+
if (!Dest.constrainAllUses(TII, TRI, RBI))
528+
return false;
529+
530+
if (MF.getTarget().isPositionIndependent()) {
531+
Dest = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass},
532+
{Dest.getReg(0), MI.getOperand(0)});
533+
if (!Dest.constrainAllUses(TII, TRI, RBI))
534+
return false;
535+
}
536+
537+
auto Branch =
538+
MIB.buildInstr(RISCV::PseudoBRIND, {}, {Dest.getReg(0)}).addImm(0);
539+
if (!Branch.constrainAllUses(TII, TRI, RBI))
540+
return false;
541+
542+
MI.eraseFromParent();
543+
return true;
544+
}
496545
case TargetOpcode::G_SEXT_INREG:
497546
return selectSExtInreg(MI, MIB);
498547
case TargetOpcode::G_FRAME_INDEX: {
@@ -784,6 +833,97 @@ bool RISCVInstructionSelector::selectGlobalValue(
784833
return false;
785834
}
786835

836+
// FIXME: This is very similar to selectGlobalValue. Merge somehow?
837+
bool RISCVInstructionSelector::selectJumpTable(MachineInstr &MI,
838+
MachineIRBuilder &MIB,
839+
MachineRegisterInfo &MRI) const {
840+
assert(MI.getOpcode() == TargetOpcode::G_JUMP_TABLE &&
841+
"Expected G_JUMP_TABLE");
842+
843+
int Idx = MI.getOperand(1).getIndex();
844+
845+
Register DefReg = MI.getOperand(0).getReg();
846+
const LLT DefTy = MRI.getType(DefReg);
847+
MachineInstr *Result = nullptr;
848+
849+
// When HWASAN is used and tagging of global variables is enabled
850+
// they should be accessed via the GOT, since the tagged address of a global
851+
// is incompatible with existing code models. This also applies to non-pic
852+
// mode.
853+
if (TM.isPositionIndependent() || Subtarget->allowTaggedGlobals()) {
854+
if (!Subtarget->allowTaggedGlobals()) {
855+
// Use PC-relative addressing to access the symbol. This generates the
856+
// pattern (PseudoLLA sym), which expands to (addi (auipc %pcrel_hi(sym))
857+
// %pcrel_lo(auipc)).
858+
Result =
859+
MIB.buildInstr(RISCV::PseudoLLA, {DefReg}, {}).addJumpTableIndex(Idx);
860+
} else {
861+
// Use PC-relative addressing to access the GOT for this symbol, then
862+
// load the address from the GOT. This generates the pattern (PseudoLGA
863+
// sym), which expands to (ld (addi (auipc %got_pcrel_hi(sym))
864+
// %pcrel_lo(auipc))).
865+
MachineFunction &MF = *MI.getParent()->getParent();
866+
MachineMemOperand *MemOp = MF.getMachineMemOperand(
867+
MachinePointerInfo::getGOT(MF),
868+
MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |
869+
MachineMemOperand::MOInvariant,
870+
DefTy, Align(DefTy.getSizeInBits() / 8));
871+
872+
Result = MIB.buildInstr(RISCV::PseudoLGA, {DefReg}, {})
873+
.addJumpTableIndex(Idx)
874+
.addMemOperand(MemOp);
875+
}
876+
877+
if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
878+
return false;
879+
880+
MI.eraseFromParent();
881+
return true;
882+
}
883+
884+
switch (TM.getCodeModel()) {
885+
default: {
886+
reportGISelFailure(const_cast<MachineFunction &>(*MF), *TPC, *MORE,
887+
getName(), "Unsupported code model for lowering", MI);
888+
return false;
889+
}
890+
case CodeModel::Small: {
891+
// Must lie within a single 2 GiB address range and must lie between
892+
// absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi
893+
// (lui %hi(sym)) %lo(sym)).
894+
Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);
895+
MachineInstr *AddrHi = MIB.buildInstr(RISCV::LUI, {AddrHiDest}, {})
896+
.addJumpTableIndex(Idx, RISCVII::MO_HI);
897+
898+
if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))
899+
return false;
900+
901+
Result = MIB.buildInstr(RISCV::ADDI, {DefReg}, {AddrHiDest})
902+
.addJumpTableIndex(Idx, RISCVII::MO_LO);
903+
904+
if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
905+
return false;
906+
907+
MI.eraseFromParent();
908+
return true;
909+
}
910+
case CodeModel::Medium: {
911+
// Generate a sequence for accessing addresses within any 2GiB range
912+
// within the address space. This generates the pattern (PseudoLLA sym),
913+
// which expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
914+
Result =
915+
MIB.buildInstr(RISCV::PseudoLLA, {DefReg}, {}).addJumpTableIndex(Idx);
916+
917+
if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))
918+
return false;
919+
920+
MI.eraseFromParent();
921+
return true;
922+
}
923+
}
924+
return false;
925+
}
926+
787927
bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI,
788928
MachineIRBuilder &MIB) const {
789929
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)