1; RUN: opt %s -inline -S | FileCheck %s 2 3declare void @external_func() 4declare void @abort() 5 6@exception_inner = external global i8 7@exception_outer = external global i8 8@condition = external global i1 9 10 11; Check for a bug in which multiple "resume" instructions in the 12; inlined function caused "catch i8* @exception_outer" to appear 13; multiple times in the resulting landingpad. 14 15define internal void @inner_multiple_resume() personality i8* null { 16 invoke void @external_func() 17 to label %cont unwind label %lpad 18cont: 19 ret void 20lpad: 21 %lp = landingpad i32 22 catch i8* @exception_inner 23 %cond = load i1, i1* @condition 24 br i1 %cond, label %resume1, label %resume2 25resume1: 26 resume i32 1 27resume2: 28 resume i32 2 29} 30 31define void @outer_multiple_resume() personality i8* null { 32 invoke void @inner_multiple_resume() 33 to label %cont unwind label %lpad 34cont: 35 ret void 36lpad: 37 %lp = landingpad i32 38 catch i8* @exception_outer 39 resume i32 %lp 40} 41; CHECK: define void @outer_multiple_resume() 42; CHECK: %lp.i = landingpad 43; CHECK-NEXT: catch i8* @exception_inner 44; CHECK-NEXT: catch i8* @exception_outer 45; Check that there isn't another "catch" clause: 46; CHECK-NEXT: load 47 48 49; Check for a bug in which having a "resume" and a "call" in the 50; inlined function caused "catch i8* @exception_outer" to appear 51; multiple times in the resulting landingpad. 52 53define internal void @inner_resume_and_call() personality i8* null { 54 call void @external_func() 55 invoke void @external_func() 56 to label %cont unwind label %lpad 57cont: 58 ret void 59lpad: 60 %lp = landingpad i32 61 catch i8* @exception_inner 62 resume i32 %lp 63} 64 65define void @outer_resume_and_call() personality i8* null { 66 invoke void @inner_resume_and_call() 67 to label %cont unwind label %lpad 68cont: 69 ret void 70lpad: 71 %lp = landingpad i32 72 catch i8* @exception_outer 73 resume i32 %lp 74} 75; CHECK: define void @outer_resume_and_call() 76; CHECK: %lp.i = landingpad 77; CHECK-NEXT: catch i8* @exception_inner 78; CHECK-NEXT: catch i8* @exception_outer 79; Check that there isn't another "catch" clause: 80; CHECK-NEXT: br 81 82 83; Check what happens if the inlined function contains an "invoke" but 84; no "resume". In this case, the inlined landingpad does not need to 85; include the "catch i8* @exception_outer" clause from the outer 86; function (since the outer function's landingpad will not be 87; reachable), but it's OK to include this clause. 88 89define internal void @inner_no_resume_or_call() personality i8* null { 90 invoke void @external_func() 91 to label %cont unwind label %lpad 92cont: 93 ret void 94lpad: 95 %lp = landingpad i32 96 catch i8* @exception_inner 97 ; A landingpad might have no "resume" if a C++ destructor aborts. 98 call void @abort() noreturn nounwind 99 unreachable 100} 101 102define void @outer_no_resume_or_call() personality i8* null { 103 invoke void @inner_no_resume_or_call() 104 to label %cont unwind label %lpad 105cont: 106 ret void 107lpad: 108 %lp = landingpad i32 109 catch i8* @exception_outer 110 resume i32 %lp 111} 112; CHECK: define void @outer_no_resume_or_call() 113; CHECK: %lp.i = landingpad 114; CHECK-NEXT: catch i8* @exception_inner 115; CHECK-NEXT: catch i8* @exception_outer 116; Check that there isn't another "catch" clause: 117; CHECK-NEXT: call void @abort() 118