1 ; RUN: opt %s -inline -S | FileCheck %s 2 3 declare void @external_func() 4 declare 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 15 define internal void @inner_multiple_resume() { 16 invoke void @external_func() 17 to label %cont unwind label %lpad 18 cont: 19 ret void 20 lpad: 21 %lp = landingpad i32 personality i8* null 22 catch i8* @exception_inner 23 %cond = load i1* @condition 24 br i1 %cond, label %resume1, label %resume2 25 resume1: 26 resume i32 1 27 resume2: 28 resume i32 2 29 } 30 31 define void @outer_multiple_resume() { 32 invoke void @inner_multiple_resume() 33 to label %cont unwind label %lpad 34 cont: 35 ret void 36 lpad: 37 %lp = landingpad i32 personality i8* null 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 53 define internal void @inner_resume_and_call() { 54 call void @external_func() 55 invoke void @external_func() 56 to label %cont unwind label %lpad 57 cont: 58 ret void 59 lpad: 60 %lp = landingpad i32 personality i8* null 61 catch i8* @exception_inner 62 resume i32 %lp 63 } 64 65 define void @outer_resume_and_call() { 66 invoke void @inner_resume_and_call() 67 to label %cont unwind label %lpad 68 cont: 69 ret void 70 lpad: 71 %lp = landingpad i32 personality i8* null 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 89 define internal void @inner_no_resume_or_call() { 90 invoke void @external_func() 91 to label %cont unwind label %lpad 92 cont: 93 ret void 94 lpad: 95 %lp = landingpad i32 personality i8* null 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 102 define void @outer_no_resume_or_call() { 103 invoke void @inner_no_resume_or_call() 104 to label %cont unwind label %lpad 105 cont: 106 ret void 107 lpad: 108 %lp = landingpad i32 personality i8* null 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