1; RUN: llc < %s -mtriple=s390x-linux-gnu -disable-block-placement | FileCheck %s 2; RUN: llc < %s -O0 -mtriple=s390x-linux-gnu -disable-block-placement | FileCheck --check-prefix=CHECK-O0 %s 3 4declare ptr @malloc(i64) 5declare void @free(ptr) 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(ptr swifterror %error_ptr_ref) { 11; CHECK-LABEL: foo: 12; CHECK: lghi %r2, 16 13; CHECK: brasl %r14, malloc 14; CHECK: mvi 8(%r2), 1 15; CHECK: lgr %r9, %r2 16; CHECK-O0-LABEL: foo: 17; CHECK-O0: lghi %r2, 16 18; CHECK-O0: brasl %r14, malloc 19; CHECK-O0: lgr [[T0:%r[0-9]+]], %r2 20; CHECK-O0: mvi 8(%r2), 1 21entry: 22 %call = call ptr @malloc(i64 16) 23 store ptr %call, ptr %error_ptr_ref 24 %tmp = getelementptr inbounds i8, ptr %call, i64 8 25 store i8 1, ptr %tmp 26 ret float 1.0 27} 28 29; "caller" calls "foo" that takes a swifterror parameter. 30define float @caller(ptr %error_ref) { 31; CHECK-LABEL: caller: 32; Make a copy of error_ref because r2 is getting clobbered 33; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2 34; CHECK-DAG: lghi %r9, 0 35; CHECK: brasl %r14, foo 36; CHECK: %r2, %r9 37; CHECK: jlh 38; Access part of the error object and save it to error_ref 39; CHECK: lb %r[[REG2:[0-9]+]], 8(%r2) 40; CHECK: stc %r[[REG2]], 0(%r[[REG1]]) 41; CHECK: brasl %r14, free 42; CHECK-O0-LABEL: caller: 43; CHECK-O0: lghi %r9, 0 44; CHECK-O0: brasl %r14, foo 45; CHECK-O0: cghi %r9, 0 46; CHECK-O0: jlh 47entry: 48 %error_ptr_ref = alloca swifterror ptr 49 store ptr null, ptr %error_ptr_ref 50 %call = call float @foo(ptr swifterror %error_ptr_ref) 51 %error_from_foo = load ptr, ptr %error_ptr_ref 52 %had_error_from_foo = icmp ne ptr %error_from_foo, null 53 br i1 %had_error_from_foo, label %handler, label %cont 54cont: 55 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1 56 %t = load i8, ptr %v1 57 store i8 %t, ptr %error_ref 58 br label %handler 59handler: 60 call void @free(ptr %error_from_foo) 61 ret float 1.0 62} 63 64; "caller2" is the caller of "foo", it calls "foo" inside a loop. 65define float @caller2(ptr %error_ref) { 66; CHECK-LABEL: caller2: 67; Make a copy of error_ref because r2 is getting clobbered 68; CHECK: lgr %r[[REG1:[0-9]+]], %r2 69; CHECK: lghi %r9, 0 70; CHECK: brasl %r14, foo 71; CHECK: cgijlh %r9, 0, 72; CHECK: ceb %f0, 73; CHECK: jnh 74; Access part of the error object and save it to error_ref 75; CHECK: lb %r[[REG2:[0-9]+]], 8(%r9) 76; CHECK: stc %r[[REG2]], 0(%r[[REG1]]) 77; CHECK: lgr %r2, %r9 78; CHECK: brasl %r14, free 79; CHECK-O0-LABEL: caller2: 80; CHECK-O0: lghi %r9, 0 81; CHECK-O0: brasl %r14, foo 82; CHECK-O0: cghi %r9, 0 83; CHECK-O0: jlh 84entry: 85 %error_ptr_ref = alloca swifterror ptr 86 br label %bb_loop 87bb_loop: 88 store ptr null, ptr %error_ptr_ref 89 %call = call float @foo(ptr swifterror %error_ptr_ref) 90 %error_from_foo = load ptr, ptr %error_ptr_ref 91 %had_error_from_foo = icmp ne ptr %error_from_foo, null 92 br i1 %had_error_from_foo, label %handler, label %cont 93cont: 94 %cmp = fcmp ogt float %call, 1.000000e+00 95 br i1 %cmp, label %bb_end, label %bb_loop 96bb_end: 97 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1 98 %t = load i8, ptr %v1 99 store i8 %t, ptr %error_ref 100 br label %handler 101handler: 102 call void @free(ptr %error_from_foo) 103 ret float 1.0 104} 105 106; "foo_if" is a function that takes a swifterror parameter, it sets swifterror 107; under a certain condition. 108define float @foo_if(ptr swifterror %error_ptr_ref, i32 %cc) { 109; CHECK-LABEL: foo_if: 110; CHECK: cije %r2, 0 111; CHECK: lghi %r2, 16 112; CHECK: brasl %r14, malloc 113; CHECK: mvi 8(%r2), 1 114; CHECK: lgr %r9, %r2 115; CHECK-NOT: %r9 116; CHECK: br %r14 117; CHECK-O0-LABEL: foo_if: 118; spill to stack 119; CHECK-O0: stg %r9, [[OFFS:[0-9]+]](%r15) 120; CHECK-O0: chi %r2, 0 121; CHECK-O0: je 122; CHECK-O0: lghi %r2, 16 123; CHECK-O0: brasl %r14, malloc 124; CHECK-O0: lgr %r9, %r2 125; CHECK-O0: mvi 8(%r2), 1 126; CHECK-O0: br %r14 127; reload from stack 128; CHECK-O0: lg %r9, [[OFFS]](%r15) 129; CHECK-O0: br %r14 130entry: 131 %cond = icmp ne i32 %cc, 0 132 br i1 %cond, label %gen_error, label %normal 133 134gen_error: 135 %call = call ptr @malloc(i64 16) 136 store ptr %call, ptr %error_ptr_ref 137 %tmp = getelementptr inbounds i8, ptr %call, i64 8 138 store i8 1, ptr %tmp 139 ret float 1.0 140 141normal: 142 ret float 0.0 143} 144 145; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror 146; under a certain condition inside a loop. 147define float @foo_loop(ptr swifterror %error_ptr_ref, i32 %cc, float %cc2) { 148; CHECK-LABEL: foo_loop: 149; CHECK: lr %r[[REG1:[0-9]+]], %r2 150; CHECK: cije %r[[REG1]], 0 151; CHECK: lghi %r2, 16 152; CHECK: brasl %r14, malloc 153; CHECK: mvi 8(%r2), 1 154; CHECK: ceb %f8, 155; CHECK: jnh 156; CHECK: lgr %r9, %r2 157; CHECK: br %r14 158; CHECK-O0-LABEL: foo_loop: 159; spill to stack 160; CHECK-O0: stg %r9, [[OFFS:[0-9]+]](%r15) 161; CHECK-O0: chi %r{{.*}}, 0 162; CHECK-O0: je 163; CHECK-O0: lghi %r2, 16 164; CHECK-O0: brasl %r14, malloc 165; CHECK-O0: lgr %r[[REG1:[0-9]+]], %r2 166; CHECK-O0: mvi 8(%r[[REG1]]), 1 167; CHECK-O0: jnh 168; reload from stack 169; CHECK-O0: lg %r9, [[OFFS:[0-9]+]](%r15) 170; CHECK-O0: br %r14 171entry: 172 br label %bb_loop 173 174bb_loop: 175 %cond = icmp ne i32 %cc, 0 176 br i1 %cond, label %gen_error, label %bb_cont 177 178gen_error: 179 %call = call ptr @malloc(i64 16) 180 store ptr %call, ptr %error_ptr_ref 181 %tmp = getelementptr inbounds i8, ptr %call, i64 8 182 store i8 1, ptr %tmp 183 br label %bb_cont 184 185bb_cont: 186 %cmp = fcmp ogt float %cc2, 1.000000e+00 187 br i1 %cmp, label %bb_end, label %bb_loop 188bb_end: 189 ret float 0.0 190} 191 192%struct.S = type { i32, i32, i32, i32, i32, i32 } 193 194; "foo_sret" is a function that takes a swifterror parameter, it also has a sret 195; parameter. 196define void @foo_sret(ptr sret(%struct.S) %agg.result, i32 %val1, ptr swifterror %error_ptr_ref) { 197; CHECK-LABEL: foo_sret: 198; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2 199; CHECK-DAG: lr %r[[REG2:[0-9]+]], %r3 200; CHECK-DAG: lghi %r2, 16 201; CHECK: brasl %r14, malloc 202; CHECK: mvi 8(%r2), 1 203; CHECK: st %r[[REG2]], 4(%r[[REG1]]) 204; CHECK: lgr %r9, %r2 205; CHECK-NOT: %r9 206; CHECK: br %r14 207 208; CHECK-O0-LABEL: foo_sret: 209; spill sret to stack 210; CHECK-O0-DAG: stg %r2, [[OFFS1:[0-9]+]](%r15) 211; CHECK-O0-DAG: st %r3, [[OFFS2:[0-9]+]](%r15) 212; CHECK-O0: lghi %r2, 16 213; CHECK-O0: brasl %r14, malloc 214; CHECK-O0-DAG: lgr %r[[REG3:[0-9]+]], %r2 215; CHECK-O0-DAG: mvi 8(%r[[REG3]]), 1 216; CHECK-O0-DAG: lg %r[[REG1:[0-9]+]], [[OFFS1]](%r15) 217; CHECK-O0-DAG: lgr %r9, %r[[REG3]] 218; CHECK-O0-DAG: l %r[[REG2:[0-9]+]], [[OFFS2]](%r15) 219; CHECK-O0: st %r[[REG2]], 4(%r[[REG1]]) 220; CHECK-O0: br %r14 221entry: 222 %call = call ptr @malloc(i64 16) 223 store ptr %call, ptr %error_ptr_ref 224 %tmp = getelementptr inbounds i8, ptr %call, i64 8 225 store i8 1, ptr %tmp 226 %v2 = getelementptr inbounds %struct.S, ptr %agg.result, i32 0, i32 1 227 store i32 %val1, ptr %v2 228 ret void 229} 230 231; "caller3" calls "foo_sret" that takes a swifterror parameter. 232define float @caller3(ptr %error_ref) { 233; CHECK-LABEL: caller3: 234; Make a copy of error_ref because r2 is getting clobbered 235; CHECK: lgr %r[[REG1:[0-9]+]], %r2 236; CHECK: lhi %r3, 1 237; CHECK: lghi %r9, 0 238; CHECK: brasl %r14, foo_sret 239; CHECK: jlh 240; Access part of the error object and save it to error_ref 241; CHECK: lb %r0, 8(%r2) 242; CHECK: stc %r0, 0(%r[[REG1]]) 243; CHECK: brasl %r14, free 244 245; CHECK-O0-LABEL: caller3: 246; CHECK-O0: lghi %r9, 0 247; CHECK-O0: lhi %r3, 1 248; CHECK-O0: brasl %r14, foo_sret 249; CHECK-O0: lgr {{.*}}, %r9 250; CHECK-O0: cghi %r9, 0 251; CHECK-O0: jlh 252; Access part of the error object and save it to error_ref 253; CHECK-O0: lb %r0, 8(%r{{.*}}) 254; CHECK-O0: stc %r0, 0(%r{{.*}}) 255; reload from stack 256; CHECK-O0: lg %r2, {{.*}}(%r15) 257; CHECK-O0: brasl %r14, free 258entry: 259 %s = alloca %struct.S, align 8 260 %error_ptr_ref = alloca swifterror ptr 261 store ptr null, ptr %error_ptr_ref 262 call void @foo_sret(ptr sret(%struct.S) %s, i32 1, ptr swifterror %error_ptr_ref) 263 %error_from_foo = load ptr, ptr %error_ptr_ref 264 %had_error_from_foo = icmp ne ptr %error_from_foo, null 265 br i1 %had_error_from_foo, label %handler, label %cont 266cont: 267 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1 268 %t = load i8, ptr %v1 269 store i8 %t, ptr %error_ref 270 br label %handler 271handler: 272 call void @free(ptr %error_from_foo) 273 ret float 1.0 274} 275 276; This is a caller with multiple swifterror values, it calls "foo" twice, each 277; time with a different swifterror value, from "alloca swifterror". 278define float @caller_with_multiple_swifterror_values(ptr %error_ref, ptr %error_ref2) { 279; CHECK-LABEL: caller_with_multiple_swifterror_values: 280; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2 281; CHECK-DAG: lgr %r[[REG2:[0-9]+]], %r3 282; The first swifterror value: 283; CHECK-DAG: lghi %r9, 0 284; CHECK: brasl %r14, foo 285; CHECK: ltgr %r2, %r9 286; CHECK: jlh 287; Access part of the error object and save it to error_ref 288; CHECK: lb %r0, 8(%r2) 289; CHECK: stc %r0, 0(%r[[REG1]]) 290; CHECK: brasl %r14, free 291 292; The second swifterror value: 293; CHECK: lghi %r9, 0 294; CHECK: brasl %r14, foo 295; CHECK: ltgr %r2, %r9 296; CHECK: jlh 297; Access part of the error object and save it to error_ref 298; CHECK: lb %r0, 8(%r2) 299; CHECK: stc %r0, 0(%r[[REG2]]) 300; CHECK: brasl %r14, free 301 302; CHECK-O0-LABEL: caller_with_multiple_swifterror_values: 303 304; The first swifterror value: 305; CHECK-O0: lghi %r9, 0 306; CHECK-O0: brasl %r14, foo 307; CHECK-O0: jlh 308 309; The second swifterror value: 310; CHECK-O0: lghi %r9, 0 311; CHECK-O0: brasl %r14, foo 312; CHECK-O0: jlh 313entry: 314 %error_ptr_ref = alloca swifterror ptr 315 store ptr null, ptr %error_ptr_ref 316 %call = call float @foo(ptr swifterror %error_ptr_ref) 317 %error_from_foo = load ptr, ptr %error_ptr_ref 318 %had_error_from_foo = icmp ne ptr %error_from_foo, null 319 br i1 %had_error_from_foo, label %handler, label %cont 320cont: 321 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1 322 %t = load i8, ptr %v1 323 store i8 %t, ptr %error_ref 324 br label %handler 325handler: 326 call void @free(ptr %error_from_foo) 327 328 %error_ptr_ref2 = alloca swifterror ptr 329 store ptr null, ptr %error_ptr_ref2 330 %call2 = call float @foo(ptr swifterror %error_ptr_ref2) 331 %error_from_foo2 = load ptr, ptr %error_ptr_ref2 332 %had_error_from_foo2 = icmp ne ptr %error_from_foo2, null 333 br i1 %had_error_from_foo2, label %handler2, label %cont2 334cont2: 335 %v2 = getelementptr inbounds %swift_error, ptr %error_from_foo2, i64 0, i32 1 336 %t2 = load i8, ptr %v2 337 store i8 %t2, ptr %error_ref2 338 br label %handler2 339handler2: 340 call void @free(ptr %error_from_foo2) 341 342 ret float 1.0 343} 344