diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp index 34724709b0f..fd37d7bc1e3 100644 --- a/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/lib/Analysis/ScalarEvolutionExpander.cpp @@ -508,20 +508,37 @@ Value *SCEVExpander::expandAddToGEP(const SCEV *const *op_begin, } Value *SCEVExpander::visitAddExpr(const SCEVAddExpr *S) { + int NumOperands = S->getNumOperands(); const Type *Ty = SE.getEffectiveSCEVType(S->getType()); - Value *V = expand(S->getOperand(S->getNumOperands()-1)); + + // Find the index of an operand to start with. Choose the operand with + // pointer type, if there is one, or the last operand otherwise. + int PIdx = 0; + for (; PIdx != NumOperands - 1; ++PIdx) + if (isa(S->getOperand(PIdx)->getType())) break; + + // Expand code for the operand that we chose. + Value *V = expand(S->getOperand(PIdx)); // Turn things like ptrtoint+arithmetic+inttoptr into GEP. See the // comments on expandAddToGEP for details. if (const PointerType *PTy = dyn_cast(V->getType())) { + // Take the operand at PIdx out of the list. const SmallVectorImpl &Ops = S->getOperands(); - return expandAddToGEP(&Ops[0], &Ops[Ops.size() - 1], PTy, Ty, V); + SmallVector NewOps; + NewOps.insert(NewOps.end(), Ops.begin(), Ops.begin() + PIdx); + NewOps.insert(NewOps.end(), Ops.begin() + PIdx + 1, Ops.end()); + // Make a GEP. + return expandAddToGEP(NewOps.begin(), NewOps.end(), PTy, Ty, V); } + // Otherwise, we'll expand the rest of the SCEVAddExpr as plain integer + // arithmetic. V = InsertNoopCastOfTo(V, Ty); // Emit a bunch of add instructions - for (int i = S->getNumOperands()-2; i >= 0; --i) { + for (int i = NumOperands-1; i >= 0; --i) { + if (i == PIdx) continue; Value *W = expandCodeFor(S->getOperand(i), Ty); V = InsertBinop(Instruction::Add, V, W); } diff --git a/test/Transforms/IndVarSimplify/preserve-gep-loop-variant.ll b/test/Transforms/IndVarSimplify/preserve-gep-loop-variant.ll new file mode 100644 index 00000000000..86e90c7623d --- /dev/null +++ b/test/Transforms/IndVarSimplify/preserve-gep-loop-variant.ll @@ -0,0 +1,41 @@ +; RUN: opt < %s -indvars -S > %t +; RUN: not grep inttoptr %t +; RUN: not grep ptrtoint %t +; RUN: grep scevgep %t + +; Indvars shouldn't need inttoptr/ptrtoint to expand an address here. + +define void @foo(i8* %p) nounwind { +entry: + br i1 true, label %bb.nph, label %for.end + +for.cond: + %phitmp = icmp slt i64 %inc, 20 + br i1 %phitmp, label %for.body, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: + br label %for.end + +bb.nph: + br label %for.body + +for.body: + %storemerge1 = phi i64 [ %inc, %for.cond ], [ 0, %bb.nph ] + %call = tail call i64 @bar() nounwind + %call2 = tail call i64 @car() nounwind + %conv = trunc i64 %call2 to i8 + %conv3 = sext i8 %conv to i64 + %add = add nsw i64 %call, %storemerge1 + %add4 = add nsw i64 %add, %conv3 + %arrayidx = getelementptr inbounds i8* %p, i64 %add4 + store i8 0, i8* %arrayidx + %inc = add nsw i64 %storemerge1, 1 + br label %for.cond + +for.end: + ret void +} + +declare i64 @bar() + +declare i64 @car()