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 4declare i8* @malloc(i64) 5declare 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". 11define 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]] 26entry: 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. 36define 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 61entry: 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 69cont: 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 74handler: 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. 80define 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 107entry: 108 %error_ptr_ref = alloca swifterror %swift_error* 109 br label %bb_loop 110bb_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 117cont: 118 %cmp = fcmp ogt float %call, 1.000000e+00 119 br i1 %cmp, label %bb_end, label %bb_loop 120bb_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 125handler: 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. 132define 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 155entry: 156 %cond = icmp ne i32 %cc, 0 157 br i1 %cond, label %gen_error, label %normal 158 159gen_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 167normal: 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. 173define 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 202entry: 203 br label %bb_loop 204 205bb_loop: 206 %cond = icmp ne i32 %cc, 0 207 br i1 %cond, label %gen_error, label %bb_cont 208 209gen_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 217bb_cont: 218 %cmp = fcmp ogt float %cc2, 1.000000e+00 219 br i1 %cmp, label %bb_end, label %bb_loop 220bb_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. 226define 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 249entry: 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. 261define 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 287entry: 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 296cont: 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 301handler: 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. 308declare void @llvm.va_start(i8*) nounwind 309define 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 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; 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 353entry: 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 373cont: 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 378handler: 379 call void @free(i8* %tmp) 380 ret float 1.0 381} 382