mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-18 18:42:46 +02:00
[SimplifyCFG] simplifyUnreachable(): erase instructions iff they are guaranteed to transfer execution to unreachable
This replaces the current ad-hoc implementation, by syncing the code from InstCombine's implementation in `InstCombinerImpl::visitUnreachableInst()`, with one exception that here in SimplifyCFG we are allowed to remove EH instructions. Effectively, this now allows SimplifyCFG to remove calls (iff they won't throw and will return), arithmetic/logic operations, etc. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D105374
This commit is contained in:
parent
c41e03ba29
commit
aec6b731b1
@ -26,6 +26,7 @@
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/AssumeBundleQueries.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/Analysis/EHPersonalities.h"
|
||||
#include "llvm/Analysis/GuardUtils.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/Loads.h"
|
||||
@ -5273,6 +5274,18 @@ bool llvm::isGuaranteedToTransferExecutionToSuccessor(const Instruction *I) {
|
||||
if (isa<UnreachableInst>(I))
|
||||
return false;
|
||||
|
||||
if (isa<CatchPadInst>(I)) {
|
||||
switch (classifyEHPersonality(I->getFunction()->getPersonalityFn())) {
|
||||
default:
|
||||
// A catchpad may invoke exception object constructors and such, which
|
||||
// in some languages can be arbitrary code, so be conservative by default.
|
||||
return false;
|
||||
case EHPersonality::CoreCLR:
|
||||
// For CoreCLR, it just involves a type test.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// An instruction that returns without throwing must transfer control flow
|
||||
// to a successor.
|
||||
return !I->mayThrow() && I->willReturn();
|
||||
|
@ -2870,6 +2870,7 @@ Instruction *InstCombinerImpl::visitReturnInst(ReturnInst &RI) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// WARNING: keep in sync with SimplifyCFGOpt::simplifyUnreachable()!
|
||||
Instruction *InstCombinerImpl::visitUnreachableInst(UnreachableInst &I) {
|
||||
// Try to remove the previous instruction if it must lead to unreachable.
|
||||
// This includes instructions like stores and "llvm.assume" that may not get
|
||||
|
@ -4655,6 +4655,7 @@ bool SimplifyCFGOpt::simplifyReturn(ReturnInst *RI, IRBuilder<> &Builder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// WARNING: keep in sync with InstCombinerImpl::visitUnreachableInst()!
|
||||
bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
|
||||
BasicBlock *BB = UI->getParent();
|
||||
|
||||
@ -4665,39 +4666,24 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
|
||||
while (UI->getIterator() != BB->begin()) {
|
||||
BasicBlock::iterator BBI = UI->getIterator();
|
||||
--BBI;
|
||||
// Do not delete instructions that can have side effects which might cause
|
||||
// the unreachable to not be reachable; specifically, calls and volatile
|
||||
// operations may have this effect.
|
||||
if (isa<CallInst>(BBI) && !isa<DbgInfoIntrinsic>(BBI))
|
||||
break;
|
||||
|
||||
if (BBI->mayHaveSideEffects()) {
|
||||
if (auto *SI = dyn_cast<StoreInst>(BBI)) {
|
||||
if (!isGuaranteedToTransferExecutionToSuccessor(&*BBI))
|
||||
break; // Can not drop any more instructions. We're done here.
|
||||
// Otherwise, this instruction can be freely erased,
|
||||
// even if it is not side-effect free.
|
||||
|
||||
// Temporarily disable removal of volatile stores preceding unreachable,
|
||||
// pending a potential LangRef change permitting volatile stores to
|
||||
// trap.
|
||||
// pending a potential LangRef change permitting volatile stores to trap.
|
||||
// TODO: Either remove this code, or properly integrate the check into
|
||||
// isGuaranteedToTransferExecutionToSuccessor().
|
||||
if (auto *SI = dyn_cast<StoreInst>(&*BBI))
|
||||
if (SI->isVolatile())
|
||||
break;
|
||||
} else if (isa<CatchPadInst>(BBI)) {
|
||||
// A catchpad may invoke exception object constructors and such, which
|
||||
// in some languages can be arbitrary code, so be conservative by
|
||||
// default.
|
||||
// For CoreCLR, it just involves a type test, so can be removed.
|
||||
if (classifyEHPersonality(BB->getParent()->getPersonalityFn()) !=
|
||||
EHPersonality::CoreCLR)
|
||||
break;
|
||||
} else if (!isa<LoadInst>(BBI) && !isa<AtomicRMWInst>(BBI) &&
|
||||
!isa<AtomicCmpXchgInst>(BBI) && !isa<FenceInst>(BBI) &&
|
||||
!isa<VAArgInst>(BBI) && !isa<LandingPadInst>(BBI)) {
|
||||
break;
|
||||
}
|
||||
// Note that deleting LandingPad's here is in fact okay, although it
|
||||
// involves a bit of subtle reasoning. If this inst is a LandingPad,
|
||||
// all the predecessors of this block will be the unwind edges of Invokes,
|
||||
break; // Can not drop this instruction. We're done here.
|
||||
|
||||
// Note that deleting EH's here is in fact okay, although it involves a bit
|
||||
// of subtle reasoning. If this inst is an EH, all the predecessors of this
|
||||
// block will be the unwind edges of Invoke/CatchSwitch/CleanupReturn,
|
||||
// and we can therefore guarantee this block will be erased.
|
||||
}
|
||||
|
||||
// Delete this instruction (any uses are guaranteed to be dead)
|
||||
BBI->replaceAllUsesWith(PoisonValue::get(BBI->getType()));
|
||||
|
@ -74,9 +74,11 @@ define void @Bork(i64 %range.0.0, i64 %range.0.1, i64 %size) personality i32 (..
|
||||
; CHECK-NEXT: .LBB0_6: # %unwind.loopexit
|
||||
; CHECK-NEXT: .Ltmp5:
|
||||
; CHECK-NEXT: .LBB0_7: # %unwind
|
||||
; CHECK-NEXT: ld 3, 0(1)
|
||||
; CHECK-NEXT: ld 4, 0(1)
|
||||
; CHECK-NEXT: mr 1, 27
|
||||
; CHECK-NEXT: std 3, 0(1)
|
||||
; CHECK-NEXT: std 4, 0(1)
|
||||
; CHECK-NEXT: bl _Unwind_Resume
|
||||
; CHECK-NEXT: nop
|
||||
entry:
|
||||
%effectiveRange = alloca %struct.Range, align 8 ; <%struct.Range*> [#uses=2]
|
||||
%tmp4 = call i8* @llvm.stacksave() ; <i8*> [#uses=1]
|
||||
@ -91,7 +93,7 @@ bb30.preheader: ; preds = %entry
|
||||
|
||||
unwind: ; preds = %cond_true, %entry
|
||||
%exn = landingpad {i8*, i32}
|
||||
catch i8* null
|
||||
cleanup
|
||||
call void @llvm.stackrestore(i8* %tmp4)
|
||||
resume { i8*, i32 } %exn
|
||||
|
||||
|
@ -8,9 +8,6 @@
|
||||
define void @widget() {
|
||||
; CHECK-LABEL: @widget(
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[I:%.*]] = load i16, i16* @global, align 1
|
||||
; CHECK-NEXT: [[I13:%.*]] = icmp ne i16 [[I]], 0
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[I13]])
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
bb:
|
||||
|
@ -116,8 +116,6 @@ b:
|
||||
define void @PR42737(i32* %a, i1 %c) {
|
||||
; CHECK-LABEL: @PR42737(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
entry:
|
||||
|
Loading…
Reference in New Issue
Block a user