Index: lib/Transforms/Scalar/IndVarSimplify.cpp =================================================================== --- lib/Transforms/Scalar/IndVarSimplify.cpp +++ lib/Transforms/Scalar/IndVarSimplify.cpp @@ -988,25 +988,76 @@ Instruction *WidenIV::cloneArithmeticIVUser(NarrowIVDefUse DU, const SCEVAddRecExpr *WideAR) { - DEBUG(dbgs() << "Cloning arithmetic IVUser: " << *DU.NarrowUse << "\n"); + DEBUG(dbgs() << "Cloning Arithmetic IVUser: " << *DU.NarrowUse << "\n"); + Instruction *NarrowUse = DU.NarrowUse; + Instruction *NarrowDef = DU.NarrowDef; - // Replace NarrowDef operands with WideDef. Otherwise, we don't know anything - // about the narrow operand yet so must insert a [sz]ext. It is probably loop - // invariant and will be folded or hoisted. If it actually comes from a - // widened IV, it should be removed during a future call to widenIVUse. - Value *LHS = (DU.NarrowUse->getOperand(0) == DU.NarrowDef) + unsigned IVOpIdx = (NarrowUse->getOperand(0) == NarrowDef) ? 0 : 1; + + auto GuessNonIVOperand = [&](bool SignExt) { + const SCEV *WideLHS; + const SCEV *WideRHS; + + auto GetExtend = SignExt ? &ScalarEvolution::getSignExtendExpr + : &ScalarEvolution::getZeroExtendExpr; + + if (IVOpIdx == 0) { + WideLHS = SE->getSCEV(DU.WideDef); + const SCEV *NarrowRHS = SE->getSCEV(NarrowUse->getOperand(1)); + WideRHS = (SE->*GetExtend)(NarrowRHS, WideType); + } else { + const SCEV *NarrowLHS = SE->getSCEV(NarrowUse->getOperand(0)); + WideLHS = (SE->*GetExtend)(NarrowLHS, WideType); + WideRHS = SE->getSCEV(DU.WideDef); + } + + const SCEV *WideOp = nullptr; + + switch (NarrowUse->getOpcode()) { + default: + llvm_unreachable("No other possibility!"); + + case Instruction::Add: + WideOp = SE->getAddExpr(WideLHS, WideRHS); + break; + + case Instruction::Mul: + WideOp = SE->getMulExpr(WideLHS, WideRHS); + break; + + case Instruction::UDiv: + WideOp = SE->getUDivExpr(WideLHS, WideRHS); + break; + + case Instruction::Sub: + WideOp = SE->getMinusSCEV(WideLHS, WideRHS); + break; + } + + return WideOp == WideAR; + }; + + bool SignExtend = IsSigned; + if (!GuessNonIVOperand(SignExtend)) { + if (!GuessNonIVOperand(!SignExtend)) + return nullptr; + SignExtend = !SignExtend; + } + + Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) ? DU.WideDef - : getExtend(DU.NarrowUse->getOperand(0), WideType, IsSigned, - DU.NarrowUse); - Value *RHS = (DU.NarrowUse->getOperand(1) == DU.NarrowDef) + : getExtend(NarrowUse->getOperand(0), WideType, SignExtend, + NarrowUse); + Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) ? DU.WideDef - : getExtend(DU.NarrowUse->getOperand(1), WideType, IsSigned, - DU.NarrowUse); + : getExtend(NarrowUse->getOperand(1), WideType, SignExtend, + NarrowUse); - auto *NarrowBO = cast(DU.NarrowUse); - auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, - NarrowBO->getName()); - IRBuilder<> Builder(DU.NarrowUse); + BinaryOperator *NarrowBO = cast(DU.NarrowUse); + BinaryOperator *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, + RHS, NarrowBO->getName()); + + IRBuilder<> Builder(NarrowUse); Builder.Insert(WideBO); if (const auto *OBO = dyn_cast(NarrowBO)) { if (OBO->hasNoUnsignedWrap()) Index: test/Transforms/IndVarSimplify/iv-widen.ll =================================================================== --- test/Transforms/IndVarSimplify/iv-widen.ll +++ test/Transforms/IndVarSimplify/iv-widen.ll @@ -6,7 +6,7 @@ target triple = "x86_64-apple-darwin" -; CHECK-LABEL: @sloop +; CHECK-LABEL: @loop_0 ; CHECK-LABEL: B18: ; Only one phi now. ; CHECK: phi @@ -16,7 +16,7 @@ ; One trunc for the dummy() call. ; CHECK-LABEL: exit24: ; CHECK: trunc i64 {{.*}}lcssa.wide to i32 -define void @sloop(i32* %a) { +define void @loop_0(i32* %a) { Prologue: br i1 undef, label %B18, label %B6 @@ -41,4 +41,30 @@ unreachable } +define void @loop_1(i32 %lim) { +; CHECK-LABEL: @loop_1( + entry: + %entry.cond = icmp ne i32 %lim, 0 + br i1 %entry.cond, label %loop, label %leave + + loop: +; CHECK: loop: +; CHECK: %indvars.iv = phi i64 [ 1, %loop.preheader ], [ %indvars.iv.next, %loop ] +; CHECK: %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 +; CHECK: [[IV_INC:%[^ ]+]] = add nsw i64 %indvars.iv, -1 +; CHECK: call void @dummy.i64(i64 [[IV_INC]]) + + %iv = phi i32 [ 1, %entry ], [ %iv.inc, %loop ] + %iv.inc = add i32 %iv, 1 + %iv.inc.sub = add i32 %iv, -1 + %iv.inc.sub.zext = zext i32 %iv.inc.sub to i64 + call void @dummy.i64(i64 %iv.inc.sub.zext) + %be.cond = icmp ult i32 %iv.inc, %lim + br i1 %be.cond, label %loop, label %leave + + leave: + ret void +} + declare void @dummy(i32) +declare void @dummy.i64(i64)