[llvm] 39e602b - [InstCombine] try to fold binop with phi operands
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Sat Jan 22 12:01:25 PST 2022
Author: Sanjay Patel
Date: 2022-01-22T15:00:06-05:00
New Revision: 39e602b6c4335b2572c74eaf9a666bebde7fd8b5
URL: https://github.com/llvm/llvm-project/commit/39e602b6c4335b2572c74eaf9a666bebde7fd8b5
DIFF: https://github.com/llvm/llvm-project/commit/39e602b6c4335b2572c74eaf9a666bebde7fd8b5.diff
LOG: [InstCombine] try to fold binop with phi operands
This is an alternate version of D115914 that handles/tests all binary opcodes.
I suspect that we don't see these patterns too often because -simplifycfg
would convert the minimal cases into selects rather than leave them in phi form
(note: instcombine has logic holes for combining the select patterns too though,
so that's another potential patch).
We only create a new binop in a predecessor that unconditionally branches to
the final block.
https://alive2.llvm.org/ce/z/C57M2F
https://alive2.llvm.org/ce/z/WHwAoU (not safe to speculate an sdiv for example)
https://alive2.llvm.org/ce/z/rdVUvW (but it is ok on this path)
Differential Revision: https://reviews.llvm.org/D117110
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/lib/Transforms/InstCombine/InstCombineInternal.h
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
llvm/test/Transforms/InstCombine/binop-phi-operands.ll
llvm/test/Transforms/InstCombine/zext-or-icmp.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index a2e875638d7d6..0598f751febe2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1288,6 +1288,9 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
// (A*B)+(A*C) -> A*(B+C) etc
if (Value *V = SimplifyUsingDistributiveLaws(I))
return replaceInstUsesWith(I, V);
@@ -1536,6 +1539,9 @@ Instruction *InstCombinerImpl::visitFAdd(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
if (Instruction *FoldedFAdd = foldBinOpIntoSelectOrPhi(I))
return FoldedFAdd;
@@ -1751,6 +1757,9 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
// If this is a 'B = x-(-A)', change to B = x+A.
@@ -2313,6 +2322,9 @@ Instruction *InstCombinerImpl::visitFSub(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
// Subtraction from -0.0 is the canonical form of fneg.
// fsub -0.0, X ==> fneg X
// fsub nsz 0.0, X ==> fneg nsz X
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index fe6a6c1203fd2..6bbb0251f2bc0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1872,6 +1872,9 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
// See if we can simplify any instructions used by the instruction whose sole
// purpose is to compute bits we don't care about.
if (SimplifyDemandedInstructionBits(I))
@@ -2665,6 +2668,9 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
// See if we can simplify any instructions used by the instruction whose sole
// purpose is to compute bits we don't care about.
if (SimplifyDemandedInstructionBits(I))
@@ -3553,6 +3559,9 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
if (Instruction *NewXor = foldXorToXor(I, Builder))
return NewXor;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index f92ee31a3de26..a7d1ff202e5e7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -608,6 +608,16 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
/// only possible if all operands to the PHI are constants).
Instruction *foldOpIntoPhi(Instruction &I, PHINode *PN);
+ /// For a binary operator with 2 phi operands, try to hoist the binary
+ /// operation before the phi. This can result in fewer instructions in
+ /// patterns where at least one set of phi operands simplifies.
+ /// Example:
+ /// BB3: binop (phi [X, BB1], [C1, BB2]), (phi [Y, BB1], [C2, BB2])
+ /// -->
+ /// BB1: BO = binop X, Y
+ /// BB3: phi [BO, BB1], [(binop C1, C2), BB2]
+ Instruction *foldBinopWithPhiOperands(BinaryOperator &BO);
+
/// Given an instruction with a select as one operand and a constant as the
/// other operand, try to fold the binary operator into the select arguments.
/// This also works for Cast instructions, which obviously do not have a
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 076c3134d0782..1aa10b550fc40 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -155,6 +155,9 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
if (Value *V = SimplifyUsingDistributiveLaws(I))
return replaceInstUsesWith(I, V);
@@ -450,6 +453,9 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
if (Instruction *FoldedMul = foldBinOpIntoSelectOrPhi(I))
return FoldedMul;
@@ -750,6 +756,9 @@ static bool isMultiple(const APInt &C1, const APInt &C2, APInt &Quotient,
/// division instructions.
/// Common integer divide transforms
Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
bool IsSigned = I.getOpcode() == Instruction::SDiv;
Type *Ty = I.getType();
@@ -1367,6 +1376,9 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
if (Instruction *R = foldFDivConstantDivisor(I))
return R;
@@ -1468,6 +1480,9 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
/// remainder instructions.
/// Common integer remainder transforms
Instruction *InstCombinerImpl::commonIRemTransforms(BinaryOperator &I) {
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
// The RHS is known non-zero.
@@ -1646,5 +1661,8 @@ Instruction *InstCombinerImpl::visitFRem(BinaryOperator &I) {
if (Instruction *X = foldVectorBinop(I))
return X;
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
return nullptr;
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 9acad19df9df5..17f0c5c4cff0e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -369,6 +369,9 @@ static Instruction *foldShiftOfShiftedLogic(BinaryOperator &I,
}
Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) {
+ if (Instruction *Phi = foldBinopWithPhiOperands(I))
+ return Phi;
+
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
assert(Op0->getType() == Op1->getType());
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 89c5fef18eca8..32f6a980afa8d 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1287,6 +1287,70 @@ Instruction *InstCombinerImpl::foldOpIntoPhi(Instruction &I, PHINode *PN) {
return replaceInstUsesWith(I, NewPN);
}
+Instruction *InstCombinerImpl::foldBinopWithPhiOperands(BinaryOperator &BO) {
+ // TODO: This should be similar to the incoming values check in foldOpIntoPhi:
+ // we are guarding against replicating the binop in >1 predecessor.
+ // This could miss matching a phi with 2 constant incoming values.
+ auto *Phi0 = dyn_cast<PHINode>(BO.getOperand(0));
+ auto *Phi1 = dyn_cast<PHINode>(BO.getOperand(1));
+ if (!Phi0 || !Phi1 || !Phi0->hasOneUse() || !Phi1->hasOneUse() ||
+ Phi0->getNumOperands() != 2 || Phi1->getNumOperands() != 2)
+ return nullptr;
+
+ // TODO: Remove the restriction for binop being in the same block as the phis.
+ if (BO.getParent() != Phi0->getParent() ||
+ BO.getParent() != Phi1->getParent())
+ return nullptr;
+
+ // Match a pair of incoming constants for one of the predecessor blocks.
+ BasicBlock *ConstBB, *OtherBB;
+ Constant *C0, *C1;
+ if (match(Phi0->getIncomingValue(0), m_ImmConstant(C0))) {
+ ConstBB = Phi0->getIncomingBlock(0);
+ OtherBB = Phi0->getIncomingBlock(1);
+ } else if (match(Phi0->getIncomingValue(1), m_ImmConstant(C0))) {
+ ConstBB = Phi0->getIncomingBlock(1);
+ OtherBB = Phi0->getIncomingBlock(0);
+ } else {
+ return nullptr;
+ }
+ if (!match(Phi1->getIncomingValueForBlock(ConstBB), m_ImmConstant(C1)))
+ return nullptr;
+
+ // The block that we are hoisting to must reach here unconditionally.
+ // Otherwise, we could be speculatively executing an expensive or
+ // non-speculative op.
+ auto *PredBlockBranch = dyn_cast<BranchInst>(OtherBB->getTerminator());
+ if (!PredBlockBranch || PredBlockBranch->isConditional() ||
+ !DT.isReachableFromEntry(OtherBB))
+ return nullptr;
+
+ // TODO: This check could be tightened to only apply to binops (div/rem) that
+ // are not safe to speculatively execute. But that could allow hoisting
+ // potentially expensive instructions (fdiv for example).
+ for (auto BBIter = BO.getParent()->begin(); &*BBIter != &BO; ++BBIter)
+ if (!isGuaranteedToTransferExecutionToSuccessor(&*BBIter))
+ return nullptr;
+
+ // Make a new binop in the predecessor block with the non-constant incoming
+ // values.
+ Builder.SetInsertPoint(PredBlockBranch);
+ Value *NewBO = Builder.CreateBinOp(BO.getOpcode(),
+ Phi0->getIncomingValueForBlock(OtherBB),
+ Phi1->getIncomingValueForBlock(OtherBB));
+ if (auto *NotFoldedNewBO = dyn_cast<BinaryOperator>(NewBO))
+ NotFoldedNewBO->copyIRFlags(&BO);
+
+ // Fold constants for the predecessor block with constant incoming values.
+ Constant *NewC = ConstantExpr::get(BO.getOpcode(), C0, C1);
+
+ // Replace the binop with a phi of the new values. The old phis are dead.
+ PHINode *NewPhi = PHINode::Create(BO.getType(), 2);
+ NewPhi->addIncoming(NewBO, OtherBB);
+ NewPhi->addIncoming(NewC, ConstBB);
+ return NewPhi;
+}
+
Instruction *InstCombinerImpl::foldBinOpIntoSelectOrPhi(BinaryOperator &I) {
if (!isa<Constant>(I.getOperand(1)))
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/binop-phi-operands.ll b/llvm/test/Transforms/InstCombine/binop-phi-operands.ll
index 81428e898eda2..b43081383156f 100644
--- a/llvm/test/Transforms/InstCombine/binop-phi-operands.ll
+++ b/llvm/test/Transforms/InstCombine/binop-phi-operands.ll
@@ -4,6 +4,8 @@
declare void @use(i32)
declare void @sideeffect()
+; negative test (but we could allow this?) - don't hoist to conditional predecessor block
+
define i32 @add_const_incoming0_speculative(i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @add_const_incoming0_speculative(
; CHECK-NEXT: entry:
@@ -34,11 +36,10 @@ define i32 @add_const_incoming0_nonspeculative(i1 %b, i32 %x, i32 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i32 [ 42, [[ENTRY:%.*]] ], [ [[X:%.*]], [[IF]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i32 [ 17, [[ENTRY]] ], [ [[Y:%.*]], [[IF]] ]
-; CHECK-NEXT: [[R:%.*]] = add i32 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP0]], [[IF]] ], [ 59, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
@@ -54,6 +55,8 @@ then:
ret i32 %r
}
+; negative test (but we could allow this?) - don't hoist to conditional predecessor block
+
define i32 @sub_const_incoming0(i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @sub_const_incoming0(
; CHECK-NEXT: entry:
@@ -84,11 +87,10 @@ define i32 @sub_const_incoming1(i1 %b, i32 %x, i32 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i32 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i32 [ [[Y:%.*]], [[IF]] ], [ 17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = sub i32 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[TMP0]], [[IF]] ], [ 25, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[R]]
;
entry:
@@ -109,11 +111,10 @@ define i8 @mul_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = mul i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ 17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = mul i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ -54, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -134,11 +135,10 @@ define i8 @and_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ 17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = and i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -159,11 +159,10 @@ define i8 @xor_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ 17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = xor i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 59, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -184,11 +183,10 @@ define i64 @or_const_incoming1(i1 %b, i64 %x, i64 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = or i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i64 [ [[X:%.*]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i64 [ [[Y:%.*]], [[IF]] ], [ 16, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = or i64 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i64 [ [[TMP0]], [[IF]] ], [ 19, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 [[R]]
;
entry:
@@ -209,11 +207,10 @@ define i64 @or_const_incoming01(i1 %b, i64 %x, i64 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = or i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i64 [ 3, [[ENTRY:%.*]] ], [ [[X:%.*]], [[IF]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i64 [ 16, [[ENTRY]] ], [ [[Y:%.*]], [[IF]] ]
-; CHECK-NEXT: [[R:%.*]] = or i64 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i64 [ [[TMP0]], [[IF]] ], [ 19, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 [[R]]
;
entry:
@@ -234,11 +231,10 @@ define i64 @or_const_incoming10(i1 %b, i64 %x, i64 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = or i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i64 [ [[Y:%.*]], [[IF]] ], [ 16, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i64 [ [[X:%.*]], [[IF]] ], [ 3, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = or i64 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i64 [ [[TMP0]], [[IF]] ], [ 19, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i64 [[R]]
;
entry:
@@ -254,6 +250,8 @@ then:
ret i64 %r
}
+; negative test (but we could allow this?) - don't hoist to conditional predecessor block
+
define i8 @ashr_const_incoming0_speculative(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @ashr_const_incoming0_speculative(
; CHECK-NEXT: entry:
@@ -284,11 +282,10 @@ define i8 @ashr_const_incoming0(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = ashr i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ 42, [[ENTRY:%.*]] ], [ [[X:%.*]], [[IF]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ 3, [[ENTRY]] ], [ [[Y:%.*]], [[IF]] ]
-; CHECK-NEXT: [[R:%.*]] = ashr i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 5, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -309,11 +306,10 @@ define i8 @lshr_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ 3, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = lshr i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 5, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -334,11 +330,10 @@ define i8 @shl_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = shl nuw nsw i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ 3, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = shl nuw nsw i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 80, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -384,11 +379,10 @@ define i8 @sdiv_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ -42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ 17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ -2, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -409,11 +403,10 @@ define i8 @udiv_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ -42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ 17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = udiv i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 12, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -434,11 +427,10 @@ define i8 @srem_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = srem i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ -17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = srem i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 8, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -459,11 +451,10 @@ define i8 @urem_const_incoming1(i1 %b, i8 %x, i8 %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi i8 [ [[X:%.*]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi i8 [ [[Y:%.*]], [[IF]] ], [ -17, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = urem i8 [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[TMP0]], [[IF]] ], [ 42, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[R]]
;
entry:
@@ -484,11 +475,10 @@ define float @fmul_const_incoming1(i1 %b, float %x, float %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi float [ [[X:%.*]], [[IF]] ], [ 4.200000e+01, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi float [ [[Y:%.*]], [[IF]] ], [ 1.700000e+01, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = fmul float [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi float [ [[TMP0]], [[IF]] ], [ 7.140000e+02, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret float [[R]]
;
entry:
@@ -509,11 +499,10 @@ define float @fadd_const_incoming1(i1 %b, float %x, float %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = fadd fast float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi float [ [[X:%.*]], [[IF]] ], [ 4.200000e+01, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi float [ [[Y:%.*]], [[IF]] ], [ 1.700000e+01, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = fadd fast float [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi float [ [[TMP0]], [[IF]] ], [ 5.900000e+01, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret float [[R]]
;
entry:
@@ -534,11 +523,10 @@ define float @fsub_const_incoming1(i1 %b, float %x, float %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = fsub nnan ninf float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi float [ [[X:%.*]], [[IF]] ], [ 4.200000e+01, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi float [ [[Y:%.*]], [[IF]] ], [ 1.700000e+01, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = fsub nnan ninf float [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi float [ [[TMP0]], [[IF]] ], [ 2.500000e+01, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret float [[R]]
;
entry:
@@ -559,11 +547,10 @@ define float @frem_const_incoming1(i1 %b, float %x, float %y) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[B:%.*]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK: if:
+; CHECK-NEXT: [[TMP0:%.*]] = frem nsz float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br label [[THEN]]
; CHECK: then:
-; CHECK-NEXT: [[P0:%.*]] = phi float [ [[X:%.*]], [[IF]] ], [ 4.200000e+01, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[P1:%.*]] = phi float [ [[Y:%.*]], [[IF]] ], [ 1.700000e+01, [[ENTRY]] ]
-; CHECK-NEXT: [[R:%.*]] = frem nsz float [[P0]], [[P1]]
+; CHECK-NEXT: [[R:%.*]] = phi float [ [[TMP0]], [[IF]] ], [ 8.000000e+00, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret float [[R]]
;
entry:
@@ -658,6 +645,9 @@ then:
ret i64 %r
}
+; The mul could be hoisted before the call that may not return
+; if we are ok with speculating a potentially expensive op.
+
define i8 @mul_const_incoming0_speculatable(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @mul_const_incoming0_speculatable(
; CHECK-NEXT: entry:
@@ -685,6 +675,8 @@ then:
ret i8 %r
}
+; The udiv should never be hoisted before the call that may not return.
+
define i8 @udiv_const_incoming0_not_speculatable(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_const_incoming0_not_speculatable(
; CHECK-NEXT: entry:
@@ -712,6 +704,8 @@ then:
ret i8 %r
}
+; TODO: It is ok to hoist the udiv even though it is not in the same block as the phis.
+
define i8 @udiv_const_incoming0_
diff erent_block(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_const_incoming0_
diff erent_block(
; CHECK-NEXT: entry:
@@ -750,20 +744,10 @@ define { i64, i32 } @ParseRetVal(i1 %b, { i64, i32 } ()* %x) {
; CHECK-NEXT: [[T4:%.*]] = tail call { i64, i32 } [[X:%.*]]()
; CHECK-NEXT: [[T5:%.*]] = extractvalue { i64, i32 } [[T4]], 0
; CHECK-NEXT: [[T6:%.*]] = extractvalue { i64, i32 } [[T4]], 1
-; CHECK-NEXT: [[T7:%.*]] = and i64 [[T5]], -4294967296
-; CHECK-NEXT: [[T8:%.*]] = and i64 [[T5]], 4294901760
-; CHECK-NEXT: [[T9:%.*]] = and i64 [[T5]], 65280
-; CHECK-NEXT: [[T10:%.*]] = and i64 [[T5]], 255
; CHECK-NEXT: br label [[F]]
; CHECK: f:
-; CHECK-NEXT: [[T12:%.*]] = phi i64 [ [[T10]], [[T]] ], [ 0, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[T13:%.*]] = phi i64 [ [[T9]], [[T]] ], [ 0, [[ENTRY]] ]
-; CHECK-NEXT: [[T14:%.*]] = phi i64 [ [[T8]], [[T]] ], [ 0, [[ENTRY]] ]
-; CHECK-NEXT: [[T15:%.*]] = phi i64 [ [[T7]], [[T]] ], [ 0, [[ENTRY]] ]
-; CHECK-NEXT: [[T16:%.*]] = phi i32 [ [[T6]], [[T]] ], [ 0, [[ENTRY]] ]
-; CHECK-NEXT: [[T17:%.*]] = or i64 [[T13]], [[T12]]
-; CHECK-NEXT: [[T18:%.*]] = or i64 [[T17]], [[T14]]
-; CHECK-NEXT: [[T19:%.*]] = or i64 [[T18]], [[T15]]
+; CHECK-NEXT: [[T16:%.*]] = phi i32 [ [[T6]], [[T]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[T19:%.*]] = phi i64 [ [[T5]], [[T]] ], [ 0, [[ENTRY]] ]
; CHECK-NEXT: [[T20:%.*]] = insertvalue { i64, i32 } poison, i64 [[T19]], 0
; CHECK-NEXT: [[T21:%.*]] = insertvalue { i64, i32 } [[T20]], i32 [[T16]], 1
; CHECK-NEXT: ret { i64, i32 } [[T21]]
diff --git a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
index 6b7f1d029cb67..68d1e8addd35a 100644
--- a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
+++ b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
@@ -46,11 +46,7 @@ define i32 @dont_widen_undef() {
; CHECK: block1:
; CHECK-NEXT: br label [[BLOCK2]]
; CHECK: block2:
-; CHECK-NEXT: [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ]
-; CHECK-NEXT: [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]]
-; CHECK-NEXT: [[CONV2:%.*]] = zext i1 [[CMP1]] to i32
-; CHECK-NEXT: ret i32 [[CONV2]]
+; CHECK-NEXT: ret i32 1
;
entry:
br label %block2
@@ -76,11 +72,7 @@ define i32 @dont_widen_undef_logical() {
; CHECK: block1:
; CHECK-NEXT: br label [[BLOCK2]]
; CHECK: block2:
-; CHECK-NEXT: [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ]
-; CHECK-NEXT: [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]]
-; CHECK-NEXT: [[CONV2:%.*]] = zext i1 [[CMP1]] to i32
-; CHECK-NEXT: ret i32 [[CONV2]]
+; CHECK-NEXT: ret i32 1
;
entry:
br label %block2
More information about the llvm-commits
mailing list