mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-13 06:38:44 +00:00
[InstCombine] Simplify a known nonzero incoming value of PHI
Summary: When a PHI is used only to be compared with zero, it is possible to replace an incoming value with any non-zero constant if the incoming value can be proved as a known nonzero value. For example, in below code, we can replace the incoming value %v with any non-zero constant based on the fact that the PHI is only used to be compared with zero and %v is a known non-zero value: %v = select %cond, 1, 2 %p = phi [%v, BB] ... %c = icmp eq, %p, 0 Reviewers: mcrosier, jmolloy, sanjoy Subscribers: hfinkel, mcrosier, majnemer, llvm-commits, haicheng, bmakam, mssimpso, gberry Differential Revision: http://reviews.llvm.org/D16240 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@260530 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a25f0be03b
commit
885a68b0cf
@ -15,8 +15,11 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
using namespace llvm;
|
||||
using namespace llvm::PatternMatch;
|
||||
|
||||
#define DEBUG_TYPE "instcombine"
|
||||
|
||||
@ -641,6 +644,16 @@ static bool PHIsEqualValue(PHINode *PN, Value *NonPhiInVal,
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return an existing non-zero constant if this phi node has, otherwise ruturn
|
||||
/// constant 1.
|
||||
static ConstantInt *GetAnyNonZeroConstInt(PHINode &PN) {
|
||||
assert(isa<IntegerType>(PN.getType()) && "Expect only intger type phi");
|
||||
for (Value *V : PN.operands())
|
||||
if (auto *ConstVA = dyn_cast<ConstantInt>(V))
|
||||
if (!ConstVA->isZeroValue())
|
||||
return ConstVA;
|
||||
return ConstantInt::get(cast<IntegerType>(PN.getType()), 1);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct PHIUsageRecord {
|
||||
@ -919,6 +932,29 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) {
|
||||
PHIUser->user_back() == &PN) {
|
||||
return replaceInstUsesWith(PN, UndefValue::get(PN.getType()));
|
||||
}
|
||||
// When a PHI is used only to be compared with zero, it is safe to replace
|
||||
// an incoming value proved as known nonzero with any non-zero constant.
|
||||
// For example, in below code, the incoming value %v can be replaced with
|
||||
// any non-zero constant based on the fact that the PHI is only used to be
|
||||
// compared with zero and %v is a known non-zero value:
|
||||
// %v = select %cond, 1, 2
|
||||
// %p = phi [%v, BB] ...
|
||||
// icmp eq, %p, 0
|
||||
auto *CmpInst = dyn_cast<ICmpInst>(PHIUser);
|
||||
// FIXME: To be simple, handle only integer type for now.
|
||||
if (CmpInst && isa<IntegerType>(PN.getType()) && CmpInst->isEquality() &&
|
||||
match(CmpInst->getOperand(1), m_Zero())) {
|
||||
ConstantInt *NonZeroConst = nullptr;
|
||||
for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) {
|
||||
Instruction *CtxI = PN.getIncomingBlock(i)->getTerminator();
|
||||
Value *VA = PN.getIncomingValue(i);
|
||||
if (isKnownNonZero(VA, DL, 0, AC, CtxI, DT)) {
|
||||
if (!NonZeroConst)
|
||||
NonZeroConst = GetAnyNonZeroConstInt(PN);
|
||||
PN.setIncomingValue(i, NonZeroConst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We sometimes end up with phi cycles that non-obviously end up being the
|
||||
|
@ -784,3 +784,98 @@ if.end: ; preds = %if.else, %if.then
|
||||
|
||||
declare void @dummy()
|
||||
|
||||
; CHECK-LABEL: @phi_knownnonzero_eq
|
||||
; CHECK-LABEL: if.then:
|
||||
; CHECK-NOT: select
|
||||
; CHECK-LABEL: if.end:
|
||||
; CHECK: phi i32 [ 1, %if.then ]
|
||||
define i1 @phi_knownnonzero_eq(i32 %n, i32 %s, i32* nocapture readonly %P) {
|
||||
entry:
|
||||
%tobool = icmp slt i32 %n, %s
|
||||
br i1 %tobool, label %if.end, label %if.then
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%0 = load i32, i32* %P
|
||||
%cmp = icmp eq i32 %n, %0
|
||||
%1 = select i1 %cmp, i32 1, i32 2
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %entry, %if.then
|
||||
%a.0 = phi i32 [ %1, %if.then ], [ %n, %entry ]
|
||||
%cmp1 = icmp eq i32 %a.0, 0
|
||||
ret i1 %cmp1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @phi_knownnonzero_ne
|
||||
; CHECK-LABEL: if.then:
|
||||
; CHECK-NOT: select
|
||||
; CHECK-LABEL: if.end:
|
||||
; CHECK: phi i32 [ 1, %if.then ]
|
||||
define i1 @phi_knownnonzero_ne(i32 %n, i32 %s, i32* nocapture readonly %P) {
|
||||
entry:
|
||||
%tobool = icmp slt i32 %n, %s
|
||||
br i1 %tobool, label %if.end, label %if.then
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%0 = load i32, i32* %P
|
||||
%cmp = icmp eq i32 %n, %0
|
||||
%1 = select i1 %cmp, i32 1, i32 2
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %entry, %if.then
|
||||
%a.0 = phi i32 [ %1, %if.then ], [ %n, %entry ]
|
||||
%cmp1 = icmp ne i32 %a.0, 0
|
||||
ret i1 %cmp1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @phi_knownnonzero_eq_2
|
||||
; CHECK-LABEL: if.then:
|
||||
; CHECK-NOT: select
|
||||
; CHECK-LABEL: if.end:
|
||||
; CHECK: phi i32 [ 2, %if.else ]
|
||||
define i1 @phi_knownnonzero_eq_2(i32 %n, i32 %s, i32* nocapture readonly %P) {
|
||||
entry:
|
||||
%tobool = icmp slt i32 %n, %s
|
||||
br i1 %tobool, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
%tobool2 = icmp slt i32 %n, %s
|
||||
br i1 %tobool2, label %if.else, label %if.end
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%0 = load i32, i32* %P
|
||||
%cmp = icmp eq i32 %n, %0
|
||||
%1 = select i1 %cmp, i32 1, i32 2
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %entry, %if.then
|
||||
%a.0 = phi i32 [ %1, %if.else], [ %n, %entry ], [2, %if.then]
|
||||
%cmp1 = icmp eq i32 %a.0, 0
|
||||
ret i1 %cmp1
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @phi_knownnonzero_ne_2
|
||||
; CHECK-LABEL: if.then:
|
||||
; CHECK-NOT: select
|
||||
; CHECK-LABEL: if.end:
|
||||
; CHECK: phi i32 [ 2, %if.else ]
|
||||
define i1 @phi_knownnonzero_ne_2(i32 %n, i32 %s, i32* nocapture readonly %P) {
|
||||
entry:
|
||||
%tobool = icmp slt i32 %n, %s
|
||||
br i1 %tobool, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
%tobool2 = icmp slt i32 %n, %s
|
||||
br i1 %tobool2, label %if.else, label %if.end
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%0 = load i32, i32* %P
|
||||
%cmp = icmp eq i32 %n, %0
|
||||
%1 = select i1 %cmp, i32 1, i32 2
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %entry, %if.then
|
||||
%a.0 = phi i32 [ %1, %if.else], [ %n, %entry ], [2, %if.then]
|
||||
%cmp1 = icmp ne i32 %a.0, 0
|
||||
ret i1 %cmp1
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user