From: Sanjoy Das Date: Fri, 16 Oct 2015 01:00:47 +0000 (+0000) Subject: [IndVars] Have `cloneArithmeticIVUser` guess better X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=457377c0d4f4f0e0ff6b836407ef3baafea20e94;p=oota-llvm.git [IndVars] Have `cloneArithmeticIVUser` guess better Summary: `cloneArithmeticIVUser` currently trips over expression like `add %iv, -1` when `%iv` is being zero extended -- it tries to construct the widened use as `add %iv.zext, zext(-1)` and (correctly) fails to prove equivalence to `zext(add %iv, -1)` (here the SCEV for `%iv` is `{1,+,1}`). This change teaches `IndVars` to try sign extending the non-IV operand if that makes the newly constructed IV use equivalent to the widened narrow IV use. Reviewers: atrick, hfinkel, reames Subscribers: sanjoy, llvm-commits Differential Revision: http://reviews.llvm.org/D13717 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@250483 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp index 90d73d0978f..f2bc2852ccf 100644 --- a/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -998,22 +998,84 @@ Instruction *WidenIV::cloneArithmeticIVUser(NarrowIVDefUse DU, DEBUG(dbgs() << "Cloning arithmetic IVUser: " << *NarrowUse << "\n"); - // 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 = - (NarrowUse->getOperand(0) == NarrowDef) - ? WideDef - : getExtend(NarrowUse->getOperand(0), WideType, IsSigned, NarrowUse); - Value *RHS = - (NarrowUse->getOperand(1) == NarrowDef) - ? WideDef - : getExtend(NarrowUse->getOperand(1), WideType, IsSigned, NarrowUse); + unsigned IVOpIdx = (NarrowUse->getOperand(0) == NarrowDef) ? 0 : 1; + + // We're trying to find X such that + // + // Widen(NarrowDef `op` NonIVNarrowDef) == WideAR == WideDef `op.wide` X + // + // We guess two solutions to X, sext(NonIVNarrowDef) and zext(NonIVNarrowDef), + // and check using SCEV if any of them are correct. + + // Returns true if extending NonIVNarrowDef according to `SignExt` is a + // correct solution to X. + auto GuessNonIVOperand = [&](bool SignExt) { + const SCEV *WideLHS; + const SCEV *WideRHS; + + auto GetExtend = [this, SignExt](const SCEV *S, Type *Ty) { + if (SignExt) + return SE->getSignExtendExpr(S, Ty); + return SE->getZeroExtendExpr(S, Ty); + }; + + if (IVOpIdx == 0) { + WideLHS = SE->getSCEV(WideDef); + const SCEV *NarrowRHS = SE->getSCEV(NarrowUse->getOperand(1)); + WideRHS = GetExtend(NarrowRHS, WideType); + } else { + const SCEV *NarrowLHS = SE->getSCEV(NarrowUse->getOperand(0)); + WideLHS = GetExtend(NarrowLHS, WideType); + WideRHS = SE->getSCEV(WideDef); + } + + // WideUse is "WideDef `op.wide` X" as described in the comment. + const SCEV *WideUse = nullptr; + + switch (NarrowUse->getOpcode()) { + default: + llvm_unreachable("No other possibility!"); + + case Instruction::Add: + WideUse = SE->getAddExpr(WideLHS, WideRHS); + break; + + case Instruction::Mul: + WideUse = SE->getMulExpr(WideLHS, WideRHS); + break; + + case Instruction::UDiv: + WideUse = SE->getUDivExpr(WideLHS, WideRHS); + break; + + case Instruction::Sub: + WideUse = SE->getMinusSCEV(WideLHS, WideRHS); + break; + } + + return WideUse == WideAR; + }; + + bool SignExtend = IsSigned; + if (!GuessNonIVOperand(SignExtend)) { + SignExtend = !SignExtend; + if (!GuessNonIVOperand(SignExtend)) + return nullptr; + } + + Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) + ? WideDef + : getExtend(NarrowUse->getOperand(0), WideType, SignExtend, + NarrowUse); + Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) + ? WideDef + : getExtend(NarrowUse->getOperand(1), WideType, SignExtend, + NarrowUse); auto *NarrowBO = cast(NarrowUse); auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, NarrowBO->getName()); + IRBuilder<> Builder(NarrowUse); Builder.Insert(WideBO); if (const auto *OBO = dyn_cast(NarrowBO)) { diff --git a/test/Transforms/IndVarSimplify/iv-widen.ll b/test/Transforms/IndVarSimplify/iv-widen.ll index 464b03ce559..ccf9fa0aa0a 100644 --- a/test/Transforms/IndVarSimplify/iv-widen.ll +++ b/test/Transforms/IndVarSimplify/iv-widen.ll @@ -6,7 +6,7 @@ target datalayout = "n8:16:32:64" 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 @@ target triple = "x86_64-apple-darwin" ; 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 @@ exit24: ; preds = %B18 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)