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