566 lines · plain
1; RUN: llc -verify-machineinstrs -frame-pointer=all -global-isel < %s -mtriple=aarch64-apple-ios | FileCheck %s2 3declare ptr @malloc(i64)4declare void @free(ptr)5%swift_error = type {i64, i8}6 7; This tests the basic usage of a swifterror parameter. "foo" is the function8; that takes a swifterror parameter and "caller" is the caller of "foo".9define float @foo(ptr swifterror %error_ptr_ref) {10; CHECK-LABEL: foo:11; CHECK: mov w0, #1612; CHECK: malloc13; CHECK: mov [[ID:w[0-9]+]], #114; CHECK: mov x21, x015; CHECK: strb [[ID]], [x0, #8]16; CHECK-NOT: x2117 18entry:19 %call = call ptr @malloc(i64 16)20 store ptr %call, ptr %error_ptr_ref21 %tmp = getelementptr inbounds i8, ptr %call, i64 822 store i8 1, ptr %tmp23 ret float 1.024}25 26; "caller" calls "foo" that takes a swifterror parameter.27define float @caller(ptr %error_ref) {28; CHECK-LABEL: caller:29; CHECK: mov [[ID:x[0-9]+]], x030; CHECK: bl {{.*}}foo31; CHECK: mov x0, x2132; CHECK: cbnz x2133; Access part of the error object and save it to error_ref34; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]35; CHECK: strb [[CODE]], [{{.*}}[[ID]]]36; CHECK: bl {{.*}}free37 38entry:39 %error_ptr_ref = alloca swifterror ptr40 store ptr null, ptr %error_ptr_ref41 %call = call float @foo(ptr swifterror %error_ptr_ref)42 %error_from_foo = load ptr, ptr %error_ptr_ref43 %had_error_from_foo = icmp ne ptr %error_from_foo, null44 br i1 %had_error_from_foo, label %handler, label %cont45cont:46 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 147 %t = load i8, ptr %v148 store i8 %t, ptr %error_ref49 br label %handler50handler:51 call void @free(ptr %error_from_foo)52 ret float 1.053}54 55; "caller2" is the caller of "foo", it calls "foo" inside a loop.56define float @caller2(ptr %error_ref) {57; CHECK-LABEL: caller2:58; CHECK: fmov [[CMP:s[0-9]+]], #1.059; CHECK: mov [[ID:x[0-9]+]], x060; CHECK: mov x21, xzr61; CHECK: bl {{.*}}foo62; CHECK: cbnz x2163; CHECK: fcmp s0, [[CMP]]64; CHECK: b.le65; Access part of the error object and save it to error_ref66; CHECK: ldrb [[CODE:w[0-9]+]], [x21, #8]67; CHECK: strb [[CODE]], [{{.*}}[[ID]]]68; CHECK: mov x0, x2169; CHECK: bl {{.*}}free70 71entry:72 %error_ptr_ref = alloca swifterror ptr73 br label %bb_loop74bb_loop:75 store ptr null, ptr %error_ptr_ref76 %call = call float @foo(ptr swifterror %error_ptr_ref)77 %error_from_foo = load ptr, ptr %error_ptr_ref78 %had_error_from_foo = icmp ne ptr %error_from_foo, null79 br i1 %had_error_from_foo, label %handler, label %cont80cont:81 %cmp = fcmp ogt float %call, 1.000000e+0082 br i1 %cmp, label %bb_end, label %bb_loop83bb_end:84 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 185 %t = load i8, ptr %v186 store i8 %t, ptr %error_ref87 br label %handler88handler:89 call void @free(ptr %error_from_foo)90 ret float 1.091}92 93; "foo_if" is a function that takes a swifterror parameter, it sets swifterror94; under a certain condition.95define float @foo_if(ptr swifterror %error_ptr_ref, i32 %cc) {96; CHECK-LABEL: foo_if:97; CHECK: cbz w098; CHECK: mov w0, #1699; CHECK: malloc100; CHECK-DAG: mov x21, x0101; CHECK-DAG: mov [[ID:w[0-9]+]], #1102; CHECK: strb [[ID]], [x0, #8]103; CHECK-NOT: x21104; CHECK: ret105 106entry:107 %cond = icmp ne i32 %cc, 0108 br i1 %cond, label %gen_error, label %normal109 110gen_error:111 %call = call ptr @malloc(i64 16)112 store ptr %call, ptr %error_ptr_ref113 %tmp = getelementptr inbounds i8, ptr %call, i64 8114 store i8 1, ptr %tmp115 ret float 1.0116 117normal:118 ret float 0.0119}120 121; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror122; under a certain condition inside a loop.123define float @foo_loop(ptr swifterror %error_ptr_ref, i32 %cc, float %cc2) {124; CHECK-LABEL: foo_loop:125; CHECK: cbz126; CHECK: mov w0, #16127; CHECK: malloc128; CHECK: mov x21, x0129; CHECK: strb w{{.*}}, [x0, #8]130; CHECK: ret131 132entry:133 br label %bb_loop134 135bb_loop:136 %cond = icmp ne i32 %cc, 0137 br i1 %cond, label %gen_error, label %bb_cont138 139gen_error:140 %call = call ptr @malloc(i64 16)141 store ptr %call, ptr %error_ptr_ref142 %tmp = getelementptr inbounds i8, ptr %call, i64 8143 store i8 1, ptr %tmp144 br label %bb_cont145 146bb_cont:147 %cmp = fcmp ogt float %cc2, 1.000000e+00148 br i1 %cmp, label %bb_end, label %bb_loop149bb_end:150 ret float 0.0151}152 153%struct.S = type { i32, i32, i32, i32, i32, i32 }154 155; "foo_sret" is a function that takes a swifterror parameter, it also has a sret156; parameter.157define void @foo_sret(ptr sret(%struct.S) %agg.result, i32 %val1, ptr swifterror %error_ptr_ref) {158; CHECK-LABEL: foo_sret:159; CHECK-DAG: mov [[SRET:x[0-9]+]], x8160; CHECK-DAG: mov w0, #16161; CHECK: malloc162; CHECK: mov [[ID:w[0-9]+]], #1163; CHECK: strb [[ID]], [x0, #8]164; CHECK: mov x21, x0165; CHECK: str w{{.*}}, [{{.*}}[[SRET]], #4]166; CHECK-NOT: x21167 168entry:169 %call = call ptr @malloc(i64 16)170 store ptr %call, ptr %error_ptr_ref171 %tmp = getelementptr inbounds i8, ptr %call, i64 8172 store i8 1, ptr %tmp173 %v2 = getelementptr inbounds %struct.S, ptr %agg.result, i32 0, i32 1174 store i32 %val1, ptr %v2175 ret void176}177 178; "caller3" calls "foo_sret" that takes a swifterror parameter.179define float @caller3(ptr %error_ref) {180; CHECK-LABEL: caller3:181; CHECK: mov [[ID:x[0-9]+]], x0182; CHECK: mov [[ZERO:x[0-9]+]], xzr183; CHECK: bl {{.*}}foo_sret184; CHECK: mov x0, x21185; CHECK: cbnz x21186; Access part of the error object and save it to error_ref187; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]188; CHECK: strb [[CODE]], [{{.*}}[[ID]]]189; CHECK: bl {{.*}}free190 191entry:192 %s = alloca %struct.S, align 8193 %error_ptr_ref = alloca swifterror ptr194 store ptr null, ptr %error_ptr_ref195 call void @foo_sret(ptr sret(%struct.S) %s, i32 1, ptr swifterror %error_ptr_ref)196 %error_from_foo = load ptr, ptr %error_ptr_ref197 %had_error_from_foo = icmp ne ptr %error_from_foo, null198 br i1 %had_error_from_foo, label %handler, label %cont199cont:200 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1201 %t = load i8, ptr %v1202 store i8 %t, ptr %error_ref203 br label %handler204handler:205 call void @free(ptr %error_from_foo)206 ret float 1.0207}208 209; "foo_vararg" is a function that takes a swifterror parameter, it also has210; variable number of arguments.211declare void @llvm.va_start(ptr) nounwind212define float @foo_vararg(ptr swifterror %error_ptr_ref, ...) {213; CHECK-LABEL: foo_vararg:214; CHECK: mov w0, #16215; CHECK: malloc216; CHECK: mov [[ID:w[0-9]+]], #1217; CHECK: strb [[ID]], [x0, #8]218; CHECK: mov x21, x0219; CHECK-NOT: x21220 221; First vararg222; CHECK: ldr {{w[0-9]+}}, [x[[ARG1:[0-9]+]]]223; CHECK-NOT: x21224; Second vararg225; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]]226; CHECK-NOT: x21227; Third vararg228; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]]229; CHECK-NOT: x21230entry:231 %call = call ptr @malloc(i64 16)232 store ptr %call, ptr %error_ptr_ref233 %tmp = getelementptr inbounds i8, ptr %call, i64 8234 store i8 1, ptr %tmp235 236 %args = alloca ptr, align 8237 %a10 = alloca i32, align 4238 %a11 = alloca i32, align 4239 %a12 = alloca i32, align 4240 call void @llvm.va_start(ptr %args)241 %v11 = va_arg ptr %args, i32242 store i32 %v11, ptr %a10, align 4243 %v12 = va_arg ptr %args, i32244 store i32 %v12, ptr %a11, align 4245 %v13 = va_arg ptr %args, i32246 store i32 %v13, ptr %a12, align 4247 248 ret float 1.0249}250 251; "caller4" calls "foo_vararg" that takes a swifterror parameter.252define float @caller4(ptr %error_ref) {253; CHECK-LABEL: caller4:254 255; CHECK: mov x21, xzr256; CHECK: mov [[ID:x[0-9]+]], x0257; CHECK: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp]258; CHECK: str {{x[0-9]+}}, [sp, #16]259 260; CHECK: bl {{.*}}foo_vararg261; CHECK: mov x0, x21262; CHECK: cbnz x21263; Access part of the error object and save it to error_ref264; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]265; CHECK: strb [[CODE]], [{{.*}}[[ID]]]266; CHECK: bl {{.*}}free267entry:268 %error_ptr_ref = alloca swifterror ptr269 store ptr null, ptr %error_ptr_ref270 271 %a10 = alloca i32, align 4272 %a11 = alloca i32, align 4273 %a12 = alloca i32, align 4274 store i32 10, ptr %a10, align 4275 store i32 11, ptr %a11, align 4276 store i32 12, ptr %a12, align 4277 %v10 = load i32, ptr %a10, align 4278 %v11 = load i32, ptr %a11, align 4279 %v12 = load i32, ptr %a12, align 4280 281 %call = call float (ptr, ...) @foo_vararg(ptr swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12)282 %error_from_foo = load ptr, ptr %error_ptr_ref283 %had_error_from_foo = icmp ne ptr %error_from_foo, null284 br i1 %had_error_from_foo, label %handler, label %cont285 286cont:287 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1288 %t = load i8, ptr %v1289 store i8 %t, ptr %error_ref290 br label %handler291handler:292 call void @free(ptr %error_from_foo)293 ret float 1.0294}295 296; Check that we don't blow up on tail calling swifterror argument functions.297define float @tailcallswifterror(ptr swifterror %error_ptr_ref) {298entry:299 %0 = tail call float @tailcallswifterror(ptr swifterror %error_ptr_ref)300 ret float %0301}302define swiftcc float @tailcallswifterror_swiftcc(ptr swifterror %error_ptr_ref) {303entry:304 %0 = tail call swiftcc float @tailcallswifterror_swiftcc(ptr swifterror %error_ptr_ref)305 ret float %0306}307 308; CHECK-LABEL: params_in_reg309; Save callee saved registers and swifterror since it will be clobbered by the first call to params_in_reg2.310; CHECK: str x28, [sp311; CHECK: stp x27, x26, [sp312; CHECK: stp x25, x24, [sp313; CHECK: stp x23, x22, [sp314; CHECK: stp x20, x19, [sp315; CHECK: stp x29, x30, [sp316; Store argument registers.317; CHECK: mov x20, x1318; CHECK: mov x22, x2319; CHECK: mov x23, x3320; CHECK: mov x24, x4321; CHECK: mov x25, x5322; CHECK: mov x26, x6323; CHECK: mov x27, x7324; CHECK: mov x28, x21325; Setup call.326; CHECK: mov w0, #1327; CHECK: mov w1, #2328; CHECK: mov w2, #3329; CHECK: mov w3, #4330; CHECK: mov w4, #5331; CHECK: mov w5, #6332; CHECK: mov w6, #7333; CHECK: mov w7, #8334; CHECK: mov x21, xzr335; CHECK: str xzr, [sp]336; CHECK: bl _params_in_reg2337; Restore original arguments for next call.338; CHECK: ldr x8, [sp, #24]339; CHECK: mov x1, x20340; CHECK: mov x2, x22341; CHECK: mov x3, x23342; CHECK: mov x4, x24343; CHECK: mov x5, x25344; CHECK: mov x6, x26345; CHECK: mov x7, x27346; Restore original swiftself argument and swifterror %err.347; CHECK: mov x21, x28348; CHECK: bl _params_in_reg2349; Restore calle save registers but don't clober swifterror x21.350; CHECK-NOT: x21351; CHECK: ldp x29, x30, [sp352; CHECK-NOT: x21353; CHECK: ldr x28, [sp354; CHECK-NOT: x21355; CHECK: ldp x20, x19, [sp356; CHECK-NOT: x21357; CHECK: ldp x23, x22, [sp358; CHECK-NOT: x21359; CHECK: ldp x25, x24, [sp360; CHECK-NOT: x21361; CHECK: ldp x27, x26, [sp362; CHECK-NOT: x21363; CHECK: ret364define swiftcc void @params_in_reg(i64, i64, i64, i64, i64, i64, i64, i64, ptr, ptr nocapture swifterror %err) {365 %error_ptr_ref = alloca swifterror ptr, align 8366 store ptr null, ptr %error_ptr_ref367 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, ptr null, ptr nocapture swifterror %error_ptr_ref)368 call swiftcc void @params_in_reg2(i64 %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, ptr %8, ptr nocapture swifterror %err)369 ret void370}371declare swiftcc void @params_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, ptr , ptr nocapture swifterror %err)372 373; CHECK-LABEL: params_and_return_in_reg374; Store callee saved registers.375; CHECK: stp x28, x0, [sp, #16376; CHECK: stp x27, x26, [sp377; CHECK: stp x25, x24, [sp378; CHECK: stp x23, x22, [sp379; CHECK: stp x20, x19, [sp380; CHECK: stp x29, x30, [sp381; Save original arguments.382; CHECK: mov x20, x1383; CHECK: mov x22, x2384; CHECK: mov x23, x3385; CHECK: mov x24, x4386; CHECK: mov x25, x5387; CHECK: mov x26, x6388; CHECK: mov x27, x7389; Setup call arguments.390; CHECK: mov w0, #1391; CHECK: mov w1, #2392; CHECK: mov w2, #3393; CHECK: mov w3, #4394; CHECK: mov w4, #5395; CHECK: mov w5, #6396; CHECK: mov w6, #7397; CHECK: mov w7, #8398; CHECK: mov x21, xzr399; CHECK: bl _params_in_reg2400; Store swifterror %error_ptr_ref.401; CHECK: ldr x0, [sp, #24]402; CHECK: stp {{x[0-9]+}}, x21, [sp]403; Setup call arguments from original arguments.404; CHECK: mov x1, x20405; CHECK: mov x2, x22406; CHECK: mov x3, x23407; CHECK: mov x4, x24408; CHECK: mov x5, x25409; CHECK: mov x6, x26410; CHECK: mov x7, x27411; CHECK: mov x21, x28412; CHECK: bl _params_and_return_in_reg2413; CHECK: mov x19, x21414; CHECK: ldr x21, [sp, #8415; Store return values.416; CHECK: mov x20, x0417; CHECK: mov x22, x1418; CHECK: mov x23, x2419; CHECK: mov x24, x3420; CHECK: mov x25, x4421; CHECK: mov x26, x5422; CHECK: mov x27, x6423; CHECK: mov x28, x7424; Setup call.425; CHECK: mov w0, #1426; CHECK: mov w1, #2427; CHECK: mov w2, #3428; CHECK: mov w3, #4429; CHECK: mov w4, #5430; CHECK: mov w5, #6431; CHECK: mov w6, #7432; CHECK: mov w7, #8433; CHECK: str xzr, [sp]434; CHECK: bl _params_in_reg2435; Restore return values for return from this function.436; CHECK: mov x0, x20437; CHECK: mov x1, x22438; CHECK: mov x2, x23439; CHECK: mov x3, x24440; CHECK: mov x4, x25441; CHECK: mov x5, x26442; CHECK: mov x6, x27443; CHECK: mov x21, x19444; CHECK: mov x7, x28445; CHECK: ldp x29, x30, [sp, #96] ; 16-byte Folded Reload446; CHECK: ldr x28, [sp, #16] ; 8-byte Reload447; CHECK: ldp x20, x19, [sp, #80] ; 16-byte Folded Reload448; CHECK: ldp x23, x22, [sp, #64] ; 16-byte Folded Reload449; CHECK: ldp x25, x24, [sp, #48] ; 16-byte Folded Reload450; CHECK: ldp x27, x26, [sp, #32] ; 16-byte Folded Reload451; CHECK: add sp, sp, #112452; CHECK: ret453define swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg(i64, i64, i64, i64, i64, i64, i64, i64, ptr , ptr nocapture swifterror %err) {454 %error_ptr_ref = alloca swifterror ptr, align 8455 store ptr null, ptr %error_ptr_ref456 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, ptr null, ptr nocapture swifterror %error_ptr_ref)457 %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, ptr %8, ptr nocapture swifterror %err)458 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, ptr null, ptr nocapture swifterror %error_ptr_ref)459 ret { i64, i64, i64, i64, i64, i64, i64, i64 } %val460}461 462declare swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, ptr , ptr nocapture swifterror %err)463 464declare void @acallee(ptr)465 466; Make sure we don't tail call if the caller returns a swifterror value. We467; would have to move into the swifterror register before the tail call.468; CHECK-LABEL: tailcall_from_swifterror:469; CHECK-NOT: b _acallee470; CHECK: bl _acallee471 472define swiftcc void @tailcall_from_swifterror(ptr swifterror %error_ptr_ref) {473entry:474 tail call void @acallee(ptr null)475 ret void476}477 478; CHECK: tailcall_from_swifterror2479; CHECK-NOT: b _simple_fn480; CHECK: bl _simple_fn481declare void @simple_fn()482define swiftcc void @tailcall_from_swifterror2(ptr swifterror %error_ptr_ref) {483 tail call void @simple_fn()484 ret void485}486 487declare swiftcc void @foo2(ptr swifterror)488; CHECK-LABEL: testAssign489; CHECK: mov x21, xzr490; CHECK: bl _foo2491; CHECK: mov x0, x21492 493define swiftcc ptr @testAssign(ptr %error_ref) {494entry:495 %error_ptr = alloca swifterror ptr496 store ptr null, ptr %error_ptr497 call swiftcc void @foo2(ptr swifterror %error_ptr)498 br label %a499 500a:501 %error = load ptr, ptr %error_ptr502 ret ptr %error503}504 505; foo takes a swifterror parameter. We should be able to see that even when506; it isn't explicitly on the call.507define float @swifterror_param_not_on_call(ptr %error_ref) {508; CHECK-LABEL: swifterror_param_not_on_call:509; CHECK: mov [[ID:x[0-9]+]], x0510; CHECK: bl {{.*}}foo511; CHECK: mov x0, x21512; CHECK: cbnz x21513; Access part of the error object and save it to error_ref514; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]515; CHECK: strb [[CODE]], [{{.*}}[[ID]]]516; CHECK: bl {{.*}}free517 518entry:519 %error_ptr_ref = alloca swifterror ptr520 store ptr null, ptr %error_ptr_ref521 %call = call float @foo(ptr %error_ptr_ref)522 %error_from_foo = load ptr, ptr %error_ptr_ref523 %had_error_from_foo = icmp ne ptr %error_from_foo, null524 br i1 %had_error_from_foo, label %handler, label %cont525cont:526 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1527 %t = load i8, ptr %v1528 store i8 %t, ptr %error_ref529 br label %handler530handler:531 call void @free(ptr %error_from_foo)532 ret float 1.0533}534 535; foo_sret takes an sret parameter and a swifterror parameter. We should be536; able to see that, even if it's not explicitly on the call.537define float @swifterror_param_not_on_call2(ptr %error_ref) {538; CHECK-LABEL: swifterror_param_not_on_call2:539; CHECK: mov [[ID:x[0-9]+]], x0540; CHECK: mov [[ZERO:x[0-9]+]], xzr541; CHECK: bl {{.*}}foo_sret542; CHECK: mov x0, x21543; CHECK: cbnz x21544; Access part of the error object and save it to error_ref545; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]546; CHECK: strb [[CODE]], [{{.*}}[[ID]]]547; CHECK: bl {{.*}}free548 549entry:550 %s = alloca %struct.S, align 8551 %error_ptr_ref = alloca swifterror ptr552 store ptr null, ptr %error_ptr_ref553 call void @foo_sret(ptr %s, i32 1, ptr %error_ptr_ref)554 %error_from_foo = load ptr, ptr %error_ptr_ref555 %had_error_from_foo = icmp ne ptr %error_from_foo, null556 br i1 %had_error_from_foo, label %handler, label %cont557cont:558 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1559 %t = load i8, ptr %v1560 store i8 %t, ptr %error_ref561 br label %handler562handler:563 call void @free(ptr %error_from_foo)564 ret float 1.0565}566