1; RUN: opt < %s -passes=inline -S | FileCheck %s 2; RUN: opt < %s -passes='cgscc(inline)' -S | FileCheck %s 3 4; Test that the inliner correctly handles inlining into invoke sites 5; by appending selectors and forwarding _Unwind_Resume directly to the 6; enclosing landing pad. 7 8;; Test 0 - basic functionality. 9 10%struct.A = type { i8 } 11 12@_ZTIi = external constant ptr 13 14declare void @_ZN1AC1Ev(ptr) 15 16declare void @_ZN1AD1Ev(ptr) 17 18declare void @use(i32) nounwind 19 20declare void @opaque() 21 22declare i32 @llvm.eh.typeid.for.p0(ptr) nounwind 23 24declare i32 @__gxx_personality_v0(...) 25 26declare ptr @__cxa_begin_catch(ptr) 27 28declare void @__cxa_end_catch() 29 30declare void @_ZSt9terminatev() 31 32define internal void @test0_in() alwaysinline uwtable ssp personality ptr @__gxx_personality_v0 { 33entry: 34 %a = alloca %struct.A, align 1 35 %b = alloca %struct.A, align 1 36 call void @_ZN1AC1Ev(ptr %a) 37 invoke void @_ZN1AC1Ev(ptr %b) 38 to label %invoke.cont unwind label %lpad 39 40invoke.cont: 41 invoke void @_ZN1AD1Ev(ptr %b) 42 to label %invoke.cont1 unwind label %lpad 43 44invoke.cont1: 45 call void @_ZN1AD1Ev(ptr %a) 46 ret void 47 48lpad: 49 %exn = landingpad {ptr, i32} 50 cleanup 51 invoke void @_ZN1AD1Ev(ptr %a) 52 to label %invoke.cont2 unwind label %terminate.lpad 53 54invoke.cont2: 55 resume { ptr, i32 } %exn 56 57terminate.lpad: 58 %exn1 = landingpad {ptr, i32} 59 catch ptr null 60 call void @_ZSt9terminatev() noreturn nounwind 61 unreachable 62} 63 64define void @test0_out() uwtable ssp personality ptr @__gxx_personality_v0 { 65entry: 66 invoke void @test0_in() 67 to label %ret unwind label %lpad 68 69ret: 70 ret void 71 72lpad: ; preds = %entry 73 %exn = landingpad {ptr, i32} 74 catch ptr @_ZTIi 75 %eh.exc = extractvalue { ptr, i32 } %exn, 0 76 %eh.selector = extractvalue { ptr, i32 } %exn, 1 77 %0 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) nounwind 78 %1 = icmp eq i32 %eh.selector, %0 79 br i1 %1, label %catch, label %eh.resume 80 81catch: 82 %ignored = call ptr @__cxa_begin_catch(ptr %eh.exc) nounwind 83 call void @__cxa_end_catch() nounwind 84 br label %ret 85 86eh.resume: 87 resume { ptr, i32 } %exn 88} 89 90; CHECK: define void @test0_out() 91; CHECK: [[A:%.*]] = alloca %struct.A, 92; CHECK: [[B:%.*]] = alloca %struct.A, 93; CHECK: invoke void @_ZN1AC1Ev(ptr [[A]]) 94; CHECK: invoke void @_ZN1AC1Ev(ptr [[B]]) 95; CHECK: invoke void @_ZN1AD1Ev(ptr [[B]]) 96; CHECK: invoke void @_ZN1AD1Ev(ptr [[A]]) 97; CHECK: landingpad { ptr, i32 } 98; CHECK-NEXT: cleanup 99; CHECK-NEXT: catch ptr @_ZTIi 100; CHECK-NEXT: invoke void @_ZN1AD1Ev(ptr [[A]]) 101; CHECK-NEXT: to label %[[LBL:[^\s]+]] unwind 102; CHECK: [[LBL]]: 103; CHECK-NEXT: br label %[[LPAD:[^\s]+]] 104; CHECK: ret void 105; CHECK: landingpad { ptr, i32 } 106; CHECK-NEXT: catch ptr @_ZTIi 107; CHECK-NEXT: br label %[[LPAD]] 108; CHECK: [[LPAD]]: 109; CHECK-NEXT: phi { ptr, i32 } [ 110; CHECK-NEXT: extractvalue { ptr, i32 } 111; CHECK-NEXT: extractvalue { ptr, i32 } 112; CHECK-NEXT: call i32 @llvm.eh.typeid.for.p0( 113 114 115;; Test 1 - Correctly handle phis in outer landing pads. 116 117define void @test1_out() uwtable ssp personality ptr @__gxx_personality_v0 { 118entry: 119 invoke void @test0_in() 120 to label %cont unwind label %lpad 121 122cont: 123 invoke void @test0_in() 124 to label %ret unwind label %lpad 125 126ret: 127 ret void 128 129lpad: 130 %x = phi i32 [ 0, %entry ], [ 1, %cont ] 131 %y = phi i32 [ 1, %entry ], [ 4, %cont ] 132 %exn = landingpad {ptr, i32} 133 catch ptr @_ZTIi 134 %eh.exc = extractvalue { ptr, i32 } %exn, 0 135 %eh.selector = extractvalue { ptr, i32 } %exn, 1 136 %0 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) nounwind 137 %1 = icmp eq i32 %eh.selector, %0 138 br i1 %1, label %catch, label %eh.resume 139 140catch: 141 %ignored = call ptr @__cxa_begin_catch(ptr %eh.exc) nounwind 142 call void @use(i32 %x) 143 call void @use(i32 %y) 144 call void @__cxa_end_catch() nounwind 145 br label %ret 146 147eh.resume: 148 resume { ptr, i32 } %exn 149} 150 151; CHECK: define void @test1_out() 152; CHECK: [[A2:%.*]] = alloca %struct.A, 153; CHECK: [[B2:%.*]] = alloca %struct.A, 154; CHECK: [[A1:%.*]] = alloca %struct.A, 155; CHECK: [[B1:%.*]] = alloca %struct.A, 156; CHECK: invoke void @_ZN1AC1Ev(ptr [[A1]]) 157; CHECK-NEXT: unwind label %[[LPAD:[^\s]+]] 158; CHECK: invoke void @_ZN1AC1Ev(ptr [[B1]]) 159; CHECK-NEXT: unwind label %[[LPAD1:[^\s]+]] 160; CHECK: invoke void @_ZN1AD1Ev(ptr [[B1]]) 161; CHECK-NEXT: unwind label %[[LPAD1]] 162; CHECK: invoke void @_ZN1AD1Ev(ptr [[A1]]) 163; CHECK-NEXT: unwind label %[[LPAD]] 164 165; Inner landing pad from first inlining. 166; CHECK: [[LPAD1]]: 167; CHECK-NEXT: [[LPADVAL1:%.*]] = landingpad { ptr, i32 } 168; CHECK-NEXT: cleanup 169; CHECK-NEXT: catch ptr @_ZTIi 170; CHECK-NEXT: invoke void @_ZN1AD1Ev(ptr [[A1]]) 171; CHECK-NEXT: to label %[[RESUME1:[^\s]+]] unwind 172; CHECK: [[RESUME1]]: 173; CHECK-NEXT: br label %[[LPAD_JOIN1:[^\s]+]] 174 175; CHECK: invoke void @_ZN1AC1Ev(ptr [[A2]]) 176; CHECK-NEXT: unwind label %[[LPAD]] 177; CHECK: invoke void @_ZN1AC1Ev(ptr [[B2]]) 178; CHECK-NEXT: unwind label %[[LPAD2:[^\s]+]] 179; CHECK: invoke void @_ZN1AD1Ev(ptr [[B2]]) 180; CHECK-NEXT: unwind label %[[LPAD2]] 181; CHECK: invoke void @_ZN1AD1Ev(ptr [[A2]]) 182; CHECK-NEXT: unwind label %[[LPAD]] 183 184; Inner landing pad from second inlining. 185; CHECK: [[LPAD2]]: 186; CHECK-NEXT: [[LPADVAL2:%.*]] = landingpad { ptr, i32 } 187; CHECK-NEXT: cleanup 188; CHECK-NEXT: catch ptr @_ZTIi 189; CHECK-NEXT: invoke void @_ZN1AD1Ev(ptr [[A2]]) 190; CHECK-NEXT: to label %[[RESUME2:[^\s]+]] unwind 191; CHECK: [[RESUME2]]: 192; CHECK-NEXT: br label %[[LPAD_JOIN2:[^\s]+]] 193 194; CHECK: ret void 195 196; CHECK: [[LPAD]]: 197; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, %entry ], [ 0, {{%.*}} ], [ 1, %cont ], [ 1, {{%.*}} ] 198; CHECK-NEXT: [[Y:%.*]] = phi i32 [ 1, %entry ], [ 1, {{%.*}} ], [ 4, %cont ], [ 4, {{%.*}} ] 199; CHECK-NEXT: [[LPADVAL:%.*]] = landingpad { ptr, i32 } 200; CHECK-NEXT: catch ptr @_ZTIi 201; CHECK-NEXT: br label %[[LPAD_JOIN2]] 202 203; CHECK: [[LPAD_JOIN2]]: 204; CHECK-NEXT: [[XJ2:%.*]] = phi i32 [ [[X]], %[[LPAD]] ], [ 1, %[[RESUME2]] ] 205; CHECK-NEXT: [[YJ2:%.*]] = phi i32 [ [[Y]], %[[LPAD]] ], [ 4, %[[RESUME2]] ] 206; CHECK-NEXT: [[EXNJ2:%.*]] = phi { ptr, i32 } [ [[LPADVAL]], %[[LPAD]] ], [ [[LPADVAL2]], %[[RESUME2]] ] 207; CHECK-NEXT: br label %[[LPAD_JOIN1]] 208 209; CHECK: [[LPAD_JOIN1]]: 210; CHECK-NEXT: [[XJ1:%.*]] = phi i32 [ [[XJ2]], %[[LPAD_JOIN2]] ], [ 0, %[[RESUME1]] ] 211; CHECK-NEXT: [[YJ1:%.*]] = phi i32 [ [[YJ2]], %[[LPAD_JOIN2]] ], [ 1, %[[RESUME1]] ] 212; CHECK-NEXT: [[EXNJ1:%.*]] = phi { ptr, i32 } [ [[EXNJ2]], %[[LPAD_JOIN2]] ], [ [[LPADVAL1]], %[[RESUME1]] ] 213; CHECK-NEXT: extractvalue { ptr, i32 } [[EXNJ1]], 0 214; CHECK-NEXT: [[SELJ1:%.*]] = extractvalue { ptr, i32 } [[EXNJ1]], 1 215; CHECK-NEXT: [[T:%.*]] = call i32 @llvm.eh.typeid.for.p0( 216; CHECK-NEXT: icmp eq i32 [[SELJ1]], [[T]] 217 218; CHECK: call void @use(i32 [[XJ1]]) 219; CHECK: call void @use(i32 [[YJ1]]) 220 221; CHECK: resume { ptr, i32 } 222 223 224;; Test 2 - Don't make invalid IR for inlines into landing pads without eh.exception calls 225define void @test2_out() uwtable ssp personality ptr @__gxx_personality_v0 { 226entry: 227 invoke void @test0_in() 228 to label %ret unwind label %lpad 229 230ret: 231 ret void 232 233lpad: 234 %exn = landingpad {ptr, i32} 235 cleanup 236 call void @_ZSt9terminatev() 237 unreachable 238} 239 240; CHECK: define void @test2_out() 241; CHECK: [[A:%.*]] = alloca %struct.A, 242; CHECK: [[B:%.*]] = alloca %struct.A, 243; CHECK: invoke void @_ZN1AC1Ev(ptr [[A]]) 244; CHECK-NEXT: unwind label %[[LPAD:[^\s]+]] 245; CHECK: invoke void @_ZN1AC1Ev(ptr [[B]]) 246; CHECK-NEXT: unwind label %[[LPAD2:[^\s]+]] 247; CHECK: invoke void @_ZN1AD1Ev(ptr [[B]]) 248; CHECK-NEXT: unwind label %[[LPAD2]] 249; CHECK: invoke void @_ZN1AD1Ev(ptr [[A]]) 250; CHECK-NEXT: unwind label %[[LPAD]] 251 252 253;; Test 3 - Deal correctly with split unwind edges. 254define void @test3_out() uwtable ssp personality ptr @__gxx_personality_v0 { 255entry: 256 invoke void @test0_in() 257 to label %ret unwind label %lpad 258 259ret: 260 ret void 261 262lpad: 263 %exn = landingpad {ptr, i32} 264 catch ptr @_ZTIi 265 br label %lpad.cont 266 267lpad.cont: 268 call void @_ZSt9terminatev() 269 unreachable 270} 271 272; CHECK: define void @test3_out() 273; CHECK: landingpad { ptr, i32 } 274; CHECK-NEXT: cleanup 275; CHECK-NEXT: catch ptr @_ZTIi 276; CHECK-NEXT: invoke void @_ZN1AD1Ev( 277; CHECK-NEXT: to label %[[L:[^\s]+]] unwind 278; CHECK: [[L]]: 279; CHECK-NEXT: br label %[[JOIN:[^\s]+]] 280; CHECK: [[JOIN]]: 281; CHECK-NEXT: phi { ptr, i32 } 282; CHECK-NEXT: br label %lpad.cont 283; CHECK: lpad.cont: 284; CHECK-NEXT: call void @_ZSt9terminatev() 285 286 287;; Test 4 - Split unwind edges with a dominance problem 288define void @test4_out() uwtable ssp personality ptr @__gxx_personality_v0 { 289entry: 290 invoke void @test0_in() 291 to label %cont unwind label %lpad.crit 292 293cont: 294 invoke void @opaque() 295 to label %ret unwind label %lpad 296 297ret: 298 ret void 299 300lpad.crit: 301 %exn = landingpad {ptr, i32} 302 catch ptr @_ZTIi 303 call void @opaque() nounwind 304 br label %terminate 305 306lpad: 307 %exn2 = landingpad {ptr, i32} 308 catch ptr @_ZTIi 309 br label %terminate 310 311terminate: 312 %phi = phi i32 [ 0, %lpad.crit ], [ 1, %lpad ] 313 call void @use(i32 %phi) 314 call void @_ZSt9terminatev() 315 unreachable 316} 317 318; CHECK: define void @test4_out() 319; CHECK: landingpad { ptr, i32 } 320; CHECK-NEXT: cleanup 321; CHECK-NEXT: catch ptr @_ZTIi 322; CHECK-NEXT: invoke void @_ZN1AD1Ev( 323; CHECK-NEXT: to label %[[L:[^\s]+]] unwind 324; CHECK: [[L]]: 325; CHECK-NEXT: br label %[[JOIN:[^\s]+]] 326; CHECK: invoke void @opaque() 327; CHECK-NEXT: unwind label %lpad 328; CHECK: lpad.crit: 329; CHECK-NEXT: landingpad { ptr, i32 } 330; CHECK-NEXT: catch ptr @_ZTIi 331; CHECK-NEXT: br label %[[JOIN]] 332; CHECK: [[JOIN]]: 333; CHECK-NEXT: phi { ptr, i32 } 334; CHECK-NEXT: call void @opaque() [[NUW:#[0-9]+]] 335; CHECK-NEXT: br label %[[FIX:[^\s]+]] 336; CHECK: lpad: 337; CHECK-NEXT: landingpad { ptr, i32 } 338; CHECK-NEXT: catch ptr @_ZTIi 339; CHECK-NEXT: br label %[[FIX]] 340; CHECK: [[FIX]]: 341; CHECK-NEXT: [[T1:%.*]] = phi i32 [ 0, %[[JOIN]] ], [ 1, %lpad ] 342; CHECK-NEXT: call void @use(i32 [[T1]]) 343; CHECK-NEXT: call void @_ZSt9terminatev() 344 345; CHECK: attributes [[NUW]] = { nounwind } 346; CHECK: attributes #1 = { nounwind memory(none) } 347; CHECK: attributes #2 = { ssp uwtable } 348; CHECK: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } 349; CHECK: attributes #4 = { noreturn nounwind } 350