1 ; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-APPLE %s 2 ; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-O0 %s 3 4 declare i8* @malloc(i64) 5 declare void @free(i8*) 6 %swift_error = type { i64, i8 } 7 %struct.S = type { i32, i32, i32, i32, i32, i32 } 8 9 ; This tests the basic usage of a swifterror parameter. "foo" is the function 10 ; that takes a swifterror parameter and "caller" is the caller of "foo". 11 define float @foo(%swift_error** swifterror %error_ptr_ref) { 12 ; CHECK-APPLE-LABEL: foo: 13 ; CHECK-APPLE: mov r0, #16 14 ; CHECK-APPLE: malloc 15 ; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], #1 16 ; CHECK-APPLE-DAG: mov r6, r{{.*}} 17 ; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8] 18 19 ; CHECK-O0-LABEL: foo: 20 ; CHECK-O0: mov r{{.*}}, #16 21 ; CHECK-O0: malloc 22 ; CHECK-O0: mov [[ID2:r[0-9]+]], r0 23 ; CHECK-O0: mov [[ID:r[0-9]+]], #1 24 ; CHECK-O0: strb [[ID]], [r0, #8] 25 ; CHECK-O0: mov r6, [[ID2]] 26 entry: 27 %call = call i8* @malloc(i64 16) 28 %call.0 = bitcast i8* %call to %swift_error* 29 store %swift_error* %call.0, %swift_error** %error_ptr_ref 30 %tmp = getelementptr inbounds i8, i8* %call, i64 8 31 store i8 1, i8* %tmp 32 ret float 1.0 33 } 34 35 ; "caller" calls "foo" that takes a swifterror parameter. 36 define float @caller(i8* %error_ref) { 37 ; CHECK-APPLE-LABEL: caller: 38 ; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0 39 ; CHECK-APPLE-DAG: mov r6, #0 40 ; CHECK-APPLE: bl {{.*}}foo 41 ; CHECK-APPLE: cmp r6, #0 42 ; Access part of the error object and save it to error_ref 43 ; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8] 44 ; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]] 45 ; CHECK-APPLE: mov r0, r6 46 ; CHECK_APPLE: bl {{.*}}free 47 48 ; CHECK-O0-LABEL: caller: 49 ; spill r0 50 ; CHECK-O0-DAG: str r0, 51 ; CHECK-O0-DAG: mov r6, #0 52 ; CHECK-O0: bl {{.*}}foo 53 ; CHECK-O0: mov r{{.*}}, r6 54 ; CHECK-O0: bne 55 ; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8] 56 ; reload r0 57 ; CHECK-O0: ldr [[ID:r[0-9]+]], 58 ; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]] 59 ; CHECK-O0: mov r0, 60 ; CHECK-O0: free 61 entry: 62 %error_ptr_ref = alloca swifterror %swift_error* 63 store %swift_error* null, %swift_error** %error_ptr_ref 64 %call = call float @foo(%swift_error** swifterror %error_ptr_ref) 65 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 66 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 67 %tmp = bitcast %swift_error* %error_from_foo to i8* 68 br i1 %had_error_from_foo, label %handler, label %cont 69 cont: 70 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 71 %t = load i8, i8* %v1 72 store i8 %t, i8* %error_ref 73 br label %handler 74 handler: 75 call void @free(i8* %tmp) 76 ret float 1.0 77 } 78 79 ; "caller2" is the caller of "foo", it calls "foo" inside a loop. 80 define float @caller2(i8* %error_ref) { 81 ; CHECK-APPLE-LABEL: caller2: 82 ; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0 83 ; CHECK-APPLE-DAG: mov r6, #0 84 ; CHECK-APPLE: bl {{.*}}foo 85 ; CHECK-APPLE: cmp r6, #0 86 ; CHECK-APPLE: bne 87 ; Access part of the error object and save it to error_ref 88 ; CHECK-APPLE: ldrb [[CODE:r[0-9]+]], [r6, #8] 89 ; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]] 90 ; CHECK-APPLE: mov r0, r6 91 ; CHECK_APPLE: bl {{.*}}free 92 93 ; CHECK-O0-LABEL: caller2: 94 ; spill r0 95 ; CHECK-O0-DAG: str r0, 96 ; CHECK-O0-DAG: mov r6, #0 97 ; CHECK-O0: bl {{.*}}foo 98 ; CHECK-O0: mov r{{.*}}, r6 99 ; CHECK-O0: bne 100 ; CHECK-O0: ble 101 ; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8] 102 ; reload r0 103 ; CHECK-O0: ldr [[ID:r[0-9]+]], 104 ; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]] 105 ; CHECK-O0: mov r0, 106 ; CHECK-O0: free 107 entry: 108 %error_ptr_ref = alloca swifterror %swift_error* 109 br label %bb_loop 110 bb_loop: 111 store %swift_error* null, %swift_error** %error_ptr_ref 112 %call = call float @foo(%swift_error** swifterror %error_ptr_ref) 113 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 114 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 115 %tmp = bitcast %swift_error* %error_from_foo to i8* 116 br i1 %had_error_from_foo, label %handler, label %cont 117 cont: 118 %cmp = fcmp ogt float %call, 1.000000e+00 119 br i1 %cmp, label %bb_end, label %bb_loop 120 bb_end: 121 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 122 %t = load i8, i8* %v1 123 store i8 %t, i8* %error_ref 124 br label %handler 125 handler: 126 call void @free(i8* %tmp) 127 ret float 1.0 128 } 129 130 ; "foo_if" is a function that takes a swifterror parameter, it sets swifterror 131 ; under a certain condition. 132 define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) { 133 ; CHECK-APPLE-LABEL: foo_if: 134 ; CHECK-APPLE: cmp r0, #0 135 ; CHECK-APPLE: eq 136 ; CHECK-APPLE: mov r0, #16 137 ; CHECK-APPLE: malloc 138 ; CHECK-APPLE: mov [[ID:r[0-9]+]], #1 139 ; CHECK-APPLE-DAG: mov r6, r{{.*}} 140 ; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8] 141 142 ; CHECK-O0-LABEL: foo_if: 143 ; CHECK-O0: cmp r0, #0 144 ; spill to stack 145 ; CHECK-O0: str r6 146 ; CHECK-O0: beq 147 ; CHECK-O0: mov r0, #16 148 ; CHECK-O0: malloc 149 ; CHECK-O0: mov [[ID:r[0-9]+]], r0 150 ; CHECK-O0: mov [[ID2:[a-z0-9]+]], #1 151 ; CHECK-O0: strb [[ID2]], [r0, #8] 152 ; CHECK-O0: mov r6, [[ID]] 153 ; reload from stack 154 ; CHECK-O0: ldr r6 155 entry: 156 %cond = icmp ne i32 %cc, 0 157 br i1 %cond, label %gen_error, label %normal 158 159 gen_error: 160 %call = call i8* @malloc(i64 16) 161 %call.0 = bitcast i8* %call to %swift_error* 162 store %swift_error* %call.0, %swift_error** %error_ptr_ref 163 %tmp = getelementptr inbounds i8, i8* %call, i64 8 164 store i8 1, i8* %tmp 165 ret float 1.0 166 167 normal: 168 ret float 0.0 169 } 170 171 ; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror 172 ; under a certain condition inside a loop. 173 define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) { 174 ; CHECK-APPLE-LABEL: foo_loop: 175 ; CHECK-APPLE: mov [[CODE:r[0-9]+]], r0 176 ; swifterror is kept in a register 177 ; CHECK-APPLE: mov [[ID:r[0-9]+]], r6 178 ; CHECK-APPLE: cmp [[CODE]], #0 179 ; CHECK-APPLE: beq 180 ; CHECK-APPLE: mov r0, #16 181 ; CHECK-APPLE: malloc 182 ; CHECK-APPLE: strb r{{.*}}, [{{.*}}[[ID]], #8] 183 ; CHECK-APPLE: ble 184 ; CHECK-APPLE: mov r6, [[ID]] 185 186 ; CHECK-O0-LABEL: foo_loop: 187 ; CHECK-O0: mov r{{.*}}, r6 188 ; CHECK-O0: cmp r{{.*}}, #0 189 ; CHECK-O0: beq 190 ; CHECK-O0-DAG: movw r{{.*}}, #1 191 ; CHECK-O0-DAG: mov r{{.*}}, #16 192 ; CHECK-O0: malloc 193 ; CHECK-O0-DAG: mov [[ID:r[0-9]+]], r0 194 ; CHECK-O0-DAG: ldr [[ID2:r[0-9]+]], [sp{{.*}}] 195 ; CHECK-O0: strb [[ID2]], [{{.*}}[[ID]], #8] 196 ; spill r0 197 ; CHECK-O0: str r0, [sp{{.*}}] 198 ; CHECK-O0: vcmpe 199 ; CHECK-O0: ble 200 ; reload from stack 201 ; CHECK-O0: ldr r6 202 entry: 203 br label %bb_loop 204 205 bb_loop: 206 %cond = icmp ne i32 %cc, 0 207 br i1 %cond, label %gen_error, label %bb_cont 208 209 gen_error: 210 %call = call i8* @malloc(i64 16) 211 %call.0 = bitcast i8* %call to %swift_error* 212 store %swift_error* %call.0, %swift_error** %error_ptr_ref 213 %tmp = getelementptr inbounds i8, i8* %call, i64 8 214 store i8 1, i8* %tmp 215 br label %bb_cont 216 217 bb_cont: 218 %cmp = fcmp ogt float %cc2, 1.000000e+00 219 br i1 %cmp, label %bb_end, label %bb_loop 220 bb_end: 221 ret float 0.0 222 } 223 224 ; "foo_sret" is a function that takes a swifterror parameter, it also has a sret 225 ; parameter. 226 define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) { 227 ; CHECK-APPLE-LABEL: foo_sret: 228 ; CHECK-APPLE: mov [[SRET:r[0-9]+]], r0 229 ; CHECK-APPLE: mov r0, #16 230 ; CHECK-APPLE: malloc 231 ; CHECK-APPLE: mov [[REG:r[0-9]+]], #1 232 ; CHECK-APPLE-DAG: mov r6, r0 233 ; CHECK-APPLE-DAG: strb [[REG]], [r0, #8] 234 ; CHECK-APPLE-DAG: str r{{.*}}, [{{.*}}[[SRET]], #4] 235 236 ; CHECK-O0-LABEL: foo_sret: 237 ; CHECK-O0: mov r{{.*}}, #16 238 ; spill to stack: sret and val1 239 ; CHECK-O0-DAG: str r0 240 ; CHECK-O0-DAG: str r1 241 ; CHECK-O0: malloc 242 ; CHECK-O0: mov [[ID:r[0-9]+]], #1 243 ; CHECK-O0: strb [[ID]], [r0, #8] 244 ; reload from stack: sret and val1 245 ; CHECK-O0: ldr 246 ; CHECK-O0: ldr 247 ; CHECK-O0: str r{{.*}}, [{{.*}}, #4] 248 ; CHECK-O0: mov r6 249 entry: 250 %call = call i8* @malloc(i64 16) 251 %call.0 = bitcast i8* %call to %swift_error* 252 store %swift_error* %call.0, %swift_error** %error_ptr_ref 253 %tmp = getelementptr inbounds i8, i8* %call, i64 8 254 store i8 1, i8* %tmp 255 %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1 256 store i32 %val1, i32* %v2 257 ret void 258 } 259 260 ; "caller3" calls "foo_sret" that takes a swifterror parameter. 261 define float @caller3(i8* %error_ref) { 262 ; CHECK-APPLE-LABEL: caller3: 263 ; CHECK-APPLE: mov [[ID:r[0-9]+]], r0 264 ; CHECK-APPLE: mov r6, #0 265 ; CHECK-APPLE: bl {{.*}}foo_sret 266 ; CHECK-APPLE: cmp r6, #0 267 ; Access part of the error object and save it to error_ref 268 ; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8] 269 ; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]] 270 ; CHECK-APPLE: mov r0, r6 271 ; CHECK_APPLE: bl {{.*}}free 272 273 ; CHECK-O0-LABEL: caller3: 274 ; CHECK-O0-DAG: mov r6, #0 275 ; CHECK-O0-DAG: mov r0 276 ; CHECK-O0-DAG: mov r1 277 ; CHECK-O0: bl {{.*}}foo_sret 278 ; CHECK-O0: mov [[ID2:r[0-9]+]], r6 279 ; CHECK-O0: cmp [[ID2]] 280 ; CHECK-O0: bne 281 ; Access part of the error object and save it to error_ref 282 ; CHECK-O0: ldrb [[CODE:r[0-9]+]] 283 ; CHECK-O0: ldr [[ID:r[0-9]+]] 284 ; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]] 285 ; CHECK-O0: mov r0, 286 ; CHECK_O0: bl {{.*}}free 287 entry: 288 %s = alloca %struct.S, align 8 289 %error_ptr_ref = alloca swifterror %swift_error* 290 store %swift_error* null, %swift_error** %error_ptr_ref 291 call void @foo_sret(%struct.S* sret %s, i32 1, %swift_error** swifterror %error_ptr_ref) 292 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 293 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 294 %tmp = bitcast %swift_error* %error_from_foo to i8* 295 br i1 %had_error_from_foo, label %handler, label %cont 296 cont: 297 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 298 %t = load i8, i8* %v1 299 store i8 %t, i8* %error_ref 300 br label %handler 301 handler: 302 call void @free(i8* %tmp) 303 ret float 1.0 304 } 305 306 ; "foo_vararg" is a function that takes a swifterror parameter, it also has 307 ; variable number of arguments. 308 declare void @llvm.va_start(i8*) nounwind 309 define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) { 310 ; CHECK-APPLE-LABEL: foo_vararg: 311 ; CHECK-APPLE: mov r0, #16 312 ; CHECK-APPLE: malloc 313 ; CHECK-APPLE: mov [[REG:r[0-9]+]], r0 314 ; CHECK-APPLE: mov [[ID:r[0-9]+]], #1 315 ; CHECK-APPLE-DAG: strb [[ID]], [{{.*}}[[REG]], #8] 316 ; CHECK-APPLE-DAG: mov r6, [[REG]] 317 318 entry: 319 %call = call i8* @malloc(i64 16) 320 %call.0 = bitcast i8* %call to %swift_error* 321 store %swift_error* %call.0, %swift_error** %error_ptr_ref 322 %tmp = getelementptr inbounds i8, i8* %call, i64 8 323 store i8 1, i8* %tmp 324 325 %args = alloca i8*, align 8 326 %a10 = alloca i32, align 4 327 %a11 = alloca i32, align 4 328 %a12 = alloca i32, align 4 329 %v10 = bitcast i8** %args to i8* 330 call void @llvm.va_start(i8* %v10) 331 %v11 = va_arg i8** %args, i32 332 store i32 %v11, i32* %a10, align 4 333 %v12 = va_arg i8** %args, i32 334 store i32 %v12, i32* %a11, align 4 335 %v13 = va_arg i8** %args, i32 336 store i32 %v13, i32* %a12, align 4 337 338 ret float 1.0 339 } 340 341 ; "caller4" calls "foo_vararg" that takes a swifterror parameter. 342 define float @caller4(i8* %error_ref) { 343 ; CHECK-APPLE-LABEL: caller4: 344 ; CHECK-APPLE: mov [[ID:r[0-9]+]], r0 345 ; CHECK-APPLE: mov r6, #0 346 ; CHECK-APPLE: bl {{.*}}foo_vararg 347 ; CHECK-APPLE: cmp r6, #0 348 ; Access part of the error object and save it to error_ref 349 ; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8] 350 ; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]] 351 ; CHECK-APPLE: mov r0, r6 352 ; CHECK_APPLE: bl {{.*}}free 353 entry: 354 %error_ptr_ref = alloca swifterror %swift_error* 355 store %swift_error* null, %swift_error** %error_ptr_ref 356 357 %a10 = alloca i32, align 4 358 %a11 = alloca i32, align 4 359 %a12 = alloca i32, align 4 360 store i32 10, i32* %a10, align 4 361 store i32 11, i32* %a11, align 4 362 store i32 12, i32* %a12, align 4 363 %v10 = load i32, i32* %a10, align 4 364 %v11 = load i32, i32* %a11, align 4 365 %v12 = load i32, i32* %a12, align 4 366 367 %call = call float (%swift_error**, ...) @foo_vararg(%swift_error** swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12) 368 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 369 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 370 %tmp = bitcast %swift_error* %error_from_foo to i8* 371 br i1 %had_error_from_foo, label %handler, label %cont 372 373 cont: 374 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 375 %t = load i8, i8* %v1 376 store i8 %t, i8* %error_ref 377 br label %handler 378 handler: 379 call void @free(i8* %tmp) 380 ret float 1.0 381 } 382