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