Files
clang-p2996/llvm/test/Transforms/SimplifyCFG/invoke.ll
Roman Lebedev 18ff1ec3c3 Reland [SimplifyCFG] markAliveBlocks(): recognize that normal dest of invoked noreturn function is unreachable
As per LangRef's definition of `noreturn` attribute:
```
noreturn
  This function attribute indicates that the function never returns
  normally, hence through a return instruction.
  This produces undefined behavior at runtime if the function
  ever does dynamically return. nnotated functions may still
  raise an exception, i.a., nounwind is not implied.
```

So if we `invoke` a `noreturn` function, and the normal destination
of an invoke is not an `unreachable`, point it at the new `unreachable`
block.

The change/fix from the original commit is that we now actually create
the new block, and don't just repurpose the original block,
because said normal destination block could have other users.

This reverts commit db1176ce66,
relanding commit 598833c987.
2022-02-05 02:58:19 +03:00

281 lines
8.0 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
declare i32 @__gxx_personality_v0(...)
declare void @__cxa_call_unexpected(i8*)
declare void @purefn() nounwind readnone
declare i32 @read_only() nounwind readonly
declare i32 @nounwind_fn() nounwind
declare i32 @fn()
define i8* @f1() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @f1(
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%call = invoke noalias i8* undef()
to label %invoke.cont unwind label %lpad
invoke.cont:
ret i8* %call
lpad:
%0 = landingpad { i8*, i32 }
filter [0 x i8*] zeroinitializer
%1 = extractvalue { i8*, i32 } %0, 0
tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind
unreachable
}
define i8* @f2() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @f2(
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%call = invoke noalias i8* null()
to label %invoke.cont unwind label %lpad
invoke.cont:
ret i8* %call
lpad:
%0 = landingpad { i8*, i32 }
filter [0 x i8*] zeroinitializer
%1 = extractvalue { i8*, i32 } %0, 0
tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind
unreachable
}
define i8* @f2_no_null_opt() nounwind uwtable ssp #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @f2_no_null_opt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = invoke noalias i8* null()
; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
; CHECK: invoke.cont:
; CHECK-NEXT: ret i8* [[CALL]]
; CHECK: lpad:
; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: filter [0 x i8*] zeroinitializer
; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0
; CHECK-NEXT: tail call void @__cxa_call_unexpected(i8* [[TMP1]]) #[[ATTR6:[0-9]+]]
; CHECK-NEXT: unreachable
;
entry:
%call = invoke noalias i8* null()
to label %invoke.cont unwind label %lpad
invoke.cont:
ret i8* %call
lpad:
%0 = landingpad { i8*, i32 }
filter [0 x i8*] zeroinitializer
%1 = extractvalue { i8*, i32 } %0, 0
tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind
unreachable
}
define i32 @f3() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @f3(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 3
;
entry:
%call = invoke i32 @read_only()
to label %invoke.cont unwind label %lpad
invoke.cont:
ret i32 3
lpad:
%0 = landingpad { i8*, i32 }
filter [0 x i8*] zeroinitializer
%1 = extractvalue { i8*, i32 } %0, 0
tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind
unreachable
}
define i32 @f4() nounwind uwtable ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @f4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @read_only()
; CHECK-NEXT: ret i32 [[CALL]]
;
entry:
%call = invoke i32 @read_only()
to label %invoke.cont unwind label %lpad
invoke.cont:
ret i32 %call
lpad:
%0 = landingpad { i8*, i32 }
filter [0 x i8*] zeroinitializer
%1 = extractvalue { i8*, i32 } %0, 0
tail call void @__cxa_call_unexpected(i8* %1) noreturn nounwind
unreachable
}
define i32 @f5(i1 %cond, i8* %a, i8* %b) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @f5(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[X:%.*]], label [[Y:%.*]]
; CHECK: x:
; CHECK-NEXT: [[CALL:%.*]] = invoke i32 @fn()
; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[LPAD:%.*]]
; CHECK: y:
; CHECK-NEXT: [[CALL2:%.*]] = call i32 @nounwind_fn()
; CHECK-NEXT: br label [[CONT]]
; CHECK: cont:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[CALL]], [[X]] ], [ [[CALL2]], [[Y]] ]
; CHECK-NEXT: ret i32 [[PHI]]
; CHECK: lpad:
; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: filter [0 x i8*] zeroinitializer
; CHECK-NEXT: tail call void @__cxa_call_unexpected(i8* [[A:%.*]]) #[[ATTR6]]
; CHECK-NEXT: unreachable
;
entry:
br i1 %cond, label %x, label %y
x:
%call = invoke i32 @fn()
to label %cont unwind label %lpad
y:
%call2 = invoke i32 @nounwind_fn()
to label %cont unwind label %lpad
cont:
%phi = phi i32 [%call, %x], [%call2, %y]
ret i32 %phi
lpad:
%phi2 = phi i8* [%a, %x], [%b, %y]
%0 = landingpad { i8*, i32 }
filter [0 x i8*] zeroinitializer
tail call void @__cxa_call_unexpected(i8* %phi2) noreturn nounwind
unreachable
}
define void @f6() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @f6(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[FOO:%.*]] = invoke i32 @fn()
; CHECK-NEXT: to label [[COMMON_RET:%.*]] unwind label [[LPAD:%.*]]
; CHECK: common.ret:
; CHECK-NEXT: ret void
; CHECK: lpad:
; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[COMMON_RET]]
;
entry:
invoke void @purefn()
to label %invoke.cont1 unwind label %lpad
invoke.cont1:
%foo = invoke i32 @fn()
to label %invoke.cont2 unwind label %lpad
invoke.cont2:
ret void
lpad:
%tmp = phi i8* [ null, %invoke.cont1 ], [ null, %entry ]
landingpad { i8*, i32 }
cleanup
ret void
}
define void @invoke_of_noreturn() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @invoke_of_noreturn(
; CHECK-NEXT: entry:
; CHECK-NEXT: invoke void @simple_throw()
; CHECK-NEXT: to label [[INVOKE_CONT_UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
; CHECK: invoke.cont.unreachable:
; CHECK-NEXT: unreachable
; CHECK: lpad:
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call void @sideeffect(i32 1)
; CHECK-NEXT: resume { i8*, i32 } [[EH]]
;
entry:
invoke void @simple_throw() to label %invoke.cont unwind label %lpad
invoke.cont:
call void @sideeffect(i32 0)
ret void
lpad:
%eh = landingpad { i8*, i32 } cleanup
call void @sideeffect(i32 1)
resume { i8*, i32 } %eh
}
define void @invoke_of_noreturn_with_shared_normal_destination(i1 %c) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @invoke_of_noreturn_with_shared_normal_destination(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[INVOKE:%.*]], label [[INVOKE_CONT:%.*]]
; CHECK: invoke:
; CHECK-NEXT: invoke void @simple_throw()
; CHECK-NEXT: to label [[INVOKE_CONT_UNREACHABLE:%.*]] unwind label [[LPAD:%.*]]
; CHECK: invoke.cont.unreachable:
; CHECK-NEXT: unreachable
; CHECK: invoke.cont:
; CHECK-NEXT: call void @sideeffect(i32 -1)
; CHECK-NEXT: ret void
; CHECK: lpad:
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call void @sideeffect(i32 1)
; CHECK-NEXT: resume { i8*, i32 } [[EH]]
;
entry:
br i1 %c, label %invoke, label %invoke.cont
invoke:
invoke void @simple_throw() to label %invoke.cont unwind label %lpad
invoke.cont:
%r = phi i32 [ 0, %invoke ], [ -1, %entry ]
call void @sideeffect(i32 %r)
ret void
lpad:
%eh = landingpad { i8*, i32 } cleanup
call void @sideeffect(i32 1)
resume { i8*, i32 } %eh
}
define void @invoke_of_nounwind() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: @invoke_of_nounwind(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @simple_return()
; CHECK-NEXT: call void @sideeffect(i32 0)
; CHECK-NEXT: ret void
;
entry:
invoke void @simple_return() to label %invoke.cont unwind label %lpad
invoke.cont:
call void @sideeffect(i32 0)
ret void
lpad:
%eh = landingpad { i8*, i32 } cleanup
call void @sideeffect(i32 1)
resume { i8*, i32 } %eh
}
declare void @simple_throw() noreturn
declare void @simple_return() nounwind
declare void @sideeffect(i32 )
attributes #0 = { null_pointer_is_valid }