Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1428,6 +1428,11 @@ return &I; } + // Try to fold add PHI(constant). + if (PHINode *PN = dyn_cast(LHS)) + if (Instruction *R = foldOpIntoPhi(I, PN)) + return R; + // TODO(jingyue): Consider willNotOverflowSignedAdd and // willNotOverflowUnsignedAdd to reduce the number of invocations of // computeKnownBits. Index: llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -410,6 +410,8 @@ Type *LHSType = LHSVal->getType(); Type *RHSType = RHSVal->getType(); + unsigned LHSNonConst = !isa(FirstInst->getOperand(0)); + unsigned RHSNonConst = !isa(FirstInst->getOperand(1)); // Scan to see if all operands are the same opcode, and all have one user. for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { @@ -429,8 +431,16 @@ // Keep track of which operand needs a phi node. if (I->getOperand(0) != LHSVal) LHSVal = nullptr; if (I->getOperand(1) != RHSVal) RHSVal = nullptr; + + if (!isa(I->getOperand(0))) LHSNonConst++; + if (!isa(I->getOperand(1))) RHSNonConst++; } + // If most of the PHI candidates are const, don't do this transformation, + // because materialization of const still needs instructions. + if (LHSNonConst <= 1) RHSVal = nullptr; + if (RHSNonConst <= 1) LHSVal = nullptr; + // If both LHS and RHS would need a PHI, don't do this transformation, // because it would increase the number of PHIs entering the block, // which leads to higher register pressure. This is especially Index: llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -393,6 +393,10 @@ if (Instruction *Res = FoldShiftByConstant(Op0, CUI, I)) return Res; + if (isa(Op1) || isa(Op1)) + if (Instruction *FoldedShift = foldBinOpIntoSelectOrPhi(I)) + return FoldedShift; + if (auto *NewShift = cast_or_null( reassociateShiftAmtsOfTwoSameDirectionShifts(&I, SQ))) return NewShift; @@ -686,9 +690,6 @@ "Shift over the type width should have been removed already"); (void)TypeBits; - if (Instruction *FoldedShift = foldBinOpIntoSelectOrPhi(I)) - return FoldedShift; - if (!Op0->hasOneUse()) return nullptr; Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -1111,20 +1111,19 @@ } static Value *foldOperationIntoPhiValue(BinaryOperator *I, Value *InV, + Value *OtherOp, bool PhiIsLHS, + BasicBlock *PredBB, InstCombiner::BuilderTy &Builder) { - bool ConstIsRHS = isa(I->getOperand(1)); - Constant *C = cast(I->getOperand(ConstIsRHS)); - - if (auto *InC = dyn_cast(InV)) { - if (ConstIsRHS) - return ConstantExpr::get(I->getOpcode(), InC, C); - return ConstantExpr::get(I->getOpcode(), C, InC); - } - - Value *Op0 = InV, *Op1 = C; - if (!ConstIsRHS) + Value *Op0 = InV, *Op1 = OtherOp; + if (!PhiIsLHS) std::swap(Op0, Op1); + auto *C0 = dyn_cast(Op0); + auto *C1 = dyn_cast(Op1); + if (C0 && C1) + return ConstantExpr::get(I->getOpcode(), C0, C1); + + Builder.SetInsertPoint(PredBB->getTerminator()); Value *RI = Builder.CreateBinOp(I->getOpcode(), Op0, Op1, "phi.bo"); auto *FPInst = dyn_cast(RI); if (FPInst && isa(FPInst)) @@ -1136,6 +1135,8 @@ unsigned NumPHIValues = PN->getNumIncomingValues(); if (NumPHIValues == 0) return nullptr; + if (I.getParent() != PN->getParent()) + return nullptr; // We normally only transform phis with a single use. However, if a PHI has // multiple uses and they are all the same operation, we can fold *all* of the @@ -1156,8 +1157,13 @@ // bail out. We don't do arbitrary constant expressions here because moving // their computation can be expensive without a cost model. BasicBlock *NonConstBB = nullptr; + BasicBlock *DominatorBB = nullptr; for (unsigned i = 0; i != NumPHIValues; ++i) { Value *InVal = PN->getIncomingValue(i); + BasicBlock *PredBB = PN->getIncomingBlock(i); + if (DT.dominates(PredBB, PN->getParent())) + DominatorBB = PredBB; + // For non-freeze, require constant operand // For freeze, require non-undef, non-poison operand if (!isa(I) && match(InVal, m_ImmConstant())) @@ -1194,6 +1200,55 @@ return nullptr; } + // If we have + // %p = phi [c1, pred1], [c2, pred2] + // %v = add %p, %op + // + // We'll generate immediate materialization instructions in predecessors. We + // can directly fold them into ALU instructions. + // + //pred1: + // %op1 = add c1, %op + // br %bb + //pred2: + // %op2 = add c2, %op + // br %bb + //bb: + // %v = phi [%op1, pred1], [%op2, pred2] + bool PhiIsLHS = false; + Value *OtherOp = I.getOperand(0); + Instruction *OtherI = nullptr;; + if (auto *BO = dyn_cast(&I)) { + if (dyn_cast(OtherOp) == PN) { + OtherOp = BO->getOperand(1); + PhiIsLHS = true; + } + if (!isa(OtherOp)) { + if (!I.getType()->isIntegerTy()) + return nullptr; + OtherI = dyn_cast(OtherOp); + if (OtherI) { + if (I.getParent() == OtherI->getParent()) { + // If I depends on other instructions in the same BB, check if we can + // move them into a dominator. For simplicity we handle only 1 + // instruction. + if (!DominatorBB) + return nullptr; + if (!isa(OtherI) && mayBeMemoryDependent(*OtherI)) + return nullptr; + for (int i = 0, e = OtherI->getNumOperands(); i != e; ++i) { + auto *OpI = dyn_cast(OtherI->getOperand(i)); + if (OpI && I.getParent() == OpI->getParent()) + return nullptr; + } + } + else + OtherI = nullptr; + } else if (!isa(OtherOp)) + return nullptr; + } + } + // Okay, we can do the transformation: create the new PHI node. PHINode *NewPN = PHINode::Create(I.getType(), PN->getNumIncomingValues()); InsertNewInstBefore(NewPN, *PN); @@ -1252,9 +1307,18 @@ NewPN->addIncoming(InV, PN->getIncomingBlock(i)); } } else if (auto *BO = dyn_cast(&I)) { + PHINode *OtherPN = nullptr; + if (OtherI) { + OtherPN = dyn_cast(OtherI); + if (!OtherPN) + OtherI->moveBefore(DominatorBB->getTerminator()); + } for (unsigned i = 0; i != NumPHIValues; ++i) { + if (OtherPN) + OtherOp = OtherPN->getIncomingValue(i); Value *InV = foldOperationIntoPhiValue(BO, PN->getIncomingValue(i), - Builder); + OtherOp, PhiIsLHS, + PN->getIncomingBlock(i), Builder); NewPN->addIncoming(InV, PN->getIncomingBlock(i)); } } else if (isa(&I)) { @@ -1290,15 +1354,18 @@ } Instruction *InstCombinerImpl::foldBinOpIntoSelectOrPhi(BinaryOperator &I) { - if (!isa(I.getOperand(1))) - return nullptr; - if (auto *Sel = dyn_cast(I.getOperand(0))) { + if (!isa(I.getOperand(1))) + return nullptr; if (Instruction *NewSel = FoldOpIntoSelect(I, Sel)) return NewSel; - } else if (auto *PN = dyn_cast(I.getOperand(0))) { - if (Instruction *NewPhi = foldOpIntoPhi(I, PN)) - return NewPhi; + } else { + if (auto *PN = dyn_cast(I.getOperand(0))) + if (Instruction *NewPhi = foldOpIntoPhi(I, PN)) + return NewPhi; + if (auto *PN = dyn_cast(I.getOperand(1))) + if (Instruction *NewPhi = foldOpIntoPhi(I, PN)) + return NewPhi; } return nullptr; } Index: llvm/test/Transforms/InstCombine/narrow.ll =================================================================== --- llvm/test/Transforms/InstCombine/narrow.ll +++ llvm/test/Transforms/InstCombine/narrow.ll @@ -190,14 +190,15 @@ define i32 @shrinkLogicAndPhi1(i8 %x, i1 %cond) { ; CHECK-LABEL: @shrinkLogicAndPhi1( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32 +; CHECK-NEXT: [[PHI_BO:%.*]] = xor i32 [[ZEXT]], 21 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ENDIF:%.*]] ; CHECK: if: +; CHECK-NEXT: [[PHI_BO1:%.*]] = xor i32 [[ZEXT]], 33 ; CHECK-NEXT: br label [[ENDIF]] ; CHECK: endif: -; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 21, [[ENTRY:%.*]] ], [ 33, [[IF]] ] -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32 -; CHECK-NEXT: [[LOGIC:%.*]] = xor i32 [[PHI]], [[ZEXT]] -; CHECK-NEXT: ret i32 [[LOGIC]] +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[PHI_BO]], [[ENTRY:%.*]] ], [ [[PHI_BO1]], [[IF]] ] +; CHECK-NEXT: ret i32 [[PHI]] ; entry: br i1 %cond, label %if, label %endif @@ -217,14 +218,15 @@ define i32 @shrinkLogicAndPhi2(i8 %x, i1 %cond) { ; CHECK-LABEL: @shrinkLogicAndPhi2( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32 +; CHECK-NEXT: [[PHI_BO:%.*]] = xor i32 [[ZEXT]], 21 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ENDIF:%.*]] ; CHECK: if: +; CHECK-NEXT: [[PHI_BO1:%.*]] = xor i32 [[ZEXT]], 33 ; CHECK-NEXT: br label [[ENDIF]] ; CHECK: endif: -; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 21, [[ENTRY:%.*]] ], [ 33, [[IF]] ] -; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i32 -; CHECK-NEXT: [[LOGIC:%.*]] = xor i32 [[PHI]], [[ZEXT]] -; CHECK-NEXT: ret i32 [[LOGIC]] +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[PHI_BO]], [[ENTRY:%.*]] ], [ [[PHI_BO1]], [[IF]] ] +; CHECK-NEXT: ret i32 [[PHI]] ; entry: br i1 %cond, label %if, label %endif Index: llvm/test/Transforms/InstCombine/not-add.ll =================================================================== --- llvm/test/Transforms/InstCombine/not-add.ll +++ llvm/test/Transforms/InstCombine/not-add.ll @@ -145,11 +145,11 @@ ; CHECK: cond.true: ; CHECK-NEXT: [[ADD_NOT:%.*]] = sub i32 -2, [[V1:%.*]] ; CHECK-NEXT: [[ADD1_NEG:%.*]] = xor i32 [[ADD_NOT]], [[V2:%.*]] +; CHECK-NEXT: [[PHI_BO:%.*]] = add i32 [[ADD1_NEG]], [[V3:%.*]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: -; CHECK-NEXT: [[COND_NEG:%.*]] = phi i32 [ [[ADD1_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[COND_NEG]], [[V3:%.*]] -; CHECK-NEXT: ret i32 [[SUB]] +; CHECK-NEXT: [[COND_NEG:%.*]] = phi i32 [ [[PHI_BO]], [[COND_TRUE]] ], [ [[V3]], [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i32 [[COND_NEG]] ; entry: br i1 %c1, label %cond.true, label %cond.end Index: llvm/test/Transforms/InstCombine/phi-binary-op.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/phi-binary-op.ll @@ -0,0 +1,240 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +; If we have +; %p = phi [c1, pred1], [c2, pred2] +; %v = add %p, %op +; +; We'll generate immediate materialization instructions in predecessors. We +; can directly fold them into ALU instructions. +; +; pred1: +; %op1 = add c1, %op +; br %bb +; pred2: +; %op2 = add c2, %op +; br %bb +; bb: +; %v = phi [%op1, pred1], [%op2, pred2] + +; Basic case. +define zeroext i1 @test1(i32 %s, i32* %ptr) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[S:%.*]], 1025 +; CHECK-NEXT: [[PHI_BO:%.*]] = and i32 [[S]], 3 +; CHECK-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[S]], 4097 +; CHECK-NEXT: [[PHI_BO1:%.*]] = and i32 [[S]], 7 +; CHECK-NEXT: br i1 [[CMP2]], label [[RETURN_SINK_SPLIT]], label [[RETURN:%.*]] +; CHECK: return.sink.split: +; CHECK-NEXT: [[DOTSINK:%.*]] = phi i32 [ [[PHI_BO]], [[ENTRY:%.*]] ], [ [[PHI_BO1]], [[IF_ELSE]] ] +; CHECK-NEXT: store i32 [[DOTSINK]], i32* [[PTR:%.*]], align 4 +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: [[RETVAL:%.*]] = phi i1 [ false, [[IF_ELSE]] ], [ true, [[RETURN_SINK_SPLIT]] ] +; CHECK-NEXT: ret i1 [[RETVAL]] +; +entry: + %cmp = icmp ult i32 %s, 1025 + br i1 %cmp, label %return.sink.split, label %if.else + +if.else: + %cmp2 = icmp ult i32 %s, 4097 + br i1 %cmp2, label %return.sink.split, label %return + +return.sink.split: + %.sink = phi i32 [ 3, %entry ], [ 7, %if.else ] + %and0 = and i32 %s, %.sink + store i32 %and0, i32* %ptr, align 4 + br label %return + +return: + %retval = phi i1 [ false, %if.else ], [ true, %return.sink.split ] + ret i1 %retval +} + +; The dependent instruction can be moved to a predecessor that is also a +; dominator. +define zeroext i1 @test2(i64 %s, i32* %ptr) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[S:%.*]], 1025 +; CHECK-NEXT: [[T:%.*]] = trunc i64 [[S]] to i32 +; CHECK-NEXT: [[PHI_BO:%.*]] = xor i32 [[T]], 3 +; CHECK-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[S]], 4097 +; CHECK-NEXT: [[PHI_BO1:%.*]] = xor i32 [[T]], 7 +; CHECK-NEXT: br i1 [[CMP2]], label [[RETURN_SINK_SPLIT]], label [[RETURN:%.*]] +; CHECK: return.sink.split: +; CHECK-NEXT: [[DOTSINK:%.*]] = phi i32 [ [[PHI_BO]], [[ENTRY:%.*]] ], [ [[PHI_BO1]], [[IF_ELSE]] ] +; CHECK-NEXT: store i32 [[DOTSINK]], i32* [[PTR:%.*]], align 4 +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: [[RETVAL:%.*]] = phi i1 [ false, [[IF_ELSE]] ], [ true, [[RETURN_SINK_SPLIT]] ] +; CHECK-NEXT: ret i1 [[RETVAL]] +; +entry: + %cmp = icmp ult i64 %s, 1025 + br i1 %cmp, label %return.sink.split, label %if.else + +if.else: + %cmp2 = icmp ult i64 %s, 4097 + br i1 %cmp2, label %return.sink.split, label %return + +return.sink.split: + %.sink = phi i32 [ 3, %entry ], [ 7, %if.else ] + %t = trunc i64 %s to i32 + %xor0 = xor i32 %t, %.sink + store i32 %xor0, i32* %ptr, align 4 + br label %return + +return: + %retval = phi i1 [ false, %if.else ], [ true, %return.sink.split ] + ret i1 %retval +} + +; There can be 1 non-const predecessor. +define zeroext i1 @test3(i32 %s, i32 %shm, i32* %ptr) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[S:%.*]], 1025 +; CHECK-NEXT: [[PHI_BO:%.*]] = shl i32 [[S]], 3 +; CHECK-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[PHI_BO1:%.*]] = shl i32 [[S]], [[SHM:%.*]] +; CHECK-NEXT: br label [[RETURN_SINK_SPLIT]] +; CHECK: return.sink.split: +; CHECK-NEXT: [[DOTSINK:%.*]] = phi i32 [ [[PHI_BO]], [[ENTRY:%.*]] ], [ [[PHI_BO1]], [[IF_ELSE]] ] +; CHECK-NEXT: store i32 [[DOTSINK]], i32* [[PTR:%.*]], align 4 +; CHECK-NEXT: ret i1 true +; +entry: + %cmp = icmp ult i32 %s, 1025 + br i1 %cmp, label %return.sink.split, label %if.else + +if.else: + br label %return.sink.split + +return.sink.split: + %.sink = phi i32 [ 3, %entry ], [ %shm, %if.else ] + %shl0 = shl i32 %s, %.sink + store i32 %shl0, i32* %ptr, align 4 + ret i1 true +} + +; One phi user depends on another phi user. +define zeroext i1 @test4(i32 %s, i32* %ptr) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[S:%.*]], 1025 +; CHECK-NEXT: [[PHI_BO:%.*]] = add i32 [[S]], 7 +; CHECK-NEXT: [[PHI_BO2:%.*]] = lshr i32 [[PHI_BO]], 3 +; CHECK-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[S]], 4097 +; CHECK-NEXT: [[PHI_BO1:%.*]] = add i32 [[S]], 100 +; CHECK-NEXT: [[PHI_BO3:%.*]] = lshr i32 [[PHI_BO1]], 7 +; CHECK-NEXT: br i1 [[CMP2]], label [[RETURN_SINK_SPLIT]], label [[RETURN:%.*]] +; CHECK: return.sink.split: +; CHECK-NEXT: [[DOTSINK:%.*]] = phi i32 [ [[PHI_BO2]], [[ENTRY:%.*]] ], [ [[PHI_BO3]], [[IF_ELSE]] ] +; CHECK-NEXT: store i32 [[DOTSINK]], i32* [[PTR:%.*]], align 4 +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: [[RETVAL:%.*]] = phi i1 [ false, [[IF_ELSE]] ], [ true, [[RETURN_SINK_SPLIT]] ] +; CHECK-NEXT: ret i1 [[RETVAL]] +; +entry: + %cmp = icmp ult i32 %s, 1025 + br i1 %cmp, label %return.sink.split, label %if.else + +if.else: + %cmp2 = icmp ult i32 %s, 4097 + br i1 %cmp2, label %return.sink.split, label %return + +return.sink.split: + %.sink5 = phi i32 [ 7, %entry ], [ 100, %if.else ] + %.sink = phi i32 [ 3, %entry ], [ 7, %if.else ] + %add6 = add nuw nsw i32 %.sink5, %s + %shr7 = lshr i32 %add6, %.sink + store i32 %shr7, i32* %ptr, align 4 + br label %return + +return: + %retval = phi i1 [ false, %if.else ], [ true, %return.sink.split ] + ret i1 %retval +} + +; One phi user depends on another phi user which depends on a third instruction. +define zeroext i1 @test5(i64 %s, i32* %ptr) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[S:%.*]], 1025 +; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[S]] to i32 +; CHECK-NEXT: [[PHI_BO:%.*]] = add i32 [[CONV]], 7 +; CHECK-NEXT: [[PHI_BO2:%.*]] = ashr i32 [[PHI_BO]], 3 +; CHECK-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[S]], 4097 +; CHECK-NEXT: [[PHI_BO1:%.*]] = add i32 [[CONV]], 100 +; CHECK-NEXT: [[PHI_BO3:%.*]] = ashr i32 [[PHI_BO1]], 7 +; CHECK-NEXT: br i1 [[CMP2]], label [[RETURN_SINK_SPLIT]], label [[RETURN:%.*]] +; CHECK: return.sink.split: +; CHECK-NEXT: [[DOTSINK:%.*]] = phi i32 [ [[PHI_BO2]], [[ENTRY:%.*]] ], [ [[PHI_BO3]], [[IF_ELSE]] ] +; CHECK-NEXT: store i32 [[DOTSINK]], i32* [[PTR:%.*]], align 4 +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: [[RETVAL:%.*]] = phi i1 [ false, [[IF_ELSE]] ], [ true, [[RETURN_SINK_SPLIT]] ] +; CHECK-NEXT: ret i1 [[RETVAL]] +; +entry: + %cmp = icmp ult i64 %s, 1025 + br i1 %cmp, label %return.sink.split, label %if.else + +if.else: + %cmp2 = icmp ult i64 %s, 4097 + br i1 %cmp2, label %return.sink.split, label %return + +return.sink.split: + %.sink5 = phi i32 [ 7, %entry ], [ 100, %if.else ] + %.sink = phi i32 [ 3, %entry ], [ 7, %if.else ] + %conv = trunc i64 %s to i32 + %add6 = add nuw nsw i32 %.sink5, %conv + %shr7 = ashr i32 %add6, %.sink + store i32 %shr7, i32* %ptr, align 4 + br label %return + +return: + %retval = phi i1 [ false, %if.else ], [ true, %return.sink.split ] + ret i1 %retval +} + +; Both operands are phi. +define i64 @test6(i1 %cond, i64 ()* %p) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[RETURN:%.*]], label [[IF_END:%.*]] +; CHECK: if.end: +; CHECK-NEXT: [[CALL:%.*]] = tail call i64 [[P:%.*]]() +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: [[P2:%.*]] = phi i64 [ [[CALL]], [[IF_END]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i64 [[P2]] +; +entry: + br i1 %cond, label %return, label %if.end + +if.end: + %call = tail call i64 %p() + %high = and i64 %call, -4294967296 + %low = and i64 %call, 4294967295 + br label %return + +return: + %p1 = phi i64 [ %low, %if.end ], [ 0, %entry ] + %p2 = phi i64 [ %high, %if.end ], [ 0, %entry ] + %v = or i64 %p2, %p1 + ret i64 %v +} Index: llvm/test/Transforms/InstCombine/phi.ll =================================================================== --- llvm/test/Transforms/InstCombine/phi.ll +++ llvm/test/Transforms/InstCombine/phi.ll @@ -291,14 +291,14 @@ define i64 @test12(i1 %cond, i8* %Ptr, i64 %Val) { ; CHECK-LABEL: @test12( ; CHECK-NEXT: entry: +; CHECK-NEXT: [[T41:%.*]] = ptrtoint i8* [[PTR:%.*]] to i64 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[END:%.*]], label [[TWO:%.*]] ; CHECK: two: +; CHECK-NEXT: [[PHI_BO5:%.*]] = add i64 [[T41]], [[VAL:%.*]] ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[T869_0_OFF64:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[VAL:%.*]], [[TWO]] ] -; CHECK-NEXT: [[T41:%.*]] = ptrtoint i8* [[PTR:%.*]] to i64 -; CHECK-NEXT: [[T2:%.*]] = add i64 [[T869_0_OFF64]], [[T41]] -; CHECK-NEXT: ret i64 [[T2]] +; CHECK-NEXT: [[T869_0_OFF64:%.*]] = phi i64 [ [[T41]], [[ENTRY:%.*]] ], [ [[PHI_BO5]], [[TWO]] ] +; CHECK-NEXT: ret i64 [[T869_0_OFF64]] ; entry: %t41 = ptrtoint i8* %Ptr to i64 Index: llvm/test/Transforms/InstCombine/rem.ll =================================================================== --- llvm/test/Transforms/InstCombine/rem.ll +++ llvm/test/Transforms/InstCombine/rem.ll @@ -607,13 +607,13 @@ ; CHECK-NEXT: br i1 [[C0:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] ; CHECK: if.then: ; CHECK-NEXT: [[V:%.*]] = load volatile i32, i32* [[P:%.*]], align 4 -; CHECK-NEXT: [[PHI_BO:%.*]] = and i32 [[V]], 2147483647 ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[LHS:%.*]] = phi i32 [ [[PHI_BO]], [[IF_THEN]] ], [ 5, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[LHS:%.*]] = phi i32 [ [[V]], [[IF_THEN]] ], [ 5, [[ENTRY:%.*]] ] ; CHECK-NEXT: br i1 [[ALWAYS_FALSE:%.*]], label [[REM_IS_SAFE:%.*]], label [[REM_IS_UNSAFE:%.*]] ; CHECK: rem.is.safe: -; CHECK-NEXT: ret i32 [[LHS]] +; CHECK-NEXT: [[REM:%.*]] = and i32 [[LHS]], 2147483647 +; CHECK-NEXT: ret i32 [[REM]] ; CHECK: rem.is.unsafe: ; CHECK-NEXT: ret i32 0 ; Index: llvm/test/Transforms/InstCombine/zext-or-icmp.ll =================================================================== --- llvm/test/Transforms/InstCombine/zext-or-icmp.ll +++ llvm/test/Transforms/InstCombine/zext-or-icmp.ll @@ -46,11 +46,7 @@ ; 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 @@ ; 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