1; RUN: llc -verify-machineinstrs -frame-pointer=all -global-isel < %s -mtriple=aarch64-apple-ios -disable-post-ra | FileCheck %s 2 3declare i8* @malloc(i64) 4declare void @free(i8*) 5%swift_error = type {i64, i8} 6 7; This tests the basic usage of a swifterror parameter. "foo" is the function 8; that takes a swifterror parameter and "caller" is the caller of "foo". 9define float @foo(%swift_error** swifterror %error_ptr_ref) { 10; CHECK-LABEL: foo: 11; CHECK: mov w0, #16 12; CHECK: malloc 13; CHECK: mov [[ID:w[0-9]+]], #1 14; CHECK: strb [[ID]], [x0, #8] 15; CHECK: mov x21, x0 16; CHECK-NOT: x21 17 18entry: 19 %call = call i8* @malloc(i64 16) 20 %call.0 = bitcast i8* %call to %swift_error* 21 store %swift_error* %call.0, %swift_error** %error_ptr_ref 22 %tmp = getelementptr inbounds i8, i8* %call, i64 8 23 store i8 1, i8* %tmp 24 ret float 1.0 25} 26 27; "caller" calls "foo" that takes a swifterror parameter. 28define float @caller(i8* %error_ref) { 29; CHECK-LABEL: caller: 30; CHECK: mov [[ID:x[0-9]+]], x0 31; CHECK: bl {{.*}}foo 32; CHECK: mov x0, x21 33; CHECK: cbnz x21 34; Access part of the error object and save it to error_ref 35; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8] 36; CHECK: strb [[CODE]], [{{.*}}[[ID]]] 37; CHECK: bl {{.*}}free 38 39entry: 40 %error_ptr_ref = alloca swifterror %swift_error* 41 store %swift_error* null, %swift_error** %error_ptr_ref 42 %call = call float @foo(%swift_error** swifterror %error_ptr_ref) 43 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 44 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 45 %tmp = bitcast %swift_error* %error_from_foo to i8* 46 br i1 %had_error_from_foo, label %handler, label %cont 47cont: 48 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 49 %t = load i8, i8* %v1 50 store i8 %t, i8* %error_ref 51 br label %handler 52handler: 53 call void @free(i8* %tmp) 54 ret float 1.0 55} 56 57; "caller2" is the caller of "foo", it calls "foo" inside a loop. 58define float @caller2(i8* %error_ref) { 59; CHECK-LABEL: caller2: 60; CHECK: mov [[ID:x[0-9]+]], x0 61; CHECK: fmov [[CMP:s[0-9]+]], #1.0 62; CHECK: mov x21, xzr 63; CHECK: bl {{.*}}foo 64; CHECK: cbnz x21 65; CHECK: fcmp s0, [[CMP]] 66; CHECK: b.le 67; Access part of the error object and save it to error_ref 68; CHECK: ldrb [[CODE:w[0-9]+]], [x21, #8] 69; CHECK: strb [[CODE]], [{{.*}}[[ID]]] 70; CHECK: mov x0, x21 71; CHECK: bl {{.*}}free 72 73entry: 74 %error_ptr_ref = alloca swifterror %swift_error* 75 br label %bb_loop 76bb_loop: 77 store %swift_error* null, %swift_error** %error_ptr_ref 78 %call = call float @foo(%swift_error** swifterror %error_ptr_ref) 79 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 80 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 81 %tmp = bitcast %swift_error* %error_from_foo to i8* 82 br i1 %had_error_from_foo, label %handler, label %cont 83cont: 84 %cmp = fcmp ogt float %call, 1.000000e+00 85 br i1 %cmp, label %bb_end, label %bb_loop 86bb_end: 87 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 88 %t = load i8, i8* %v1 89 store i8 %t, i8* %error_ref 90 br label %handler 91handler: 92 call void @free(i8* %tmp) 93 ret float 1.0 94} 95 96; "foo_if" is a function that takes a swifterror parameter, it sets swifterror 97; under a certain condition. 98define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) { 99; CHECK-LABEL: foo_if: 100; CHECK: cbz w0 101; CHECK: mov w0, #16 102; CHECK: malloc 103; CHECK: mov [[ID:w[0-9]+]], #1 104; CHECK: strb [[ID]], [x0, #8] 105; CHECK: mov x21, x0 106; CHECK-NOT: x21 107; CHECK: ret 108 109entry: 110 %cond = icmp ne i32 %cc, 0 111 br i1 %cond, label %gen_error, label %normal 112 113gen_error: 114 %call = call i8* @malloc(i64 16) 115 %call.0 = bitcast i8* %call to %swift_error* 116 store %swift_error* %call.0, %swift_error** %error_ptr_ref 117 %tmp = getelementptr inbounds i8, i8* %call, i64 8 118 store i8 1, i8* %tmp 119 ret float 1.0 120 121normal: 122 ret float 0.0 123} 124 125; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror 126; under a certain condition inside a loop. 127define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) { 128; CHECK-LABEL: foo_loop: 129; CHECK: cbz 130; CHECK: mov w0, #16 131; CHECK: malloc 132; CHECK: mov x21, x0 133; CHECK: strb w{{.*}}, [x0, #8] 134; CHECK: ret 135 136entry: 137 br label %bb_loop 138 139bb_loop: 140 %cond = icmp ne i32 %cc, 0 141 br i1 %cond, label %gen_error, label %bb_cont 142 143gen_error: 144 %call = call i8* @malloc(i64 16) 145 %call.0 = bitcast i8* %call to %swift_error* 146 store %swift_error* %call.0, %swift_error** %error_ptr_ref 147 %tmp = getelementptr inbounds i8, i8* %call, i64 8 148 store i8 1, i8* %tmp 149 br label %bb_cont 150 151bb_cont: 152 %cmp = fcmp ogt float %cc2, 1.000000e+00 153 br i1 %cmp, label %bb_end, label %bb_loop 154bb_end: 155 ret float 0.0 156} 157 158%struct.S = type { i32, i32, i32, i32, i32, i32 } 159 160; "foo_sret" is a function that takes a swifterror parameter, it also has a sret 161; parameter. 162define void @foo_sret(%struct.S* sret(%struct.S) %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) { 163; CHECK-LABEL: foo_sret: 164; CHECK: mov [[SRET:x[0-9]+]], x8 165; CHECK: mov w0, #16 166; CHECK: malloc 167; CHECK: mov [[ID:w[0-9]+]], #1 168; CHECK: strb [[ID]], [x0, #8] 169; CHECK: str w{{.*}}, [{{.*}}[[SRET]], #4] 170; CHECK: mov x21, x0 171; CHECK-NOT: x21 172 173entry: 174 %call = call i8* @malloc(i64 16) 175 %call.0 = bitcast i8* %call to %swift_error* 176 store %swift_error* %call.0, %swift_error** %error_ptr_ref 177 %tmp = getelementptr inbounds i8, i8* %call, i64 8 178 store i8 1, i8* %tmp 179 %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1 180 store i32 %val1, i32* %v2 181 ret void 182} 183 184; "caller3" calls "foo_sret" that takes a swifterror parameter. 185define float @caller3(i8* %error_ref) { 186; CHECK-LABEL: caller3: 187; CHECK: mov [[ID:x[0-9]+]], x0 188; CHECK: mov [[ZERO:x[0-9]+]], xzr 189; CHECK: bl {{.*}}foo_sret 190; CHECK: mov x0, x21 191; CHECK: cbnz x21 192; Access part of the error object and save it to error_ref 193; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8] 194; CHECK: strb [[CODE]], [{{.*}}[[ID]]] 195; CHECK: bl {{.*}}free 196 197entry: 198 %s = alloca %struct.S, align 8 199 %error_ptr_ref = alloca swifterror %swift_error* 200 store %swift_error* null, %swift_error** %error_ptr_ref 201 call void @foo_sret(%struct.S* sret(%struct.S) %s, i32 1, %swift_error** swifterror %error_ptr_ref) 202 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 203 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 204 %tmp = bitcast %swift_error* %error_from_foo to i8* 205 br i1 %had_error_from_foo, label %handler, label %cont 206cont: 207 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 208 %t = load i8, i8* %v1 209 store i8 %t, i8* %error_ref 210 br label %handler 211handler: 212 call void @free(i8* %tmp) 213 ret float 1.0 214} 215 216; "foo_vararg" is a function that takes a swifterror parameter, it also has 217; variable number of arguments. 218declare void @llvm.va_start(i8*) nounwind 219define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) { 220; CHECK-LABEL: foo_vararg: 221; CHECK: mov w0, #16 222; CHECK: malloc 223; CHECK-DAG: mov [[ID:w[0-9]+]], #1 224; CHECK-DAG: strb [[ID]], [x0, #8] 225 226; First vararg 227; CHECK: ldr {{w[0-9]+}}, [x[[ARG1:[0-9]+]]], #8 228; Second vararg 229; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]], #8 230; Third vararg 231; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]], #8 232 233; CHECK: mov x21, x0 234; CHECK-NOT: x21 235entry: 236 %call = call i8* @malloc(i64 16) 237 %call.0 = bitcast i8* %call to %swift_error* 238 store %swift_error* %call.0, %swift_error** %error_ptr_ref 239 %tmp = getelementptr inbounds i8, i8* %call, i64 8 240 store i8 1, i8* %tmp 241 242 %args = alloca i8*, align 8 243 %a10 = alloca i32, align 4 244 %a11 = alloca i32, align 4 245 %a12 = alloca i32, align 4 246 %v10 = bitcast i8** %args to i8* 247 call void @llvm.va_start(i8* %v10) 248 %v11 = va_arg i8** %args, i32 249 store i32 %v11, i32* %a10, align 4 250 %v12 = va_arg i8** %args, i32 251 store i32 %v12, i32* %a11, align 4 252 %v13 = va_arg i8** %args, i32 253 store i32 %v13, i32* %a12, align 4 254 255 ret float 1.0 256} 257 258; "caller4" calls "foo_vararg" that takes a swifterror parameter. 259define float @caller4(i8* %error_ref) { 260; CHECK-LABEL: caller4: 261 262; CHECK: mov [[ID:x[0-9]+]], x0 263; CHECK: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp] 264; CHECK: str {{x[0-9]+}}, [sp, #16] 265; CHECK: mov x21, xzr 266 267; CHECK: bl {{.*}}foo_vararg 268; CHECK: mov x0, x21 269; CHECK: cbnz x21 270; Access part of the error object and save it to error_ref 271; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8] 272; CHECK: strb [[CODE]], [{{.*}}[[ID]]] 273; CHECK: bl {{.*}}free 274entry: 275 %error_ptr_ref = alloca swifterror %swift_error* 276 store %swift_error* null, %swift_error** %error_ptr_ref 277 278 %a10 = alloca i32, align 4 279 %a11 = alloca i32, align 4 280 %a12 = alloca i32, align 4 281 store i32 10, i32* %a10, align 4 282 store i32 11, i32* %a11, align 4 283 store i32 12, i32* %a12, align 4 284 %v10 = load i32, i32* %a10, align 4 285 %v11 = load i32, i32* %a11, align 4 286 %v12 = load i32, i32* %a12, align 4 287 288 %call = call float (%swift_error**, ...) @foo_vararg(%swift_error** swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12) 289 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 290 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 291 %tmp = bitcast %swift_error* %error_from_foo to i8* 292 br i1 %had_error_from_foo, label %handler, label %cont 293 294cont: 295 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 296 %t = load i8, i8* %v1 297 store i8 %t, i8* %error_ref 298 br label %handler 299handler: 300 call void @free(i8* %tmp) 301 ret float 1.0 302} 303 304; Check that we don't blow up on tail calling swifterror argument functions. 305define float @tailcallswifterror(%swift_error** swifterror %error_ptr_ref) { 306entry: 307 %0 = tail call float @tailcallswifterror(%swift_error** swifterror %error_ptr_ref) 308 ret float %0 309} 310define swiftcc float @tailcallswifterror_swiftcc(%swift_error** swifterror %error_ptr_ref) { 311entry: 312 %0 = tail call swiftcc float @tailcallswifterror_swiftcc(%swift_error** swifterror %error_ptr_ref) 313 ret float %0 314} 315 316; CHECK-LABEL: params_in_reg 317; Save callee saved registers and swifterror since it will be clobbered by the first call to params_in_reg2. 318; CHECK: stp x28, x0, [sp 319; CHECK: stp x27, x26, [sp 320; CHECK: stp x25, x24, [sp 321; CHECK: stp x23, x22, [sp 322; CHECK: stp x20, x19, [sp 323; CHECK: stp x29, x30, [sp 324; Store argument registers. 325; CHECK: mov x20, x1 326; CHECK: mov x22, x2 327; CHECK: mov x23, x3 328; CHECK: mov x24, x4 329; CHECK: mov x25, x5 330; CHECK: mov x26, x6 331; CHECK: mov x27, x7 332; CHECK: mov x28, x21 333; Setup call. 334; CHECK: mov w0, #1 335; CHECK: mov w1, #2 336; CHECK: mov w2, #3 337; CHECK: mov w3, #4 338; CHECK: mov w4, #5 339; CHECK: mov w5, #6 340; CHECK: mov w6, #7 341; CHECK: mov w7, #8 342; CHECK: str xzr, [sp] 343; CHECK: mov x21, xzr 344; CHECK: bl _params_in_reg2 345; Restore original arguments for next call. 346; CHECK: ldr x0, [sp 347; CHECK: mov x1, x20 348; CHECK: mov x2, x22 349; CHECK: mov x3, x23 350; CHECK: mov x4, x24 351; CHECK: mov x5, x25 352; CHECK: mov x6, x26 353; CHECK: mov x7, x27 354; Restore original swiftself argument and swifterror %err. 355; CHECK: mov x21, x28 356; CHECK: bl _params_in_reg2 357; Restore calle save registers but don't clober swifterror x21. 358; CHECK-NOT: x21 359; CHECK: ldp x29, x30, [sp 360; CHECK-NOT: x21 361; CHECK: ldp x20, x19, [sp 362; CHECK-NOT: x21 363; CHECK: ldp x23, x22, [sp 364; CHECK-NOT: x21 365; CHECK: ldp x25, x24, [sp 366; CHECK-NOT: x21 367; CHECK: ldp x27, x26, [sp 368; CHECK-NOT: x21 369; CHECK: ldr x28, [sp 370; CHECK-NOT: x21 371; CHECK: ret 372define swiftcc void @params_in_reg(i64, i64, i64, i64, i64, i64, i64, i64, i8*, %swift_error** nocapture swifterror %err) { 373 %error_ptr_ref = alloca swifterror %swift_error*, align 8 374 store %swift_error* null, %swift_error** %error_ptr_ref 375 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i8* null, %swift_error** nocapture swifterror %error_ptr_ref) 376 call swiftcc void @params_in_reg2(i64 %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i8* %8, %swift_error** nocapture swifterror %err) 377 ret void 378} 379declare swiftcc void @params_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, i8* , %swift_error** nocapture swifterror %err) 380 381; CHECK-LABEL: params_and_return_in_reg 382; Store callee saved registers. 383; CHECK: stp x28, x0, [sp, #16 384; CHECK: stp x27, x26, [sp 385; CHECK: stp x25, x24, [sp 386; CHECK: stp x23, x22, [sp 387; CHECK: stp x20, x19, [sp 388; CHECK: stp x29, x30, [sp 389; Save original arguments. 390; CHECK: mov x20, x1 391; CHECK: mov x22, x2 392; CHECK: mov x23, x3 393; CHECK: mov x24, x4 394; CHECK: mov x25, x5 395; CHECK: mov x26, x6 396; CHECK: mov x27, x7 397; CHECK: mov x28, x21 398; Setup call arguments. 399; CHECK: mov w0, #1 400; CHECK: mov w1, #2 401; CHECK: mov w2, #3 402; CHECK: mov w3, #4 403; CHECK: mov w4, #5 404; CHECK: mov w5, #6 405; CHECK: mov w6, #7 406; CHECK: mov w7, #8 407; CHECK: mov x21, xzr 408; CHECK: bl _params_in_reg2 409; Store swifterror %error_ptr_ref. 410; CHECK: stp {{x[0-9]+}}, x21, [sp] 411; Setup call arguments from original arguments. 412; CHECK: ldr x0, [sp, #24 413; CHECK: mov x1, x20 414; CHECK: mov x2, x22 415; CHECK: mov x3, x23 416; CHECK: mov x4, x24 417; CHECK: mov x5, x25 418; CHECK: mov x6, x26 419; CHECK: mov x7, x27 420; CHECK: mov x21, x28 421; CHECK: bl _params_and_return_in_reg2 422; Store return values. 423; CHECK: mov x20, x0 424; CHECK: mov x22, x1 425; CHECK: mov x23, x2 426; CHECK: mov x24, x3 427; CHECK: mov x25, x4 428; CHECK: mov x26, x5 429; CHECK: mov x27, x6 430; CHECK: mov x28, x7 431; Save swifterror %err. 432; CHECK: mov x19, x21 433; Setup call. 434; CHECK: mov w0, #1 435; CHECK: mov w1, #2 436; CHECK: mov w2, #3 437; CHECK: mov w3, #4 438; CHECK: mov w4, #5 439; CHECK: mov w5, #6 440; CHECK: mov w6, #7 441; CHECK: mov w7, #8 442; ... setup call with swiferror %error_ptr_ref. 443; CHECK: ldr x21, [sp, #8] 444; CHECK: bl _params_in_reg2 445; Restore return values for return from this function. 446; CHECK: mov x0, x20 447; CHECK: mov x1, x22 448; CHECK: mov x2, x23 449; CHECK: mov x3, x24 450; CHECK: mov x4, x25 451; CHECK: mov x5, x26 452; CHECK: mov x6, x27 453; CHECK: mov x7, x28 454; CHECK: mov x21, x19 455; Restore callee save registers. 456; CHECK: ldp x29, x30, [sp 457; CHECK: ldp x20, x19, [sp 458; CHECK: ldp x23, x22, [sp 459; CHECK: ldp x25, x24, [sp 460; CHECK: ldp x27, x26, [sp 461; CHECK: ldr x28, [sp 462; CHECK: ret 463define swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg(i64, i64, i64, i64, i64, i64, i64, i64, i8* , %swift_error** nocapture swifterror %err) { 464 %error_ptr_ref = alloca swifterror %swift_error*, align 8 465 store %swift_error* null, %swift_error** %error_ptr_ref 466 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i8* null, %swift_error** nocapture swifterror %error_ptr_ref) 467 %val = call swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg2(i64 %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i8* %8, %swift_error** nocapture swifterror %err) 468 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, i8* null, %swift_error** nocapture swifterror %error_ptr_ref) 469 ret { i64, i64, i64, i64, i64, i64, i64, i64 } %val 470} 471 472declare swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, i8* , %swift_error** nocapture swifterror %err) 473 474declare void @acallee(i8*) 475 476; Make sure we don't tail call if the caller returns a swifterror value. We 477; would have to move into the swifterror register before the tail call. 478; CHECK: tailcall_from_swifterror: 479; CHECK-NOT: b _acallee 480; CHECK: bl _acallee 481 482define swiftcc void @tailcall_from_swifterror(%swift_error** swifterror %error_ptr_ref) { 483entry: 484 tail call void @acallee(i8* null) 485 ret void 486} 487 488; CHECK: tailcall_from_swifterror2 489; CHECK-NOT: b _simple_fn 490; CHECK: bl _simple_fn 491declare void @simple_fn() 492define swiftcc void @tailcall_from_swifterror2(%swift_error** swifterror %error_ptr_ref) { 493 tail call void @simple_fn() 494 ret void 495} 496 497declare swiftcc void @foo2(%swift_error** swifterror) 498; CHECK-LABEL: testAssign 499; CHECK: mov x21, xzr 500; CHECK: bl _foo2 501; CHECK: mov x0, x21 502 503define swiftcc %swift_error* @testAssign(i8* %error_ref) { 504entry: 505 %error_ptr = alloca swifterror %swift_error* 506 store %swift_error* null, %swift_error** %error_ptr 507 call swiftcc void @foo2(%swift_error** swifterror %error_ptr) 508 br label %a 509 510a: 511 %error = load %swift_error*, %swift_error** %error_ptr 512 ret %swift_error* %error 513} 514 515; foo takes a swifterror parameter. We should be able to see that even when 516; it isn't explicitly on the call. 517define float @swifterror_param_not_on_call(i8* %error_ref) { 518; CHECK-LABEL: swifterror_param_not_on_call: 519; CHECK: mov [[ID:x[0-9]+]], x0 520; CHECK: bl {{.*}}foo 521; CHECK: mov x0, x21 522; CHECK: cbnz x21 523; Access part of the error object and save it to error_ref 524; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8] 525; CHECK: strb [[CODE]], [{{.*}}[[ID]]] 526; CHECK: bl {{.*}}free 527 528entry: 529 %error_ptr_ref = alloca swifterror %swift_error* 530 store %swift_error* null, %swift_error** %error_ptr_ref 531 %call = call float @foo(%swift_error** %error_ptr_ref) 532 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 533 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 534 %tmp = bitcast %swift_error* %error_from_foo to i8* 535 br i1 %had_error_from_foo, label %handler, label %cont 536cont: 537 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 538 %t = load i8, i8* %v1 539 store i8 %t, i8* %error_ref 540 br label %handler 541handler: 542 call void @free(i8* %tmp) 543 ret float 1.0 544} 545 546; foo_sret takes an sret parameter and a swifterror parameter. We should be 547; able to see that, even if it's not explicitly on the call. 548define float @swifterror_param_not_on_call2(i8* %error_ref) { 549; CHECK-LABEL: swifterror_param_not_on_call2: 550; CHECK: mov [[ID:x[0-9]+]], x0 551; CHECK: mov [[ZERO:x[0-9]+]], xzr 552; CHECK: bl {{.*}}foo_sret 553; CHECK: mov x0, x21 554; CHECK: cbnz x21 555; Access part of the error object and save it to error_ref 556; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8] 557; CHECK: strb [[CODE]], [{{.*}}[[ID]]] 558; CHECK: bl {{.*}}free 559 560entry: 561 %s = alloca %struct.S, align 8 562 %error_ptr_ref = alloca swifterror %swift_error* 563 store %swift_error* null, %swift_error** %error_ptr_ref 564 call void @foo_sret(%struct.S* %s, i32 1, %swift_error** %error_ptr_ref) 565 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 566 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 567 %tmp = bitcast %swift_error* %error_from_foo to i8* 568 br i1 %had_error_from_foo, label %handler, label %cont 569cont: 570 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 571 %t = load i8, i8* %v1 572 store i8 %t, i8* %error_ref 573 br label %handler 574handler: 575 call void @free(i8* %tmp) 576 ret float 1.0 577} 578