Index: llvm/trunk/lib/Transforms/InstCombine/InstCombinePHI.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -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 @@ return true; } +/// Return an existing non-zero constant if this phi node has, otherwise ruturn +/// constant 1. +static ConstantInt *GetAnyNonZeroConstInt(PHINode &PN) { + assert(isa(PN.getType()) && "Expect only intger type phi"); + for (Value *V : PN.operands()) + if (auto *ConstVA = dyn_cast(V)) + if (!ConstVA->isZeroValue()) + return ConstVA; + return ConstantInt::get(cast(PN.getType()), 1); +} namespace { struct PHIUsageRecord { @@ -919,6 +932,29 @@ 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(PHIUser); + // FIXME: To be simple, handle only integer type for now. + if (CmpInst && isa(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 Index: llvm/trunk/test/Transforms/InstCombine/phi.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/phi.ll +++ llvm/trunk/test/Transforms/InstCombine/phi.ll @@ -784,3 +784,98 @@ 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 +}