Currently, FunctionAttrs treats landingpads as non-throwing, and will infer nounwind for functions with landingpads (assuming they can't unwind in some other way, e.g. via resum). There are two problems with this: * Non-cleanup landingpads with catch/filter clauses do not necessarily catch all exceptions. Unless there are catch ptr null or filter [0 x ptr] zeroinitializer clauses, we should assume that we may unwind past this landingpad. This seems like an outright bug. * Cleanup landingpads are skipped during phase one unwinding, so we effectively need to support unwinding past them. Marking these nounwind is technically correct, but not compatible with how unwinding works in reality. Fixes https://github.com/llvm/llvm-project/issues/61945. Differential Revision: https://reviews.llvm.org/D147694
336 lines
9.3 KiB
LLVM
336 lines
9.3 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
|
|
; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
|
|
|
|
; TEST 1
|
|
define i32 @foo1() {
|
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@foo1
|
|
; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
|
|
; CHECK-NEXT: ret i32 1
|
|
;
|
|
ret i32 1
|
|
}
|
|
|
|
; TEST 2
|
|
define i32 @scc1_foo() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@scc1_foo
|
|
; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @scc1_bar()
|
|
; CHECK-NEXT: ret i32 1
|
|
;
|
|
%1 = call i32 @scc1_bar()
|
|
ret i32 1
|
|
}
|
|
|
|
|
|
; TEST 3
|
|
define i32 @scc1_bar() {
|
|
; CHECK: Function Attrs: nofree nosync nounwind memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@scc1_bar
|
|
; CHECK-SAME: () #[[ATTR1]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @scc1_foo()
|
|
; CHECK-NEXT: ret i32 1
|
|
;
|
|
%1 = call i32 @scc1_foo()
|
|
ret i32 1
|
|
}
|
|
|
|
declare i32 @non_nounwind()
|
|
|
|
; TEST 4
|
|
define void @call_non_nounwind(){
|
|
; CHECK-LABEL: define {{[^@]+}}@call_non_nounwind() {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @non_nounwind()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
tail call i32 @non_nounwind()
|
|
ret void
|
|
}
|
|
|
|
; TEST 5 - throw
|
|
; int maybe_throw(bool canThrow) {
|
|
; if (canThrow)
|
|
; throw;
|
|
; else
|
|
; return -1;
|
|
; }
|
|
|
|
define i32 @maybe_throw(i1 zeroext %0) {
|
|
; CHECK-LABEL: define {{[^@]+}}@maybe_throw
|
|
; CHECK-SAME: (i1 zeroext [[TMP0:%.*]]) {
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[TMP2:%.*]], label [[TMP3:%.*]]
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: tail call void @__cxa_rethrow()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: 3:
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
br i1 %0, label %2, label %3
|
|
|
|
2: ; preds = %1
|
|
tail call void @__cxa_rethrow() #1
|
|
unreachable
|
|
|
|
3: ; preds = %1
|
|
ret i32 -1
|
|
}
|
|
|
|
declare void @__cxa_rethrow()
|
|
|
|
; TEST 6 - catch
|
|
; int catch_thing() {
|
|
; try {
|
|
; int a = doThing(true);
|
|
; }
|
|
; catch(...) { return -1; }
|
|
; return 1;
|
|
; }
|
|
|
|
define i32 @catch_thing() personality ptr @__gxx_personality_v0 {
|
|
; CHECK-LABEL: define {{[^@]+}}@catch_thing() personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @__cxa_rethrow()
|
|
; CHECK-NEXT: to label [[TMP1:%.*]] unwind label [[TMP2:%.*]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: [[TMP3:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: catch ptr null
|
|
; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0
|
|
; CHECK-NEXT: [[TMP5:%.*]] = tail call ptr @__cxa_begin_catch(ptr [[TMP4]])
|
|
; CHECK-NEXT: tail call void @__cxa_end_catch()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
invoke void @__cxa_rethrow() #1
|
|
to label %1 unwind label %2
|
|
|
|
1: ; preds = %0
|
|
unreachable
|
|
|
|
2: ; preds = %0
|
|
%3 = landingpad { ptr, i32 }
|
|
catch ptr null
|
|
%4 = extractvalue { ptr, i32 } %3, 0
|
|
%5 = tail call ptr @__cxa_begin_catch(ptr %4) #2
|
|
tail call void @__cxa_end_catch()
|
|
ret i32 -1
|
|
}
|
|
|
|
define i32 @catch_thing_user() {
|
|
; CHECK-LABEL: define {{[^@]+}}@catch_thing_user() {
|
|
; CHECK-NEXT: [[CATCH_THING_CALL:%.*]] = call i32 @catch_thing()
|
|
; CHECK-NEXT: ret i32 [[CATCH_THING_CALL]]
|
|
;
|
|
%catch_thing_call = call i32 @catch_thing()
|
|
ret i32 %catch_thing_call
|
|
}
|
|
|
|
declare void @do_throw()
|
|
declare void @abort() nounwind
|
|
@catch_ty = external global ptr
|
|
|
|
define void @catch_specific_landingpad() personality ptr @__gxx_personality_v0 {
|
|
; CHECK: Function Attrs: noreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@catch_specific_landingpad
|
|
; CHECK-SAME: () #[[ATTR3:[0-9]+]] personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @do_throw()
|
|
; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
|
|
; CHECK: lpad:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: catch ptr @catch_ty
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
invoke void @do_throw()
|
|
to label %unreachable unwind label %lpad
|
|
|
|
lpad:
|
|
%lp = landingpad { ptr, i32 }
|
|
catch ptr @catch_ty
|
|
call void @abort()
|
|
unreachable
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @catch_all_landingpad() personality ptr @__gxx_personality_v0 {
|
|
; CHECK: Function Attrs: noreturn nounwind
|
|
; CHECK-LABEL: define {{[^@]+}}@catch_all_landingpad
|
|
; CHECK-SAME: () #[[ATTR4:[0-9]+]] personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @do_throw()
|
|
; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
|
|
; CHECK: lpad:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: catch ptr null
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
invoke void @do_throw()
|
|
to label %unreachable unwind label %lpad
|
|
|
|
lpad:
|
|
%lp = landingpad { ptr, i32 }
|
|
catch ptr null
|
|
call void @abort()
|
|
unreachable
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @filter_specific_landingpad() personality ptr @__gxx_personality_v0 {
|
|
; CHECK: Function Attrs: noreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@filter_specific_landingpad
|
|
; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @do_throw()
|
|
; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
|
|
; CHECK: lpad:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: filter [1 x ptr] [ptr @catch_ty]
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
invoke void @do_throw()
|
|
to label %unreachable unwind label %lpad
|
|
|
|
lpad:
|
|
%lp = landingpad { ptr, i32 }
|
|
filter [1 x ptr] [ptr @catch_ty]
|
|
call void @abort()
|
|
unreachable
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @filter_none_landingpad() personality ptr @__gxx_personality_v0 {
|
|
; CHECK: Function Attrs: noreturn nounwind
|
|
; CHECK-LABEL: define {{[^@]+}}@filter_none_landingpad
|
|
; CHECK-SAME: () #[[ATTR4]] personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @do_throw()
|
|
; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
|
|
; CHECK: lpad:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: filter [0 x ptr] zeroinitializer
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
invoke void @do_throw()
|
|
to label %unreachable unwind label %lpad
|
|
|
|
lpad:
|
|
%lp = landingpad { ptr, i32 }
|
|
filter [0 x ptr] zeroinitializer
|
|
call void @abort()
|
|
unreachable
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @cleanup_landingpad() personality ptr @__gxx_personality_v0 {
|
|
; CHECK: Function Attrs: noreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@cleanup_landingpad
|
|
; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @do_throw()
|
|
; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
|
|
; CHECK: lpad:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: cleanup
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
invoke void @do_throw()
|
|
to label %unreachable unwind label %lpad
|
|
|
|
lpad:
|
|
%lp = landingpad { ptr, i32 }
|
|
cleanup
|
|
call void @abort()
|
|
unreachable
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @cleanuppad() personality ptr @__gxx_personality_v0 {
|
|
; CHECK: Function Attrs: noreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@cleanuppad
|
|
; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @do_throw()
|
|
; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[CPAD:%.*]]
|
|
; CHECK: cpad:
|
|
; CHECK-NEXT: [[CP:%.*]] = cleanuppad within none []
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
invoke void @do_throw()
|
|
to label %unreachable unwind label %cpad
|
|
|
|
cpad:
|
|
%cp = cleanuppad within none []
|
|
call void @abort()
|
|
unreachable
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
define void @catchswitch_cleanuppad() personality ptr @__gxx_personality_v0 {
|
|
; CHECK: Function Attrs: noreturn
|
|
; CHECK-LABEL: define {{[^@]+}}@catchswitch_cleanuppad
|
|
; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 {
|
|
; CHECK-NEXT: invoke void @do_throw()
|
|
; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[CS:%.*]]
|
|
; CHECK: cs:
|
|
; CHECK-NEXT: [[TOK:%.*]] = catchswitch within none [label %catch] unwind label [[CPAD:%.*]]
|
|
; CHECK: catch:
|
|
; CHECK-NEXT: [[C:%.*]] = catchpad within [[TOK]] [ptr @catch_ty, i32 0, ptr null]
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: cpad:
|
|
; CHECK-NEXT: [[CP:%.*]] = cleanuppad within none []
|
|
; CHECK-NEXT: call void @abort()
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: unreachable:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
invoke void @do_throw()
|
|
to label %unreachable unwind label %cs
|
|
|
|
cs:
|
|
%tok = catchswitch within none [label %catch] unwind label %cpad
|
|
|
|
catch:
|
|
%c = catchpad within %tok [ptr @catch_ty, i32 0, ptr null]
|
|
call void @abort()
|
|
unreachable
|
|
|
|
cpad:
|
|
%cp = cleanuppad within none []
|
|
call void @abort()
|
|
unreachable
|
|
|
|
unreachable:
|
|
unreachable
|
|
}
|
|
|
|
declare i32 @__gxx_personality_v0(...)
|
|
|
|
declare ptr @__cxa_begin_catch(ptr)
|
|
|
|
declare void @__cxa_end_catch()
|