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