1 ; RUN: llc -mtriple=mips-linux-gnu -relocation-model=static < %s \
2 ; RUN: | FileCheck --check-prefixes=ALL,O32,O32-BE %s
3 ; RUN: llc -mtriple=mipsel-linux-gnu -relocation-model=static < %s \
4 ; RUN: | FileCheck --check-prefixes=ALL,O32,O32-LE %s
6 ; RUN-TODO: llc -mtriple=mips64-linux-gnu -relocation-model=static -target-abi o32 < %s \
7 ; RUN-TODO: | FileCheck --check-prefixes=ALL,O32 %s
8 ; RUN-TODO: llc -mtriple=mips64el-linux-gnu -relocation-model=static -target-abi o32 < %s \
9 ; RUN-TODO: | FileCheck --check-prefixes=ALL,O32 %s
11 ; RUN: llc -mtriple=mips64-linux-gnu -relocation-model=static -target-abi n32 < %s \
12 ; RUN: | FileCheck --check-prefixes=ALL,N32,N32-BE %s
13 ; RUN: llc -mtriple=mips64el-linux-gnu -relocation-model=static -target-abi n32 < %s \
14 ; RUN: | FileCheck --check-prefixes=ALL,N32,N32-LE %s
16 ; RUN: llc -mtriple=mips64-linux-gnu -relocation-model=static -target-abi n64 < %s \
17 ; RUN: | FileCheck --check-prefixes=ALL,N64,N64-BE %s
18 ; RUN: llc -mtriple=mips64el-linux-gnu -relocation-model=static -target-abi n64 < %s \
19 ; RUN: | FileCheck --check-prefixes=ALL,N64,N64-LE %s
21 ; Test struct returns for all ABI's and byte orders.
23 @struct_byte = global {i8} zeroinitializer
24 @struct_2byte = global {i8,i8} zeroinitializer
25 @struct_3xi16 = global {[3 x i16]} zeroinitializer
26 @struct_6xi32 = global {[6 x i32]} zeroinitializer
27 @struct_128xi16 = global {[128 x i16]} zeroinitializer
29 declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1)
31 define inreg {i8} @ret_struct_i8() nounwind {
33 %0 = load volatile {i8}, {i8}* @struct_byte
37 ; ALL-LABEL: ret_struct_i8:
38 ; O32-DAG: lui [[R1:\$[0-9]+]], %hi(struct_byte)
39 ; O32-DAG: lbu $2, %lo(struct_byte)([[R1]])
41 ; N32-LE-DAG: lui [[R1:\$[0-9]+]], %hi(struct_byte)
42 ; N32-LE-DAG: lb $2, %lo(struct_byte)([[R1]])
44 ; N32-BE-DAG: lui [[R1:\$[0-9]+]], %hi(struct_byte)
45 ; N32-BE-DAG: lb [[R2:\$[0-9]+]], %lo(struct_byte)([[R1]])
46 ; N32-BE-DAG: dsll $2, [[R2]], 56
48 ; N64-LE-DAG: lb $2, %lo(struct_byte)(${{[0-9]+}})
50 ; N64-BE-DAG: lb [[R1:\$[0-9]+]], %lo(struct_byte)(${{[0-9]+}})
51 ; N64-BE-DAG: dsll $2, [[R1]], 56
53 ; This test is based on the way clang currently lowers {i8,i8} to {i16}.
54 ; FIXME: It should probably work for without any lowering too but this doesn't
55 ; work as expected. Each member gets mapped to a register rather than
56 ; packed into a single register.
57 define inreg {i16} @ret_struct_i16() nounwind {
59 %retval = alloca {i8,i8}, align 1
60 %0 = bitcast {i8,i8}* %retval to i8*
61 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* getelementptr inbounds ({i8,i8}, {i8,i8}* @struct_2byte, i32 0, i32 0), i64 2, i1 false)
62 %1 = bitcast {i8,i8}* %retval to {i16}*
63 %2 = load volatile {i16}, {i16}* %1
67 ; ALL-LABEL: ret_struct_i16:
68 ; O32-DAG: lui [[R1:\$[0-9]+]], %hi(struct_2byte)
69 ; O32-DAG: lhu [[R2:\$[0-9]+]], %lo(struct_2byte)([[R1]])
70 ; O32-DAG: sh [[R2]], 0([[SP:\$sp]])
71 ; O32-DAG: lhu $2, 0([[SP:\$sp]])
73 ; N32-LE-DAG: lui [[R1:\$[0-9]+]], %hi(struct_2byte)
74 ; N32-LE-DAG: lhu [[R2:\$[0-9]+]], %lo(struct_2byte)([[R1]])
75 ; N32-LE-DAG: sh [[R2]], 8([[SP:\$sp]])
76 ; N32-LE-DAG: lh $2, 8([[SP:\$sp]])
78 ; N32-BE-DAG: lui [[R1:\$[0-9]+]], %hi(struct_2byte)
79 ; N32-BE-DAG: lhu [[R2:\$[0-9]+]], %lo(struct_2byte)([[R1]])
80 ; N32-BE-DAG: sh [[R2]], 8([[SP:\$sp]])
81 ; N32-BE-DAG: lh [[R3:\$[0-9]+]], 8([[SP:\$sp]])
82 ; N32-BE-DAG: dsll $2, [[R3]], 48
84 ; N64-LE-DAG: daddiu $[[R0:[0-9]+]], ${{[0-9]+}}, %hi(struct_2byte)
85 ; N64-LE-DAG: dsll [[R1:\$[0-9]]], $[[R0]], 16
86 ; N64-LE-DAG: lhu [[R2:\$[0-9]+]], %lo(struct_2byte)([[R1]])
87 ; N64-LE-DAG: sh [[R2]], 8([[SP:\$sp]])
88 ; N64-LE-DAG: lh $2, 8([[SP:\$sp]])
90 ; N64-BE-DAG: daddiu $[[R0:[0-9]+]], ${{[0-9]+}}, %hi(struct_2byte)
91 ; N64-BE-DAG: dsll $[[R1:[0-9]]], $[[R0]], 16
92 ; N64-BE-DAG: lhu [[R2:\$[0-9]+]], %lo(struct_2byte)($[[R1]])
93 ; N64-BE-DAG: sh [[R2]], 8([[SP:\$sp]])
94 ; N64-BE-DAG: lh [[R3:\$[0-9]+]], 8([[SP:\$sp]])
95 ; N64-BE-DAG: dsll $2, [[R3]], 48
97 ; Ensure that structures bigger than 32-bits but smaller than 64-bits are
98 ; also returned in the upper bits on big endian targets. Previously, these were
99 ; missed by the CCPromoteToType and the shift didn't happen.
100 define inreg {i48} @ret_struct_3xi16() nounwind {
102 %0 = load volatile i48, i48* bitcast ({[3 x i16]}* @struct_3xi16 to i48*), align 2
103 %1 = insertvalue {i48} undef, i48 %0, 0
107 ; ALL-LABEL: ret_struct_3xi16:
109 ; O32-BE-DAG: lui [[PTR_HI:\$[0-9]+]], %hi(struct_3xi16)
110 ; O32-BE-DAG: addiu [[PTR_LO:\$[0-9]+]], [[PTR_HI]], %lo(struct_3xi16)
111 ; O32-BE-DAG: lhu [[R1:\$[0-9]+]], 4([[PTR_LO]])
112 ; O32-BE-DAG: lw [[R2:\$[0-9]+]], %lo(struct_3xi16)([[PTR_HI]])
113 ; O32-BE-DAG: sll [[R3:\$[0-9]+]], [[R2]], 16
114 ; O32-BE-DAG: or $3, [[R1]], [[R3]]
115 ; O32-BE-DAG: srl $2, [[R2]], 16
117 ; O32-LE-DAG: lui [[PTR_HI:\$[0-9]+]], %hi(struct_3xi16)
118 ; O32-LE-DAG: addiu [[PTR_LO:\$[0-9]+]], [[PTR_HI]], %lo(struct_3xi16)
119 ; O32-LE-DAG: lhu $3, 4([[PTR_LO]])
120 ; O32-LE-DAG: lw $2, %lo(struct_3xi16)([[PTR_HI]])
122 ; N32-LE-DAG: lui [[PTR_HI:\$[0-9]+]], %hi(struct_3xi16)
123 ; N32-LE-DAG: addiu [[PTR_LO:\$[0-9]+]], [[PTR_HI]], %lo(struct_3xi16)
124 ; N32-LE-DAG: lh [[R1:\$[0-9]+]], 4([[PTR_LO]])
125 ; N32-LE-DAG: lwu [[R2:\$[0-9]+]], %lo(struct_3xi16)([[PTR_HI]])
126 ; N32-LE-DAG: dsll [[R3:\$[0-9]+]], [[R1]], 32
127 ; N32-LE-DAG: or $2, [[R2]], [[R3]]
129 ; N32-BE-DAG: lui [[PTR_HI:\$[0-9]+]], %hi(struct_3xi16)
130 ; N32-BE-DAG: addiu [[PTR_LO:\$[0-9]+]], [[PTR_HI]], %lo(struct_3xi16)
131 ; N32-BE-DAG: lw [[R1:\$[0-9]+]], %lo(struct_3xi16)([[PTR_HI]])
132 ; N32-BE-DAG: dsll [[R2:\$[0-9]+]], [[R1]], 16
133 ; N32-BE-DAG: lhu [[R3:\$[0-9]+]], 4([[PTR_LO]])
134 ; N32-BE-DAG: or [[R4:\$[0-9]+]], [[R3]], [[R2]]
135 ; N32-BE-DAG: dsll $2, [[R4]], 16
137 ; N64-LE-DAG: daddiu [[PTR:\$[0-9]+]], [[R0:\$[0-9]+]], %lo(struct_3xi16)
138 ; N64-LE-DAG: lh [[R1:\$[0-9]+]], 4([[PTR]])
139 ; N64-LE-DAG: lwu [[R2:\$[0-9]+]], %lo(struct_3xi16)([[R0]])
140 ; N64-LE-DAG: dsll [[R3:\$[0-9]+]], [[R1]], 32
141 ; N64-LE-DAG: or $2, [[R2]], [[R3]]
143 ; N64-BE-DAG: daddiu [[PTR:\$[0-9]+]], [[R0:\$[0-9]+]], %lo(struct_3xi16)
144 ; N64-BE-DAG: lw [[R1:\$[0-9]+]], %lo(struct_3xi16)([[R0]])
145 ; N64-BE-DAG: dsll [[R2:\$[0-9]+]], [[R1]], 16
146 ; N64-BE-DAG: lhu [[R3:\$[0-9]+]], 4([[PTR]])
147 ; N64-BE-DAG: or [[R4:\$[0-9]+]], [[R3]], [[R2]]
148 ; N64-BE-DAG: dsll $2, [[R4]], 16
150 ; Ensure that large structures (>128-bit) are returned indirectly.
151 ; We pick an extremely large structure so we don't have to match inlined memcpy's.
152 define void @ret_struct_128xi16({[128 x i16]}* sret %returnval) {
154 %0 = bitcast {[128 x i16]}* %returnval to i8*
155 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 2 %0, i8* align 2 bitcast ({[128 x i16]}* @struct_128xi16 to i8*), i64 256, i1 false)
159 ; ALL-LABEL: ret_struct_128xi16:
161 ; sret pointer is already in $4
162 ; O32-DAG: lui [[PTR:\$[0-9]+]], %hi(struct_128xi16)
163 ; O32-DAG: addiu $5, [[PTR]], %lo(struct_128xi16)
166 ; sret pointer is already in $4
167 ; N32-DAG: lui [[PTR_HI:\$[0-9]+]], %hi(struct_128xi16)
168 ; N32-DAG: addiu [[PTR:\$[0-9]+]], [[PTR_HI]], %lo(struct_128xi16)
171 ; sret pointer is already in $4
172 ; N64-DAG: lui ${{[0-9]}}, %highest(struct_128xi16)
175 ; Ensure that large structures (>128-bit) are returned indirectly.
176 ; This will generate inlined memcpy's anyway so pick the smallest large
178 ; This time we let the backend lower the sret argument.
179 define {[6 x i32]} @ret_struct_6xi32() {
181 %0 = load volatile {[6 x i32]}, {[6 x i32]}* @struct_6xi32, align 2
185 ; ALL-LABEL: ret_struct_6xi32:
187 ; sret pointer is already in $4
188 ; O32-DAG: lui [[PTR_HI:\$[0-9]+]], %hi(struct_6xi32)
189 ; O32-DAG: addiu [[PTR:\$[0-9]+]], [[PTR_HI]], %lo(struct_6xi32)
190 ; O32-DAG: lw [[T0:\$[0-9]+]], %lo(struct_6xi32)([[PTR]])
191 ; O32-DAG: lw [[T1:\$[0-9]+]], 4([[PTR]])
192 ; O32-DAG: lw [[T2:\$[0-9]+]], 8([[PTR]])
193 ; O32-DAG: lw [[T3:\$[0-9]+]], 12([[PTR]])
194 ; O32-DAG: lw [[T4:\$[0-9]+]], 16([[PTR]])
195 ; O32-DAG: lw [[T5:\$[0-9]+]], 20([[PTR]])
196 ; O32-DAG: sw [[T0]], 0($4)
197 ; O32-DAG: sw [[T1]], 4($4)
198 ; O32-DAG: sw [[T2]], 8($4)
199 ; O32-DAG: sw [[T3]], 12($4)
200 ; O32-DAG: sw [[T4]], 16($4)
201 ; O32-DAG: sw [[T5]], 20($4)
203 ; FIXME: This signext isn't necessary. Like integers, pointers are
204 ; but unlike integers, pointers cannot have the signext attribute.
205 ; In this case we don't have anywhere to put the signext either since
206 ; the sret argument is invented by the backend.
207 ; N32-DAG: sll [[RET_PTR:\$[0-9]+]], $4, 0
208 ; N32-DAG: lui [[PTR_HI:\$[0-9]+]], %hi(struct_6xi32)
209 ; N32-DAG: addiu [[PTR:\$[0-9]+]], [[PTR_HI]], %lo(struct_6xi32)
210 ; N32-DAG: lw [[T0:\$[0-9]+]], %lo(struct_6xi32)([[PTR]])
211 ; N32-DAG: lw [[T1:\$[0-9]+]], 4([[PTR]])
212 ; N32-DAG: lw [[T2:\$[0-9]+]], 8([[PTR]])
213 ; N32-DAG: lw [[T3:\$[0-9]+]], 12([[PTR]])
214 ; N32-DAG: lw [[T4:\$[0-9]+]], 16([[PTR]])
215 ; N32-DAG: lw [[T5:\$[0-9]+]], 20([[PTR]])
216 ; N32-DAG: sw [[T0]], 0([[RET_PTR]])
217 ; N32-DAG: sw [[T1]], 4([[RET_PTR]])
218 ; N32-DAG: sw [[T2]], 8([[RET_PTR]])
219 ; N32-DAG: sw [[T3]], 12([[RET_PTR]])
220 ; N32-DAG: sw [[T4]], 16([[RET_PTR]])
221 ; N32-DAG: sw [[T5]], 20([[RET_PTR]])
223 ; sret pointer is already in $4
224 ; N64-DAG: lui [[PTR_HI:\$[0-9]+]], %highest(struct_6xi32)
225 ; N64-DAG: daddiu [[PTR:\$[0-9]+]], [[PTR_HI]], %lo(struct_6xi32)
226 ; N64-DAG: lw [[T1:\$[0-9]+]], 4([[PTR]])
227 ; N64-DAG: lw [[T2:\$[0-9]+]], 8([[PTR]])
228 ; N64-DAG: lw [[T3:\$[0-9]+]], 12([[PTR]])
229 ; N64-DAG: lw [[T4:\$[0-9]+]], 16([[PTR]])
230 ; N64-DAG: lw [[T5:\$[0-9]+]], 20([[PTR]])
231 ; N64-DAG: lw [[T0:\$[0-9]+]], %lo(struct_6xi32)([[PTR_HI]])
232 ; N64-DAG: sw [[T0]], 0($4)
233 ; N64-DAG: sw [[T1]], 4($4)
234 ; N64-DAG: sw [[T2]], 8($4)
235 ; N64-DAG: sw [[T3]], 12($4)
236 ; N64-DAG: sw [[T4]], 16($4)
237 ; N64-DAG: sw [[T5]], 20($4)