350 lines · plain
1; RUN: opt < %s -passes=inline -S | FileCheck %s2; RUN: opt < %s -passes='cgscc(inline)' -S | FileCheck %s3 4; Test that the inliner correctly handles inlining into invoke sites5; by appending selectors and forwarding _Unwind_Resume directly to the6; enclosing landing pad.7 8;; Test 0 - basic functionality.9 10%struct.A = type { i8 }11 12@_ZTIi = external constant ptr13 14declare void @_ZN1AC1Ev(ptr)15 16declare void @_ZN1AD1Ev(ptr)17 18declare void @use(i32) nounwind19 20declare void @opaque()21 22declare i32 @llvm.eh.typeid.for.p0(ptr) nounwind23 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 135 %b = alloca %struct.A, align 136 call void @_ZN1AC1Ev(ptr %a)37 invoke void @_ZN1AC1Ev(ptr %b)38 to label %invoke.cont unwind label %lpad39 40invoke.cont:41 invoke void @_ZN1AD1Ev(ptr %b)42 to label %invoke.cont1 unwind label %lpad43 44invoke.cont1:45 call void @_ZN1AD1Ev(ptr %a)46 ret void47 48lpad:49 %exn = landingpad {ptr, i32}50 cleanup51 invoke void @_ZN1AD1Ev(ptr %a)52 to label %invoke.cont2 unwind label %terminate.lpad53 54invoke.cont2:55 resume { ptr, i32 } %exn56 57terminate.lpad:58 %exn1 = landingpad {ptr, i32}59 catch ptr null60 call void @_ZSt9terminatev() noreturn nounwind61 unreachable62}63 64define void @test0_out() uwtable ssp personality ptr @__gxx_personality_v0 {65entry:66 invoke void @test0_in()67 to label %ret unwind label %lpad68 69ret:70 ret void71 72lpad: ; preds = %entry73 %exn = landingpad {ptr, i32}74 catch ptr @_ZTIi75 %eh.exc = extractvalue { ptr, i32 } %exn, 076 %eh.selector = extractvalue { ptr, i32 } %exn, 177 %0 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) nounwind78 %1 = icmp eq i32 %eh.selector, %079 br i1 %1, label %catch, label %eh.resume80 81catch:82 %ignored = call ptr @__cxa_begin_catch(ptr %eh.exc) nounwind83 call void @__cxa_end_catch() nounwind84 br label %ret85 86eh.resume:87 resume { ptr, i32 } %exn88}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: cleanup99; CHECK-NEXT: catch ptr @_ZTIi100; CHECK-NEXT: invoke void @_ZN1AD1Ev(ptr [[A]])101; CHECK-NEXT: to label %[[LBL:[^\s]+]] unwind102; CHECK: [[LBL]]:103; CHECK-NEXT: br label %[[LPAD:[^\s]+]]104; CHECK: ret void105; CHECK: landingpad { ptr, i32 }106; CHECK-NEXT: catch ptr @_ZTIi107; 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 %lpad121 122cont:123 invoke void @test0_in()124 to label %ret unwind label %lpad125 126ret:127 ret void128 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 @_ZTIi134 %eh.exc = extractvalue { ptr, i32 } %exn, 0135 %eh.selector = extractvalue { ptr, i32 } %exn, 1136 %0 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) nounwind137 %1 = icmp eq i32 %eh.selector, %0138 br i1 %1, label %catch, label %eh.resume139 140catch:141 %ignored = call ptr @__cxa_begin_catch(ptr %eh.exc) nounwind142 call void @use(i32 %x)143 call void @use(i32 %y)144 call void @__cxa_end_catch() nounwind145 br label %ret146 147eh.resume:148 resume { ptr, i32 } %exn149}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: cleanup169; CHECK-NEXT: catch ptr @_ZTIi170; CHECK-NEXT: invoke void @_ZN1AD1Ev(ptr [[A1]])171; CHECK-NEXT: to label %[[RESUME1:[^\s]+]] unwind172; 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: cleanup188; CHECK-NEXT: catch ptr @_ZTIi189; CHECK-NEXT: invoke void @_ZN1AD1Ev(ptr [[A2]])190; CHECK-NEXT: to label %[[RESUME2:[^\s]+]] unwind191; CHECK: [[RESUME2]]:192; CHECK-NEXT: br label %[[LPAD_JOIN2:[^\s]+]]193 194; CHECK: ret void195 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 @_ZTIi201; 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]], 0214; CHECK-NEXT: [[SELJ1:%.*]] = extractvalue { ptr, i32 } [[EXNJ1]], 1215; 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 calls225define void @test2_out() uwtable ssp personality ptr @__gxx_personality_v0 {226entry:227 invoke void @test0_in()228 to label %ret unwind label %lpad229 230ret:231 ret void232 233lpad:234 %exn = landingpad {ptr, i32}235 cleanup236 call void @_ZSt9terminatev()237 unreachable238}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 %lpad258 259ret:260 ret void261 262lpad:263 %exn = landingpad {ptr, i32}264 catch ptr @_ZTIi265 br label %lpad.cont266 267lpad.cont:268 call void @_ZSt9terminatev()269 unreachable270}271 272; CHECK: define void @test3_out()273; CHECK: landingpad { ptr, i32 }274; CHECK-NEXT: cleanup275; CHECK-NEXT: catch ptr @_ZTIi276; CHECK-NEXT: invoke void @_ZN1AD1Ev(277; CHECK-NEXT: to label %[[L:[^\s]+]] unwind278; CHECK: [[L]]:279; CHECK-NEXT: br label %[[JOIN:[^\s]+]]280; CHECK: [[JOIN]]:281; CHECK-NEXT: phi { ptr, i32 }282; CHECK-NEXT: br label %lpad.cont283; CHECK: lpad.cont:284; CHECK-NEXT: call void @_ZSt9terminatev()285 286 287;; Test 4 - Split unwind edges with a dominance problem288define void @test4_out() uwtable ssp personality ptr @__gxx_personality_v0 {289entry:290 invoke void @test0_in()291 to label %cont unwind label %lpad.crit292 293cont:294 invoke void @opaque()295 to label %ret unwind label %lpad296 297ret:298 ret void299 300lpad.crit:301 %exn = landingpad {ptr, i32}302 catch ptr @_ZTIi303 call void @opaque() nounwind304 br label %terminate305 306lpad:307 %exn2 = landingpad {ptr, i32}308 catch ptr @_ZTIi309 br label %terminate310 311terminate:312 %phi = phi i32 [ 0, %lpad.crit ], [ 1, %lpad ]313 call void @use(i32 %phi)314 call void @_ZSt9terminatev()315 unreachable316}317 318; CHECK: define void @test4_out()319; CHECK: landingpad { ptr, i32 }320; CHECK-NEXT: cleanup321; CHECK-NEXT: catch ptr @_ZTIi322; CHECK-NEXT: invoke void @_ZN1AD1Ev(323; CHECK-NEXT: to label %[[L:[^\s]+]] unwind324; CHECK: [[L]]:325; CHECK-NEXT: br label %[[JOIN:[^\s]+]]326; CHECK: invoke void @opaque()327; CHECK-NEXT: unwind label %lpad328; CHECK: lpad.crit:329; CHECK-NEXT: landingpad { ptr, i32 }330; CHECK-NEXT: catch ptr @_ZTIi331; 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 @_ZTIi339; 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