Skip to content

Commit 21ae2e7

Browse files
committed
[RISCV] Codegen support for memory operations
This required the implementation of RISCVTargetInstrInfo::copyPhysReg. Support for lowering global addresses follow in the next patch. Differential Revision: https://reviews.llvm.org/D29934 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317685 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent c5abad3 commit 21ae2e7

File tree

6 files changed

+240
-0
lines changed

6 files changed

+240
-0
lines changed

lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
4949

5050
setStackPointerRegisterToSaveRestore(RISCV::X2);
5151

52+
for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD})
53+
setLoadExtAction(N, XLenVT, MVT::i1, Promote);
54+
5255
// TODO: add all necessary setOperationAction calls.
5356

5457
setBooleanContents(ZeroOrOneBooleanContent);

lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,15 @@
2929
using namespace llvm;
3030

3131
RISCVInstrInfo::RISCVInstrInfo() : RISCVGenInstrInfo() {}
32+
33+
void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
34+
MachineBasicBlock::iterator MBBI,
35+
const DebugLoc &DL, unsigned DstReg,
36+
unsigned SrcReg, bool KillSrc) const {
37+
assert(RISCV::GPRRegClass.contains(DstReg, SrcReg) &&
38+
"Impossible reg-to-reg copy");
39+
40+
BuildMI(MBB, MBBI, DL, get(RISCV::ADDI), DstReg)
41+
.addReg(SrcReg, getKillRegState(KillSrc))
42+
.addImm(0);
43+
}

lib/Target/RISCV/RISCVInstrInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
2626

2727
public:
2828
RISCVInstrInfo();
29+
30+
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
31+
const DebugLoc &DL, unsigned DstReg, unsigned SrcReg,
32+
bool KillSrc) const override;
2933
};
3034
}
3135

lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,31 @@ def : PatGprSimm12<setult, SLTIU>;
311311
let isBarrier = 1, isReturn = 1, isTerminator = 1 in
312312
def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>,
313313
PseudoInstExpansion<(JALR X0, X1, 0)>;
314+
315+
/// Loads
316+
317+
multiclass LdPat<PatFrag LoadOp, RVInst Inst> {
318+
def : Pat<(LoadOp GPR:$rs1), (Inst GPR:$rs1, 0)>;
319+
def : Pat<(LoadOp (add GPR:$rs1, simm12:$imm12)),
320+
(Inst GPR:$rs1, simm12:$imm12)>;
321+
}
322+
323+
defm : LdPat<sextloadi8, LB>;
324+
defm : LdPat<extloadi8, LB>;
325+
defm : LdPat<sextloadi16, LH>;
326+
defm : LdPat<extloadi16, LH>;
327+
defm : LdPat<load, LW>;
328+
defm : LdPat<zextloadi8, LBU>;
329+
defm : LdPat<zextloadi16, LHU>;
330+
331+
/// Stores
332+
333+
multiclass StPat<PatFrag StoreOp, RVInst Inst> {
334+
def : Pat<(StoreOp GPR:$rs2, GPR:$rs1), (Inst GPR:$rs2, GPR:$rs1, 0)>;
335+
def : Pat<(StoreOp GPR:$rs2, (add GPR:$rs1, simm12:$imm12)),
336+
(Inst GPR:$rs2, GPR:$rs1, simm12:$imm12)>;
337+
}
338+
339+
defm : StPat<truncstorei8, SB>;
340+
defm : StPat<truncstorei16, SH>;
341+
defm : StPat<store, SW>;

test/CodeGen/RISCV/mem.ll

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
3+
; RUN: | FileCheck %s -check-prefix=RV32I
4+
5+
; Check indexed and unindexed, sext, zext and anyext loads
6+
7+
define i32 @lb(i8 *%a) nounwind {
8+
; RV32I-LABEL: lb:
9+
; RV32I: # BB#0:
10+
; RV32I-NEXT: lb a1, 0(a0)
11+
; RV32I-NEXT: lb a0, 1(a0)
12+
; RV32I-NEXT: jalr zero, ra, 0
13+
%1 = getelementptr i8, i8* %a, i32 1
14+
%2 = load i8, i8* %1
15+
%3 = sext i8 %2 to i32
16+
; the unused load will produce an anyext for selection
17+
%4 = load volatile i8, i8* %a
18+
ret i32 %3
19+
}
20+
21+
define i32 @lh(i16 *%a) nounwind {
22+
; RV32I-LABEL: lh:
23+
; RV32I: # BB#0:
24+
; RV32I-NEXT: lh a1, 0(a0)
25+
; RV32I-NEXT: lh a0, 4(a0)
26+
; RV32I-NEXT: jalr zero, ra, 0
27+
%1 = getelementptr i16, i16* %a, i32 2
28+
%2 = load i16, i16* %1
29+
%3 = sext i16 %2 to i32
30+
; the unused load will produce an anyext for selection
31+
%4 = load volatile i16, i16* %a
32+
ret i32 %3
33+
}
34+
35+
define i32 @lw(i32 *%a) nounwind {
36+
; RV32I-LABEL: lw:
37+
; RV32I: # BB#0:
38+
; RV32I-NEXT: lw a1, 0(a0)
39+
; RV32I-NEXT: lw a0, 12(a0)
40+
; RV32I-NEXT: jalr zero, ra, 0
41+
%1 = getelementptr i32, i32* %a, i32 3
42+
%2 = load i32, i32* %1
43+
%3 = load volatile i32, i32* %a
44+
ret i32 %2
45+
}
46+
47+
define i32 @lbu(i8 *%a) nounwind {
48+
; RV32I-LABEL: lbu:
49+
; RV32I: # BB#0:
50+
; RV32I-NEXT: lbu a1, 0(a0)
51+
; RV32I-NEXT: lbu a0, 4(a0)
52+
; RV32I-NEXT: add a0, a0, a1
53+
; RV32I-NEXT: jalr zero, ra, 0
54+
%1 = getelementptr i8, i8* %a, i32 4
55+
%2 = load i8, i8* %1
56+
%3 = zext i8 %2 to i32
57+
%4 = load volatile i8, i8* %a
58+
%5 = zext i8 %4 to i32
59+
%6 = add i32 %3, %5
60+
ret i32 %6
61+
}
62+
63+
define i32 @lhu(i16 *%a) nounwind {
64+
; RV32I-LABEL: lhu:
65+
; RV32I: # BB#0:
66+
; RV32I-NEXT: lhu a1, 0(a0)
67+
; RV32I-NEXT: lhu a0, 10(a0)
68+
; RV32I-NEXT: add a0, a0, a1
69+
; RV32I-NEXT: jalr zero, ra, 0
70+
%1 = getelementptr i16, i16* %a, i32 5
71+
%2 = load i16, i16* %1
72+
%3 = zext i16 %2 to i32
73+
%4 = load volatile i16, i16* %a
74+
%5 = zext i16 %4 to i32
75+
%6 = add i32 %3, %5
76+
ret i32 %6
77+
}
78+
79+
; Check indexed and unindexed stores
80+
81+
define void @sb(i8 *%a, i8 %b) nounwind {
82+
; RV32I-LABEL: sb:
83+
; RV32I: # BB#0:
84+
; RV32I-NEXT: sb a1, 6(a0)
85+
; RV32I-NEXT: sb a1, 0(a0)
86+
; RV32I-NEXT: jalr zero, ra, 0
87+
store i8 %b, i8* %a
88+
%1 = getelementptr i8, i8* %a, i32 6
89+
store i8 %b, i8* %1
90+
ret void
91+
}
92+
93+
define void @sh(i16 *%a, i16 %b) nounwind {
94+
; RV32I-LABEL: sh:
95+
; RV32I: # BB#0:
96+
; RV32I-NEXT: sh a1, 14(a0)
97+
; RV32I-NEXT: sh a1, 0(a0)
98+
; RV32I-NEXT: jalr zero, ra, 0
99+
store i16 %b, i16* %a
100+
%1 = getelementptr i16, i16* %a, i32 7
101+
store i16 %b, i16* %1
102+
ret void
103+
}
104+
105+
define void @sw(i32 *%a, i32 %b) nounwind {
106+
; RV32I-LABEL: sw:
107+
; RV32I: # BB#0:
108+
; RV32I-NEXT: sw a1, 32(a0)
109+
; RV32I-NEXT: sw a1, 0(a0)
110+
; RV32I-NEXT: jalr zero, ra, 0
111+
store i32 %b, i32* %a
112+
%1 = getelementptr i32, i32* %a, i32 8
113+
store i32 %b, i32* %1
114+
ret void
115+
}
116+
117+
; Check load and store to an i1 ___location
118+
define i32 @load_sext_zext_anyext_i1(i1 *%a) nounwind {
119+
; RV32I-LABEL: load_sext_zext_anyext_i1:
120+
; RV32I: # BB#0:
121+
; RV32I-NEXT: lb a1, 0(a0)
122+
; RV32I-NEXT: lbu a1, 1(a0)
123+
; RV32I-NEXT: lbu a0, 2(a0)
124+
; RV32I-NEXT: sub a0, a0, a1
125+
; RV32I-NEXT: jalr zero, ra, 0
126+
; sextload i1
127+
%1 = getelementptr i1, i1* %a, i32 1
128+
%2 = load i1, i1* %1
129+
%3 = sext i1 %2 to i32
130+
; zextload i1
131+
%4 = getelementptr i1, i1* %a, i32 2
132+
%5 = load i1, i1* %4
133+
%6 = zext i1 %5 to i32
134+
%7 = add i32 %3, %6
135+
; extload i1 (anyext). Produced as the load is unused.
136+
%8 = load volatile i1, i1* %a
137+
ret i32 %7
138+
}
139+
140+
define i16 @load_sext_zext_anyext_i1_i16(i1 *%a) nounwind {
141+
; RV32I-LABEL: load_sext_zext_anyext_i1_i16:
142+
; RV32I: # BB#0:
143+
; RV32I-NEXT: lb a1, 0(a0)
144+
; RV32I-NEXT: lbu a1, 1(a0)
145+
; RV32I-NEXT: lbu a0, 2(a0)
146+
; RV32I-NEXT: sub a0, a0, a1
147+
; RV32I-NEXT: jalr zero, ra, 0
148+
; sextload i1
149+
%1 = getelementptr i1, i1* %a, i32 1
150+
%2 = load i1, i1* %1
151+
%3 = sext i1 %2 to i16
152+
; zextload i1
153+
%4 = getelementptr i1, i1* %a, i32 2
154+
%5 = load i1, i1* %4
155+
%6 = zext i1 %5 to i16
156+
%7 = add i16 %3, %6
157+
; extload i1 (anyext). Produced as the load is unused.
158+
%8 = load volatile i1, i1* %a
159+
ret i16 %7
160+
}
161+
162+
; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1
163+
define i32 @lw_sw_constant(i32 %a) nounwind {
164+
; TODO: the addi should be folded in to the lw/sw
165+
; RV32I-LABEL: lw_sw_constant:
166+
; RV32I: # BB#0:
167+
; RV32I-NEXT: lui a1, 912092
168+
; RV32I-NEXT: addi a2, a1, -273
169+
; RV32I-NEXT: lw a1, 0(a2)
170+
; RV32I-NEXT: sw a0, 0(a2)
171+
; RV32I-NEXT: addi a0, a1, 0
172+
; RV32I-NEXT: jalr zero, ra, 0
173+
%1 = inttoptr i32 3735928559 to i32*
174+
%2 = load volatile i32, i32* %1
175+
store i32 %a, i32* %1
176+
ret i32 %2
177+
}

test/CodeGen/RISCV/wide-mem.ll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
3+
; RUN: | FileCheck %s -check-prefix=RV32I
4+
5+
; Check load/store operations on values wider than what is natively supported
6+
7+
define i64 @load_i64(i64 *%a) nounwind {
8+
; RV32I-LABEL: load_i64:
9+
; RV32I: # BB#0:
10+
; RV32I-NEXT: lw a2, 0(a0)
11+
; RV32I-NEXT: lw a1, 4(a0)
12+
; RV32I-NEXT: addi a0, a2, 0
13+
; RV32I-NEXT: jalr zero, ra, 0
14+
%1 = load i64, i64* %a
15+
ret i64 %1
16+
}

0 commit comments

Comments
 (0)