Commit 39e602b6 authored by Sanjay Patel's avatar Sanjay Patel
Browse files

[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
parent d44b6be6
......@@ -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
......
......@@ -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;
......
......@@ -608,6 +608,16 @@ public:
/// 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
......
......@@ -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;
}
......@@ -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());
......
......@@ -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;
......
......@@ -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_different_block(i1 %b, i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_const_incoming0_different_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]]
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment