Index: lib/Transforms/InstCombine/InstCombinePHI.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombinePHI.cpp +++ lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -781,6 +781,108 @@ return ReplaceInstUsesWith(FirstPhi, Undef); } +// If a PHI node has two edges and the PHI node is used in instructions like +// add, sub, mul, div, shifts; if one of incoming values is a constant +// that makes the instruction and identity operation, we can hoist this +// instruction into one of the basic blocks. +// Because of such a transformation, the identity operation won't be +// executed, since it doesn't contribute to the result. +// +static Instruction *PartiallySimplifyIdentityOps(PHINode &PN, const Constant &C, + Value &IncomingVal, + Instruction &PNUser, + InstCombiner &IC) { + if (!PNUser.isBinaryOp()) + return nullptr; + if (PN.getParent() != PNUser.getParent()) + return nullptr; + + // C IncomingVal + // \ / + // \ 0 1 / -- (IncomingValIdx) + // \ / + // PN = phi [C , ...] [ IncomingVal, BB ] + // ... + // 0 1 -- (OpOperandIdx) + // PNUser = op PN, x + + + const unsigned IncomingValIdx = + (&IncomingVal == PN.getIncomingValue(0)) ? 0 : 1; + const unsigned OpOperandIdx = (&PN == PNUser.getOperand(0)) ? 1 : 0; + + // Exit if not an identity operation. + // For everything except add Add and Mul constant must be on the RHS. + switch (PNUser.getOpcode()) { + default: + return nullptr; + case Instruction::Add: + if (!C.isZeroValue()) + return nullptr; + break; + + case Instruction::Sub: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + if (!C.isZeroValue() || OpOperandIdx == 1) + return nullptr; + break; + + case Instruction::Mul: + if (!C.isOneValue()) + return nullptr; + break; + + case Instruction::UDiv: + case Instruction::SDiv: + if (!C.isOneValue() || OpOperandIdx == 1) + return nullptr; + break; + } + + BasicBlock *BB = PN.getIncomingBlock(IncomingValIdx); + auto *Terminator = BB->getTerminator(); + + if (const auto *Incoming = dyn_cast(&IncomingVal)) + if (!IC.getDominatorTree()->dominates(Incoming, Terminator)) + return nullptr; + + // Operand must be available in newly generated instruction and + // as an incoming value of the PHI node. + if (const auto *Operand = + dyn_cast(PNUser.getOperand(OpOperandIdx))) + if (!IC.getDominatorTree()->dominates(Operand, Terminator) || + !IC.getDominatorTree()->dominates(Operand, &PN)) + return nullptr; + + // Ensure that the non-constant value in the PHI node doesn't come + // from the same BasicBlock as the PHI node. This prevents errors + // that could appear with loops (loop backedge could have this + // problem). + if (PN.getIncomingBlock(IncomingValIdx) == PN.getParent()) + return nullptr; + + Value *LHS = &IncomingVal, *RHS = PNUser.getOperand(OpOperandIdx); + if (OpOperandIdx == 0) + std::swap(LHS, RHS); + + // Add new instruction to one of the edges. + IRBuilder<> Builder(Terminator); + auto *NewInst = + Builder.CreateBinOp(cast(PNUser).getOpcode(), LHS, RHS); + cast(NewInst)->copyIRFlags(&PNUser); + + // The new incoming values are: + // - result of the newly emmited instruction + // - operand of the instruction + PN.setIncomingValue(IncomingValIdx, NewInst); + PN.setIncomingValue(IncomingValIdx == 0 ? 1 : 0, + PNUser.getOperand(OpOperandIdx)); + IC.ReplaceInstUsesWith(PNUser, &PN); + return &PN; +} + // PHINode simplification // Instruction *InstCombiner::visitPHINode(PHINode &PN) { @@ -822,6 +924,20 @@ PHIUser->user_back() == &PN) { return ReplaceInstUsesWith(PN, UndefValue::get(PN.getType())); } + + // If this phi has one use, exactly 2 edges and one is a constant, we + // may be able to apply the PartiallySimplifyIdentityOps optimization. + if (PN.getNumIncomingValues() == 2) { + const Constant *C = dyn_cast(PN.getIncomingValue(0)); + Value *Val = PN.getIncomingValue(1); + if (!C) { + C = dyn_cast(PN.getIncomingValue(1)); + Val = PN.getIncomingValue(0); + } + if (C && !isa(Val)) + if (auto *I = PartiallySimplifyIdentityOps(PN, *C, *Val, *PHIUser, *this)) + return I; + } } // We sometimes end up with phi cycles that non-obviously end up being the Index: test/Transforms/InstCombine/phi.ll =================================================================== --- test/Transforms/InstCombine/phi.ll +++ test/Transforms/InstCombine/phi.ll @@ -247,8 +247,9 @@ ret i64 %tmp2 ; CHECK-LABEL: @test12( ; CHECK-NOT: zext +; CHECK: %[[X:.*]] = add i64 %{{.*}}, %Val ; CHECK: end: -; CHECK-NEXT: phi i64 [ 0, %entry ], [ %Val, %two ] +; CHECK-NEXT: phi i64 [ %tmp41, %entry ], [ %[[X]], %two ] ; CHECK-NOT: phi ; CHECK: ret i64 } @@ -630,3 +631,124 @@ %y = phi i32 [ undef, %entry ] ret i32 %y } + +; CHECK-LABEL: @test28( +; CHECK add nsw i32 %x, %dfd +; CHECK: if.end: +; CHECK-NEXT: phi i32 [ %{{.*}}, %if.else ], [ %x, %entry ] +; CHECK-NEXT: ret +define i32 @test28(i1* nocapture readonly %cond, i32* nocapture readonly %a, i32 %x, i32 %v) { +entry: + %0 = load volatile i1, i1* %cond, align 1 + br i1 %0, label %if.else, label %if.end + +if.else: + %1 = load volatile i32, i32* %a, align 4 + br label %if.end + +if.end: + %v.addr.0 = phi i32 [ %1, %if.else ], [ 0, %entry ] + %div = add nsw i32 %x, %v.addr.0 + ret i32 %div +} + +; CHECK-LABEL: @test29( +; CHECK: ashr i32 %x, %1 +; CHECK: if.end: +; CHECK-NEXT: phi i32 [ %{{.*}}, %if.else ], [ %x, %entry ] +; CHECK-NEXT: ret +define i32 @test29(i1* nocapture readonly %cond, i32* nocapture readonly %a, i32 %x, i32 %v) { +entry: + %0 = load volatile i1, i1* %cond, align 1 + br i1 %0, label %if.else, label %if.end + +if.else: + %1 = load volatile i32, i32* %a, align 4 + br label %if.end + +if.end: + %v.addr.0 = phi i32 [ %1, %if.else ], [ 0, %entry ] + %div = ashr i32 %x, %v.addr.0 + ret i32 %div +} + +; CHECK-LABEL: @test30( +; CHECK: sdiv i32 %x, %1 +; CHECK: if.end: +; CHECK-NEXT: phi i32 [ %{{.*}}, %if.else ], [ %x, %entry ] +; CHECK-NEXT: ret +define i32 @test30(i1* nocapture readonly %cond, i32* nocapture readonly %a, i32 %x, i32 %v) { +entry: + %0 = load volatile i1, i1* %cond, align 1 + br i1 %0, label %if.else, label %if.end + +if.else: + %1 = load volatile i32, i32* %a, align 4 + br label %if.end + +if.end: + %v.addr.0 = phi i32 [ %1, %if.else ], [ 1, %entry ] + %div = sdiv i32 %x, %v.addr.0 + ret i32 %div +} + +; CHECK-LABEL: @test31( +; CHECK: mul i32 +; CHECK: if.end: +; CHECK-NEXT: phi i32 [ %{{.*}}, %if.else ], [ %x, %entry ] +; CHECK-NEXT: ret +define i32 @test31(i1* nocapture readonly %cond, i32* nocapture readonly %a, i32 %x, i32 %v) { +entry: + %0 = load volatile i1, i1* %cond, align 1 + br i1 %0, label %if.else, label %if.end + +if.else: + %1 = load volatile i32, i32* %a, align 4 + br label %if.end + +if.end: + %v.addr.0 = phi i32 [ %1, %if.else ], [ 1, %entry ] + %div = mul i32 %x, %v.addr.0 + ret i32 %div +} + +; CHECK-LABEL: @test32( +; CHECK: sdiv i32 %x, %1 +; CHECK: if.end: +; CHECK-NEXT: phi i32 [ %x, %entry ], [ %{{.*}}, %if.else ] +; CHECK-NEXT: ret +define i32 @test32(i1* nocapture readonly %cond, i32* nocapture readonly %a, i32 %x, i32 %v) { +entry: + %0 = load volatile i1, i1* %cond, align 1 + br i1 %0, label %if.else, label %if.end + +if.else: + %1 = load volatile i32, i32* %a, align 4 + br label %if.end + +if.end: + %v.addr.0 = phi i32 [ 1, %entry ], [ %1, %if.else ] + %div = sdiv i32 %x, %v.addr.0 + ret i32 %div +} + +; Constant (0) is on the LHS of shift - should not aplpy the transformation +; CHECK-LABEL: @test33( +; CHECK: if.end: +; CHECK-NEXT: %v.addr.0 = phi i32 [ 0, %entry ], [ %1, %if.else ] +; CHECK-NEXT: shl +; CHECK-NEXT: ret +define i32 @test33(i1* nocapture readonly %cond, i32* nocapture readonly %a, i32 %x, i32 %v) { +entry: + %0 = load volatile i1, i1* %cond, align 1 + br i1 %0, label %if.else, label %if.end + +if.else: + %1 = load volatile i32, i32* %a, align 4 + br label %if.end + +if.end: + %v.addr.0 = phi i32 [ 0, %entry ], [ %1, %if.else ] + %div = shl i32 %v.addr.0, %x + ret i32 %div +}