Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / test / CodeGen / RISCV / GlobalISel / irtranslator / calling-conv-ilp32-ilp32f-ilp32d-common.ll
blobe6837b90e3bb161115fc69223de11dbf8f0c0988
1 ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
2 ; RUN: llc -mtriple=riscv32 \
3 ; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
4 ; RUN:   | FileCheck -check-prefix=RV32I %s
5 ; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f \
6 ; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
7 ; RUN:   | FileCheck -check-prefix=RV32I %s
8 ; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d \
9 ; RUN:    -global-isel -stop-after=irtranslator -verify-machineinstrs < %s \
10 ; RUN:   | FileCheck -check-prefix=RV32I %s
12 ; This file contains tests that should have identical output for the ilp32,
13 ; ilp32f, and ilp32d ABIs. i.e. where no arguments are passed according to
14 ; the floating point ABI.
16 ; Check that on RV32, i64 is passed in a pair of registers. Unlike
17 ; the convention for varargs, this need not be an aligned pair.
19 define i32 @callee_i64_in_regs(i32 %a, i64 %b) nounwind {
20   ; RV32I-LABEL: name: callee_i64_in_regs
21   ; RV32I: bb.1 (%ir-block.0):
22   ; RV32I-NEXT:   liveins: $x10, $x11, $x12
23   ; RV32I-NEXT: {{  $}}
24   ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
25   ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
26   ; RV32I-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
27   ; RV32I-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY1]](s32), [[COPY2]](s32)
28   ; RV32I-NEXT:   [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[MV]](s64)
29   ; RV32I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[TRUNC]]
30   ; RV32I-NEXT:   $x10 = COPY [[ADD]](s32)
31   ; RV32I-NEXT:   PseudoRET implicit $x10
32   %b_trunc = trunc i64 %b to i32
33   %1 = add i32 %a, %b_trunc
34   ret i32 %1
37 define i32 @caller_i64_in_regs() nounwind {
38   ; RV32I-LABEL: name: caller_i64_in_regs
39   ; RV32I: bb.1 (%ir-block.0):
40   ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
41   ; RV32I-NEXT:   [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
42   ; RV32I-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C1]](s64)
43   ; RV32I-NEXT:   $x10 = COPY [[C]](s32)
44   ; RV32I-NEXT:   $x11 = COPY [[UV]](s32)
45   ; RV32I-NEXT:   $x12 = COPY [[UV1]](s32)
46   ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_i64_in_regs, implicit-def $x1, implicit $x10, implicit $x11, implicit $x12, implicit-def $x10
47   ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
48   ; RV32I-NEXT:   $x10 = COPY [[COPY]](s32)
49   ; RV32I-NEXT:   PseudoRET implicit $x10
50   %1 = call i32 @callee_i64_in_regs(i32 1, i64 2)
51   ret i32 %1
54 ; Check that the stack is used once the GPRs are exhausted
56 define i32 @callee_many_scalars(i8 %a, i16 %b, i32 %c, i64 %d, i32 %e, i32 %f, i64 %g, i32 %h) nounwind {
57   ; RV32I-LABEL: name: callee_many_scalars
58   ; RV32I: bb.1 (%ir-block.0):
59   ; RV32I-NEXT:   liveins: $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17
60   ; RV32I-NEXT: {{  $}}
61   ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
62   ; RV32I-NEXT:   [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32)
63   ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
64   ; RV32I-NEXT:   [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
65   ; RV32I-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY $x12
66   ; RV32I-NEXT:   [[COPY3:%[0-9]+]]:_(s32) = COPY $x13
67   ; RV32I-NEXT:   [[COPY4:%[0-9]+]]:_(s32) = COPY $x14
68   ; RV32I-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY3]](s32), [[COPY4]](s32)
69   ; RV32I-NEXT:   [[COPY5:%[0-9]+]]:_(s32) = COPY $x15
70   ; RV32I-NEXT:   [[COPY6:%[0-9]+]]:_(s32) = COPY $x16
71   ; RV32I-NEXT:   [[COPY7:%[0-9]+]]:_(s32) = COPY $x17
72   ; RV32I-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.1
73   ; RV32I-NEXT:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (load (s32) from %fixed-stack.1, align 16)
74   ; RV32I-NEXT:   [[MV1:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY7]](s32), [[LOAD]](s32)
75   ; RV32I-NEXT:   [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
76   ; RV32I-NEXT:   [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX1]](p0) :: (load (s32) from %fixed-stack.0)
77   ; RV32I-NEXT:   [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC]](s8)
78   ; RV32I-NEXT:   [[ZEXT1:%[0-9]+]]:_(s32) = G_ZEXT [[TRUNC1]](s16)
79   ; RV32I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[ZEXT]], [[ZEXT1]]
80   ; RV32I-NEXT:   [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[ADD]], [[COPY2]]
81   ; RV32I-NEXT:   [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), [[MV]](s64), [[MV1]]
82   ; RV32I-NEXT:   [[ZEXT2:%[0-9]+]]:_(s32) = G_ZEXT [[ICMP]](s1)
83   ; RV32I-NEXT:   [[ADD2:%[0-9]+]]:_(s32) = G_ADD [[ZEXT2]], [[ADD1]]
84   ; RV32I-NEXT:   [[ADD3:%[0-9]+]]:_(s32) = G_ADD [[ADD2]], [[COPY5]]
85   ; RV32I-NEXT:   [[ADD4:%[0-9]+]]:_(s32) = G_ADD [[ADD3]], [[COPY6]]
86   ; RV32I-NEXT:   [[ADD5:%[0-9]+]]:_(s32) = G_ADD [[ADD4]], [[LOAD1]]
87   ; RV32I-NEXT:   $x10 = COPY [[ADD5]](s32)
88   ; RV32I-NEXT:   PseudoRET implicit $x10
89   %a_ext = zext i8 %a to i32
90   %b_ext = zext i16 %b to i32
91   %1 = add i32 %a_ext, %b_ext
92   %2 = add i32 %1, %c
93   %3 = icmp eq i64 %d, %g
94   %4 = zext i1 %3 to i32
95   %5 = add i32 %4, %2
96   %6 = add i32 %5, %e
97   %7 = add i32 %6, %f
98   %8 = add i32 %7, %h
99   ret i32 %8
102 define i32 @caller_many_scalars() nounwind {
103   ; RV32I-LABEL: name: caller_many_scalars
104   ; RV32I: bb.1 (%ir-block.0):
105   ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 1
106   ; RV32I-NEXT:   [[C1:%[0-9]+]]:_(s16) = G_CONSTANT i16 2
107   ; RV32I-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
108   ; RV32I-NEXT:   [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
109   ; RV32I-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
110   ; RV32I-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 6
111   ; RV32I-NEXT:   [[C6:%[0-9]+]]:_(s64) = G_CONSTANT i64 7
112   ; RV32I-NEXT:   [[C7:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
113   ; RV32I-NEXT:   [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[C]](s8)
114   ; RV32I-NEXT:   [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[C1]](s16)
115   ; RV32I-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C3]](s64)
116   ; RV32I-NEXT:   [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C6]](s64)
117   ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x2
118   ; RV32I-NEXT:   [[C8:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
119   ; RV32I-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C8]](s32)
120   ; RV32I-NEXT:   G_STORE [[UV3]](s32), [[PTR_ADD]](p0) :: (store (s32) into stack, align 16)
121   ; RV32I-NEXT:   [[C9:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
122   ; RV32I-NEXT:   [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C9]](s32)
123   ; RV32I-NEXT:   G_STORE [[C7]](s32), [[PTR_ADD1]](p0) :: (store (s32) into stack + 4)
124   ; RV32I-NEXT:   $x10 = COPY [[ANYEXT]](s32)
125   ; RV32I-NEXT:   $x11 = COPY [[ANYEXT1]](s32)
126   ; RV32I-NEXT:   $x12 = COPY [[C2]](s32)
127   ; RV32I-NEXT:   $x13 = COPY [[UV]](s32)
128   ; RV32I-NEXT:   $x14 = COPY [[UV1]](s32)
129   ; RV32I-NEXT:   $x15 = COPY [[C4]](s32)
130   ; RV32I-NEXT:   $x16 = COPY [[C5]](s32)
131   ; RV32I-NEXT:   $x17 = COPY [[UV2]](s32)
132   ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_many_scalars, implicit-def $x1, implicit $x10, implicit $x11, implicit $x12, implicit $x13, implicit $x14, implicit $x15, implicit $x16, implicit $x17, implicit-def $x10
133   ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x10
134   ; RV32I-NEXT:   $x10 = COPY [[COPY1]](s32)
135   ; RV32I-NEXT:   PseudoRET implicit $x10
136   %1 = call i32 @callee_many_scalars(i8 1, i16 2, i32 3, i64 4, i32 5, i32 6, i64 7, i32 8)
137   ret i32 %1
140 ; Check return of 2x xlen scalars
142 define i64 @callee_small_scalar_ret() nounwind {
143   ; RV32I-LABEL: name: callee_small_scalar_ret
144   ; RV32I: bb.1 (%ir-block.0):
145   ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1234567898765
146   ; RV32I-NEXT:   [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
147   ; RV32I-NEXT:   $x10 = COPY [[UV]](s32)
148   ; RV32I-NEXT:   $x11 = COPY [[UV1]](s32)
149   ; RV32I-NEXT:   PseudoRET implicit $x10, implicit $x11
150   ret i64 1234567898765
153 define i32 @caller_small_scalar_ret() nounwind {
154   ; RV32I-LABEL: name: caller_small_scalar_ret
155   ; RV32I: bb.1 (%ir-block.0):
156   ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 987654321234567
157   ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_small_scalar_ret, implicit-def $x1, implicit-def $x10, implicit-def $x11
158   ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
159   ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
160   ; RV32I-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
161   ; RV32I-NEXT:   [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), [[C]](s64), [[MV]]
162   ; RV32I-NEXT:   [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[ICMP]](s1)
163   ; RV32I-NEXT:   $x10 = COPY [[ZEXT]](s32)
164   ; RV32I-NEXT:   PseudoRET implicit $x10
165   %1 = call i64 @callee_small_scalar_ret()
166   %2 = icmp eq i64 987654321234567, %1
167   %3 = zext i1 %2 to i32
168   ret i32 %3
171 ; Check return of 2x xlen structs
173 %struct.small = type { i32, ptr }
175 define %struct.small @callee_small_struct_ret() nounwind {
176   ; RV32I-LABEL: name: callee_small_struct_ret
177   ; RV32I: bb.1 (%ir-block.0):
178   ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
179   ; RV32I-NEXT:   [[C1:%[0-9]+]]:_(p0) = G_CONSTANT i32 0
180   ; RV32I-NEXT:   $x10 = COPY [[C]](s32)
181   ; RV32I-NEXT:   $x11 = COPY [[C1]](p0)
182   ; RV32I-NEXT:   PseudoRET implicit $x10, implicit $x11
183   ret %struct.small { i32 1, ptr null }
186 define i32 @caller_small_struct_ret() nounwind {
187   ; RV32I-LABEL: name: caller_small_struct_ret
188   ; RV32I: bb.1 (%ir-block.0):
189   ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_small_struct_ret, implicit-def $x1, implicit-def $x10, implicit-def $x11
190   ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $x10
191   ; RV32I-NEXT:   [[COPY1:%[0-9]+]]:_(p0) = COPY $x11
192   ; RV32I-NEXT:   [[PTRTOINT:%[0-9]+]]:_(s32) = G_PTRTOINT [[COPY1]](p0)
193   ; RV32I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[PTRTOINT]]
194   ; RV32I-NEXT:   $x10 = COPY [[ADD]](s32)
195   ; RV32I-NEXT:   PseudoRET implicit $x10
196   %1 = call %struct.small @callee_small_struct_ret()
197   %2 = extractvalue %struct.small %1, 0
198   %3 = extractvalue %struct.small %1, 1
199   %4 = ptrtoint ptr %3 to i32
200   %5 = add i32 %2, %4
201   ret i32 %5
204 ; Check return of >2x xlen structs
206 %struct.large = type { i32, i32, i32, i32 }
208 define void @callee_large_struct_ret(ptr noalias sret(%struct.large) %agg.result) nounwind {
209   ; RV32I-LABEL: name: callee_large_struct_ret
210   ; RV32I: bb.1 (%ir-block.0):
211   ; RV32I-NEXT:   liveins: $x10
212   ; RV32I-NEXT: {{  $}}
213   ; RV32I-NEXT:   [[COPY:%[0-9]+]]:_(p0) = COPY $x10
214   ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
215   ; RV32I-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
216   ; RV32I-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
217   ; RV32I-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
218   ; RV32I-NEXT:   G_STORE [[C]](s32), [[COPY]](p0) :: (store (s32) into %ir.agg.result)
219   ; RV32I-NEXT:   [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
220   ; RV32I-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = nuw G_PTR_ADD [[COPY]], [[C4]](s32)
221   ; RV32I-NEXT:   G_STORE [[C1]](s32), [[PTR_ADD]](p0) :: (store (s32) into %ir.b)
222   ; RV32I-NEXT:   [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
223   ; RV32I-NEXT:   [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw G_PTR_ADD [[COPY]], [[C5]](s32)
224   ; RV32I-NEXT:   G_STORE [[C2]](s32), [[PTR_ADD1]](p0) :: (store (s32) into %ir.c)
225   ; RV32I-NEXT:   [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
226   ; RV32I-NEXT:   [[PTR_ADD2:%[0-9]+]]:_(p0) = nuw G_PTR_ADD [[COPY]], [[C6]](s32)
227   ; RV32I-NEXT:   G_STORE [[C3]](s32), [[PTR_ADD2]](p0) :: (store (s32) into %ir.d)
228   ; RV32I-NEXT:   PseudoRET
229   store i32 1, ptr %agg.result, align 4
230   %b = getelementptr inbounds %struct.large, ptr %agg.result, i32 0, i32 1
231   store i32 2, ptr %b, align 4
232   %c = getelementptr inbounds %struct.large, ptr %agg.result, i32 0, i32 2
233   store i32 3, ptr %c, align 4
234   %d = getelementptr inbounds %struct.large, ptr %agg.result, i32 0, i32 3
235   store i32 4, ptr %d, align 4
236   ret void
239 define i32 @caller_large_struct_ret() nounwind {
240   ; RV32I-LABEL: name: caller_large_struct_ret
241   ; RV32I: bb.1 (%ir-block.0):
242   ; RV32I-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
243   ; RV32I-NEXT:   $x10 = COPY [[FRAME_INDEX]](p0)
244   ; RV32I-NEXT:   PseudoCALL target-flags(riscv-call) @callee_large_struct_ret, implicit-def $x1, implicit $x10
245   ; RV32I-NEXT:   [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[FRAME_INDEX]](p0) :: (dereferenceable load (s32) from %ir.1)
246   ; RV32I-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
247   ; RV32I-NEXT:   [[PTR_ADD:%[0-9]+]]:_(p0) = nuw G_PTR_ADD [[FRAME_INDEX]], [[C]](s32)
248   ; RV32I-NEXT:   [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD]](p0) :: (dereferenceable load (s32) from %ir.3)
249   ; RV32I-NEXT:   [[ADD:%[0-9]+]]:_(s32) = G_ADD [[LOAD]], [[LOAD1]]
250   ; RV32I-NEXT:   $x10 = COPY [[ADD]](s32)
251   ; RV32I-NEXT:   PseudoRET implicit $x10
252   %1 = alloca %struct.large
253   call void @callee_large_struct_ret(ptr sret(%struct.large) %1)
254   %2 = load i32, ptr %1
255   %3 = getelementptr inbounds %struct.large, ptr %1, i32 0, i32 3
256   %4 = load i32, ptr %3
257   %5 = add i32 %2, %4
258   ret i32 %5