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 4declare i8* @malloc(i64) 5declare 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". 10define 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 27entry: 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. 37define 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]] 54entry: 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 62cont: 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 67handler: 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. 73define 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]] 93entry: 94 %error_ptr_ref = alloca swifterror %swift_error* 95 br label %bb_loop 96bb_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 103cont: 104 %cmp = fcmp ogt float %call, 1.000000e+00 105 br i1 %cmp, label %bb_end, label %bb_loop 106bb_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 111handler: 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. 118define 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 143entry: 144 %cond = icmp ne i32 %cc, 0 145 br i1 %cond, label %gen_error, label %normal 146 147gen_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 155normal: 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. 161define 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 188entry: 189 br label %bb_loop 190 191bb_loop: 192 %cond = icmp ne i32 %cc, 0 193 br i1 %cond, label %gen_error, label %bb_cont 194 195gen_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 203bb_cont: 204 %cmp = fcmp ogt float %cc2, 1.000000e+00 205 br i1 %cmp, label %bb_end, label %bb_loop 206bb_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. 214define 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 239entry: 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. 251define 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 276entry: 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 285cont: 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 290handler: 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. 297declare void @llvm.va_start(i8*) nounwind 298define 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 318entry: 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. 342define 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 357entry: 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 377cont: 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 382handler: 383 call void @free(i8* %tmp) 384 ret float 1.0 385} 386