[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:
Jun Bum Lim 2016-02-11 15:50:07 +00:00
parent a25f0be03b
commit 885a68b0cf
2 changed files with 131 additions and 0 deletions

View File

@ -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

View File

@ -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
}