diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -569,7 +569,9 @@ /// Return true if this function can prove that V is never undef value /// or poison value. - bool isGuaranteedNotToBeUndefOrPoison(const Value *V); + bool isGuaranteedNotToBeUndefOrPoison(const Value *V, + const Instruction *CxtI = nullptr, + const DominatorTree *DT = nullptr); /// Specific patterns of select instructions we can match. enum SelectPatternFlavor { diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -5361,16 +5361,17 @@ } /// Given operands for a Freeze, see if we can fold the result. -static Value *SimplifyFreezeInst(Value *Op0) { +static Value *SimplifyFreezeInst(Value *Op0, const SimplifyQuery &Q) { // Use a utility function defined in ValueTracking. - if (llvm::isGuaranteedNotToBeUndefOrPoison(Op0)) + if (llvm::isGuaranteedNotToBeUndefOrPoison(Op0, Q.CxtI, Q.DT)) return Op0; + // We have room for improvement. return nullptr; } Value *llvm::SimplifyFreezeInst(Value *Op0, const SimplifyQuery &Q) { - return ::SimplifyFreezeInst(Op0); + return ::SimplifyFreezeInst(Op0, Q); } /// See if we can compute a simplified version of this instruction. diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4525,7 +4525,9 @@ return llvm::any_of(GuardingBranches, AllUsesGuardedByBranch); } -bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V) { +bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V, + const Instruction *CxtI, + const DominatorTree *DT) { // If the value is a freeze instruction, then it can never // be undef or poison. if (isa(V)) @@ -4558,6 +4560,30 @@ return true; } + if (CxtI) { + // If V is used as a branch condition before reaching CxtI, V cannot be + // undef or poison. + // br V, BB1, BB2 + // BB1: + // CxtI ; V cannot be undef or poison here + auto hasCond = [](const BasicBlock *BI, const Value *V) { + auto TI = BI->getTerminator(); + if (auto BI = dyn_cast(TI)) + return BI->isConditional() && BI->getCondition() == V; + else if (auto SI = dyn_cast(TI)) + return SI->getCondition() == V; + return false; + }; + + if (!DT) + return hasCond(CxtI->getParent(), V); + else { + for (auto N = DT->getNode(CxtI->getParent()); N; N = N->getIDom()) + if (hasCond(N->getBlock(), V)) + return true; + } + } + return false; } diff --git a/llvm/test/Transforms/InstSimplify/freeze.ll b/llvm/test/Transforms/InstSimplify/freeze.ll --- a/llvm/test/Transforms/InstSimplify/freeze.ll +++ b/llvm/test/Transforms/InstSimplify/freeze.ll @@ -18,3 +18,41 @@ %x = freeze i32 10 ret i32 %x } + +define i1 @brcond(i1 %c, i1 %c2) { +; CHECK-LABEL: @brcond( +; CHECK-NEXT: br i1 [[C:%.*]], label [[A:%.*]], label [[B:%.*]] +; CHECK: A: +; CHECK-NEXT: br i1 [[C2:%.*]], label [[A2:%.*]], label [[B]] +; CHECK: A2: +; CHECK-NEXT: ret i1 [[C]] +; CHECK: B: +; CHECK-NEXT: ret i1 [[C]] +; + %f = freeze i1 %c + br i1 %c, label %A, label %B +A: + br i1 %c2, label %A2, label %B +A2: + ret i1 %f +B: + ret i1 %f +} + +define i32 @brcond_switch(i32 %x) { +; CHECK-LABEL: @brcond_switch( +; CHECK-NEXT: switch i32 [[X:%.*]], label [[EXIT:%.*]] [ +; CHECK-NEXT: i32 0, label [[EXIT]] +; CHECK-NEXT: ] +; CHECK: A: +; CHECK-NEXT: ret i32 [[X]] +; CHECK: EXIT: +; CHECK-NEXT: ret i32 [[X]] +; + %fr = freeze i32 %x + switch i32 %x, label %EXIT [ i32 0, label %EXIT ] +A: + ret i32 %fr +EXIT: + ret i32 %fr +}