xref: /llvm-project/llvm/test/CodeGen/RISCV/inline-asm.ll (revision 228f88fdc8e92789e0562f8a47493493da843145)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=riscv32 -verify-machineinstrs -no-integrated-as < %s \
3; RUN:   | FileCheck -check-prefix=RV32I %s
4; RUN: llc -mtriple=riscv64 -verify-machineinstrs -no-integrated-as < %s \
5; RUN:   | FileCheck -check-prefix=RV64I %s
6
7@gi = external global i32
8
9define i32 @constraint_r(i32 %a) nounwind {
10; RV32I-LABEL: constraint_r:
11; RV32I:       # %bb.0:
12; RV32I-NEXT:    lui a1, %hi(gi)
13; RV32I-NEXT:    lw a1, %lo(gi)(a1)
14; RV32I-NEXT:    #APP
15; RV32I-NEXT:    add a0, a0, a1
16; RV32I-NEXT:    #NO_APP
17; RV32I-NEXT:    ret
18;
19; RV64I-LABEL: constraint_r:
20; RV64I:       # %bb.0:
21; RV64I-NEXT:    lui a1, %hi(gi)
22; RV64I-NEXT:    lw a1, %lo(gi)(a1)
23; RV64I-NEXT:    #APP
24; RV64I-NEXT:    add a0, a0, a1
25; RV64I-NEXT:    #NO_APP
26; RV64I-NEXT:    ret
27  %1 = load i32, ptr @gi
28  %2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 %a, i32 %1)
29  ret i32 %2
30}
31
32; Don't allow 'x0' for 'r'. Some instructions have a different behavior when
33; x0 is encoded.
34define i32 @constraint_r_zero(i32 %a) nounwind {
35; RV32I-LABEL: constraint_r_zero:
36; RV32I:       # %bb.0:
37; RV32I-NEXT:    lui a0, %hi(gi)
38; RV32I-NEXT:    lw a0, %lo(gi)(a0)
39; RV32I-NEXT:    li a1, 0
40; RV32I-NEXT:    #APP
41; RV32I-NEXT:    add a0, a1, a0
42; RV32I-NEXT:    #NO_APP
43; RV32I-NEXT:    ret
44;
45; RV64I-LABEL: constraint_r_zero:
46; RV64I:       # %bb.0:
47; RV64I-NEXT:    lui a0, %hi(gi)
48; RV64I-NEXT:    lw a0, %lo(gi)(a0)
49; RV64I-NEXT:    li a1, 0
50; RV64I-NEXT:    #APP
51; RV64I-NEXT:    add a0, a1, a0
52; RV64I-NEXT:    #NO_APP
53; RV64I-NEXT:    ret
54  %1 = load i32, ptr @gi
55  %2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 0, i32 %1)
56  ret i32 %2
57}
58
59define i32 @constraint_cr(i32 %a) nounwind {
60; RV32I-LABEL: constraint_cr:
61; RV32I:       # %bb.0:
62; RV32I-NEXT:    lui a1, %hi(gi)
63; RV32I-NEXT:    lw a1, %lo(gi)(a1)
64; RV32I-NEXT:    #APP
65; RV32I-NEXT:    c.add a0, a0, a1
66; RV32I-NEXT:    #NO_APP
67; RV32I-NEXT:    ret
68;
69; RV64I-LABEL: constraint_cr:
70; RV64I:       # %bb.0:
71; RV64I-NEXT:    lui a1, %hi(gi)
72; RV64I-NEXT:    lw a1, %lo(gi)(a1)
73; RV64I-NEXT:    #APP
74; RV64I-NEXT:    c.add a0, a0, a1
75; RV64I-NEXT:    #NO_APP
76; RV64I-NEXT:    ret
77  %1 = load i32, ptr @gi
78  %2 = tail call i32 asm "c.add $0, $1, $2", "=^cr,0,^cr"(i32 %a, i32 %1)
79  ret i32 %2
80}
81
82define i32 @constraint_i(i32 %a) nounwind {
83; RV32I-LABEL: constraint_i:
84; RV32I:       # %bb.0:
85; RV32I-NEXT:    #APP
86; RV32I-NEXT:    addi a0, a0, 113
87; RV32I-NEXT:    #NO_APP
88; RV32I-NEXT:    ret
89;
90; RV64I-LABEL: constraint_i:
91; RV64I:       # %bb.0:
92; RV64I-NEXT:    #APP
93; RV64I-NEXT:    addi a0, a0, 113
94; RV64I-NEXT:    #NO_APP
95; RV64I-NEXT:    ret
96  %1 = load i32, ptr @gi
97  %2 = tail call i32 asm "addi $0, $1, $2", "=r,r,i"(i32 %a, i32 113)
98  ret i32 %2
99}
100
101define void @constraint_I() nounwind {
102; RV32I-LABEL: constraint_I:
103; RV32I:       # %bb.0:
104; RV32I-NEXT:    #APP
105; RV32I-NEXT:    addi a0, a0, 2047
106; RV32I-NEXT:    #NO_APP
107; RV32I-NEXT:    #APP
108; RV32I-NEXT:    addi a0, a0, -2048
109; RV32I-NEXT:    #NO_APP
110; RV32I-NEXT:    ret
111;
112; RV64I-LABEL: constraint_I:
113; RV64I:       # %bb.0:
114; RV64I-NEXT:    #APP
115; RV64I-NEXT:    addi a0, a0, 2047
116; RV64I-NEXT:    #NO_APP
117; RV64I-NEXT:    #APP
118; RV64I-NEXT:    addi a0, a0, -2048
119; RV64I-NEXT:    #NO_APP
120; RV64I-NEXT:    ret
121  tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2047)
122  tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2048)
123  ret void
124}
125
126define void @constraint_J() nounwind {
127; RV32I-LABEL: constraint_J:
128; RV32I:       # %bb.0:
129; RV32I-NEXT:    #APP
130; RV32I-NEXT:    addi a0, a0, 0
131; RV32I-NEXT:    #NO_APP
132; RV32I-NEXT:    ret
133;
134; RV64I-LABEL: constraint_J:
135; RV64I:       # %bb.0:
136; RV64I-NEXT:    #APP
137; RV64I-NEXT:    addi a0, a0, 0
138; RV64I-NEXT:    #NO_APP
139; RV64I-NEXT:    ret
140  tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 0)
141  ret void
142}
143
144define void @constraint_K() nounwind {
145; RV32I-LABEL: constraint_K:
146; RV32I:       # %bb.0:
147; RV32I-NEXT:    #APP
148; RV32I-NEXT:    csrwi mstatus, 31
149; RV32I-NEXT:    #NO_APP
150; RV32I-NEXT:    #APP
151; RV32I-NEXT:    csrwi mstatus, 0
152; RV32I-NEXT:    #NO_APP
153; RV32I-NEXT:    ret
154;
155; RV64I-LABEL: constraint_K:
156; RV64I:       # %bb.0:
157; RV64I-NEXT:    #APP
158; RV64I-NEXT:    csrwi mstatus, 31
159; RV64I-NEXT:    #NO_APP
160; RV64I-NEXT:    #APP
161; RV64I-NEXT:    csrwi mstatus, 0
162; RV64I-NEXT:    #NO_APP
163; RV64I-NEXT:    ret
164  tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 31)
165  tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 0)
166  ret void
167}
168
169define i32 @modifier_z_zero(i32 %a) nounwind {
170; RV32I-LABEL: modifier_z_zero:
171; RV32I:       # %bb.0:
172; RV32I-NEXT:    #APP
173; RV32I-NEXT:    add a0, a0, zero
174; RV32I-NEXT:    #NO_APP
175; RV32I-NEXT:    ret
176;
177; RV64I-LABEL: modifier_z_zero:
178; RV64I:       # %bb.0:
179; RV64I-NEXT:    #APP
180; RV64I-NEXT:    add a0, a0, zero
181; RV64I-NEXT:    #NO_APP
182; RV64I-NEXT:    ret
183  %1 = tail call i32 asm "add $0, $1, ${2:z}", "=r,r,i"(i32 %a, i32 0)
184  ret i32 %1
185}
186
187define i32 @modifier_z_nonzero(i32 %a) nounwind {
188; RV32I-LABEL: modifier_z_nonzero:
189; RV32I:       # %bb.0:
190; RV32I-NEXT:    #APP
191; RV32I-NEXT:    add a0, a0, 1
192; RV32I-NEXT:    #NO_APP
193; RV32I-NEXT:    ret
194;
195; RV64I-LABEL: modifier_z_nonzero:
196; RV64I:       # %bb.0:
197; RV64I-NEXT:    #APP
198; RV64I-NEXT:    add a0, a0, 1
199; RV64I-NEXT:    #NO_APP
200; RV64I-NEXT:    ret
201  %1 = tail call i32 asm "add $0, $1, ${2:z}", "=r,r,i"(i32 %a, i32 1)
202  ret i32 %1
203}
204
205define i32 @modifier_i_imm(i32 %a) nounwind {
206; RV32I-LABEL: modifier_i_imm:
207; RV32I:       # %bb.0:
208; RV32I-NEXT:    #APP
209; RV32I-NEXT:    addi a0, a0, 1
210; RV32I-NEXT:    #NO_APP
211; RV32I-NEXT:    ret
212;
213; RV64I-LABEL: modifier_i_imm:
214; RV64I:       # %bb.0:
215; RV64I-NEXT:    #APP
216; RV64I-NEXT:    addi a0, a0, 1
217; RV64I-NEXT:    #NO_APP
218; RV64I-NEXT:    ret
219  %1 = tail call i32 asm "add${2:i} $0, $1, $2", "=r,r,ri"(i32 %a, i32 1)
220  ret i32 %1
221}
222
223define i32 @modifier_i_reg(i32 %a, i32 %b) nounwind {
224; RV32I-LABEL: modifier_i_reg:
225; RV32I:       # %bb.0:
226; RV32I-NEXT:    #APP
227; RV32I-NEXT:    add a0, a0, a1
228; RV32I-NEXT:    #NO_APP
229; RV32I-NEXT:    ret
230;
231; RV64I-LABEL: modifier_i_reg:
232; RV64I:       # %bb.0:
233; RV64I-NEXT:    #APP
234; RV64I-NEXT:    add a0, a0, a1
235; RV64I-NEXT:    #NO_APP
236; RV64I-NEXT:    ret
237  %1 = tail call i32 asm "add${2:i} $0, $1, $2", "=r,r,ri"(i32 %a, i32 %b)
238  ret i32 %1
239}
240
241;; `.insn 0x4, 0x33 | (${0:N} << 7) | (${1:N} << 15) | (${2:N} << 20)` is the
242;; raw encoding of `add`
243
244define i32 @modifier_N_reg(i32 %a, i32 %b) nounwind {
245; RV32I-LABEL: modifier_N_reg:
246; RV32I:       # %bb.0:
247; RV32I-NEXT:    #APP
248; RV32I-NEXT:    .insn 0x4, 0x33 | (10 << 7) | (10 << 15) | (11 << 20)
249; RV32I-NEXT:    #NO_APP
250; RV32I-NEXT:    ret
251;
252; RV64I-LABEL: modifier_N_reg:
253; RV64I:       # %bb.0:
254; RV64I-NEXT:    #APP
255; RV64I-NEXT:    .insn 0x4, 0x33 | (10 << 7) | (10 << 15) | (11 << 20)
256; RV64I-NEXT:    #NO_APP
257; RV64I-NEXT:    ret
258  %1 = tail call i32 asm ".insn 0x4, 0x33 | (${0:N} << 7) | (${1:N} << 15) | (${2:N} << 20)", "=r,r,r"(i32 %a, i32 %b)
259  ret i32 %1
260}
261
262;; `.insn 0x2, 0x9422 | (${0:N} << 7) | (${2:N} << 2)` is the raw encoding of
263;; `c.add` (note the constraint that the first input should be the same as the
264;; output).
265
266define i32 @modifier_N_with_cr_reg(i32 %a, i32 %b) nounwind {
267; RV32I-LABEL: modifier_N_with_cr_reg:
268; RV32I:       # %bb.0:
269; RV32I-NEXT:    #APP
270; RV32I-NEXT:    .insn 0x2, 0x9422 | (10 << 7) | (11 << 2)
271; RV32I-NEXT:    #NO_APP
272; RV32I-NEXT:    ret
273;
274; RV64I-LABEL: modifier_N_with_cr_reg:
275; RV64I:       # %bb.0:
276; RV64I-NEXT:    #APP
277; RV64I-NEXT:    .insn 0x2, 0x9422 | (10 << 7) | (11 << 2)
278; RV64I-NEXT:    #NO_APP
279; RV64I-NEXT:    ret
280  %1 = tail call i32 asm ".insn 0x2, 0x9422 | (${0:N} << 7) | (${2:N} << 2)", "=^cr,0,^cr"(i32 %a, i32 %b)
281  ret i32 %1
282}
283
284define void @operand_global() nounwind {
285; RV32I-LABEL: operand_global:
286; RV32I:       # %bb.0:
287; RV32I-NEXT:    #APP
288; RV32I-NEXT:    .8byte gi
289; RV32I-NEXT:    #NO_APP
290; RV32I-NEXT:    ret
291;
292; RV64I-LABEL: operand_global:
293; RV64I:       # %bb.0:
294; RV64I-NEXT:    #APP
295; RV64I-NEXT:    .8byte gi
296; RV64I-NEXT:    #NO_APP
297; RV64I-NEXT:    ret
298  tail call void asm sideeffect ".8byte $0", "i"(ptr @gi)
299  ret void
300}
301
302define void @operand_block_address() nounwind {
303; RV32I-LABEL: operand_block_address:
304; RV32I:       # %bb.0:
305; RV32I-NEXT:    #APP
306; RV32I-NEXT:    j .Ltmp0
307; RV32I-NEXT:    #NO_APP
308; RV32I-NEXT:  .Ltmp0: # Block address taken
309; RV32I-NEXT:  # %bb.1: # %bb
310; RV32I-NEXT:    ret
311;
312; RV64I-LABEL: operand_block_address:
313; RV64I:       # %bb.0:
314; RV64I-NEXT:    #APP
315; RV64I-NEXT:    j .Ltmp0
316; RV64I-NEXT:    #NO_APP
317; RV64I-NEXT:  .Ltmp0: # Block address taken
318; RV64I-NEXT:  # %bb.1: # %bb
319; RV64I-NEXT:    ret
320  call void asm sideeffect "j $0", "i"(ptr blockaddress(@operand_block_address, %bb))
321  br label %bb
322bb:
323  ret void
324}
325
326; TODO: expand tests for more complex constraints, out of range immediates etc
327