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