Index: ../include/llvm/Transforms/Utils/LoopUtils.h =================================================================== --- ../include/llvm/Transforms/Utils/LoopUtils.h +++ ../include/llvm/Transforms/Utils/LoopUtils.h @@ -263,13 +263,15 @@ enum InductionKind { IK_NoInduction, ///< Not an induction variable. IK_IntInduction, ///< Integer induction variable. Step = C. - IK_PtrInduction ///< Pointer induction var. Step = C / sizeof(elem). + IK_PtrInduction, ///< Pointer induction var. Step = C / sizeof(elem). + IK_FpInduction ///< Floating point induction variable. }; public: /// Default constructor - creates an invalid induction. InductionDescriptor() - : StartValue(nullptr), IK(IK_NoInduction), Step(nullptr) {} + : StartValue(nullptr), IK(IK_NoInduction), Step(nullptr), + UnsafeAlgebraInst(nullptr), BinaryOp((Instruction::BinaryOps)0) {} /// Get the consecutive direction. Returns: /// 0 - unknown or non-consecutive. @@ -291,26 +293,46 @@ const SCEV *getStep() const { return Step; } ConstantInt *getConstIntStepValue() const; - /// Returns true if \p Phi is an induction. If \p Phi is an induction, - /// the induction descriptor \p D will contain the data describing this - /// induction. If by some other means the caller has a better SCEV + /// Returns true if \p Phi is an induction in the loop \p L. If \p Phi is an + /// induction, the induction descriptor \p D will contain the data describing + /// this induction. If by some other means the caller has a better SCEV /// expression for \p Phi than the one returned by the ScalarEvolution /// analysis, it can be passed through \p Expr. - static bool isInductionPHI(PHINode *Phi, ScalarEvolution *SE, + static bool isInductionPHI(PHINode *Phi, const Loop* L, ScalarEvolution *SE, InductionDescriptor &D, const SCEV *Expr = nullptr); - /// Returns true if \p Phi is an induction, in the context associated with - /// the run-time predicate of PSE. If \p Assume is true, this can add further - /// SCEV predicates to \p PSE in order to prove that \p Phi is an induction. + /// Returns true if \p Phi is a floating point induction in the loop \p L. + /// If \p Phi is an induction, the induction descriptor \p D will contain + /// the data describing this induction. + static bool isFpInductionPHI(PHINode *Phi, const Loop* L, + ScalarEvolution *SE, InductionDescriptor &D); + + /// Returns true if \p Phi is a loop \p L induction, in the context associated + /// with the run-time predicate of PSE. If \p Assume is true, this can add + /// further SCEV predicates to \p PSE in order to prove that \p Phi is an + /// induction. /// If \p Phi is an induction, \p D will contain the data describing this /// induction. - static bool isInductionPHI(PHINode *Phi, PredicatedScalarEvolution &PSE, + static bool isInductionPHI(PHINode *Phi, const Loop* L, + PredicatedScalarEvolution &PSE, InductionDescriptor &D, bool Assume = false); + /// Returns true if the induction has unsafe algebra which requires a relaxed + /// floating-point model. + bool hasUnsafeAlgebra() { return UnsafeAlgebraInst != nullptr; } + + /// Returns unsafe algebra instruction. + Instruction *getUnsafeAlgebraInst() { return UnsafeAlgebraInst; } + + /// Returns binary opcode. + Instruction::BinaryOps getBinaryOpcode() const { return BinaryOp; } + private: /// Private constructor - used by \c isInductionPHI. - InductionDescriptor(Value *Start, InductionKind K, const SCEV *Step); + InductionDescriptor(Value *Start, InductionKind K, const SCEV *Step, + Instruction *UAI = nullptr, + Instruction::BinaryOps BOp = (Instruction::BinaryOps)0); /// Start value. TrackingVH StartValue; @@ -318,6 +340,10 @@ InductionKind IK; /// Step value. const SCEV *Step; + // Induction has unsafe algebra. + Instruction *UnsafeAlgebraInst; + // Original Induction opcode. + Instruction::BinaryOps BinaryOp; }; BasicBlock *InsertPreheaderForLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, Index: ../lib/Transforms/Scalar/LoopInterchange.cpp =================================================================== --- ../lib/Transforms/Scalar/LoopInterchange.cpp +++ ../lib/Transforms/Scalar/LoopInterchange.cpp @@ -703,7 +703,7 @@ RecurrenceDescriptor RD; InductionDescriptor ID; PHINode *PHI = cast(I); - if (InductionDescriptor::isInductionPHI(PHI, SE, ID)) + if (InductionDescriptor::isInductionPHI(PHI, L, SE, ID)) Inductions.push_back(PHI); else if (RecurrenceDescriptor::isReductionPHI(PHI, L, RD)) Reductions.push_back(PHI); Index: ../lib/Transforms/Utils/LoopUtils.cpp =================================================================== --- ../lib/Transforms/Utils/LoopUtils.cpp +++ ../lib/Transforms/Utils/LoopUtils.cpp @@ -654,8 +654,10 @@ } InductionDescriptor::InductionDescriptor(Value *Start, InductionKind K, - const SCEV *Step) - : StartValue(Start), IK(K), Step(Step) { + const SCEV *Step, Instruction *UAI, + Instruction::BinaryOps BOp) + : StartValue(Start), IK(K), Step(Step), UnsafeAlgebraInst(UAI), + BinaryOp(BOp) { assert(IK != IK_NoInduction && "Not an induction"); // Start value type should match the induction kind and the value @@ -672,7 +674,13 @@ assert((IK != IK_PtrInduction || getConstIntStepValue()) && "Step value should be constant for pointer induction"); - assert(Step->getType()->isIntegerTy() && "StepValue is not an integer"); + assert((IK == IK_FpInduction || Step->getType()->isIntegerTy()) && + "StepValue is not an integer"); + + assert((IK != IK_FpInduction || Step->getType()->isFloatingPointTy()) && + "StepValue is not FP for FpInduction"); + assert((IK != IK_FpInduction || BinaryOp != 0) && + "Binary opcode should be specified for FP induction"); } int InductionDescriptor::getConsecutiveDirection() const { @@ -693,6 +701,8 @@ const DataLayout& DL) const { SCEVExpander Exp(*SE, DL, "induction"); + assert(Index->getType() == Step->getType() && + "Index type does not match StepValue type"); switch (IK) { case IK_IntInduction: { assert(Index->getType() == StartValue->getType() && @@ -717,29 +727,110 @@ return Exp.expandCodeFor(S, StartValue->getType(), &*B.GetInsertPoint()); } case IK_PtrInduction: { - assert(Index->getType() == Step->getType() && - "Index type does not match StepValue type"); assert(isa(Step) && "Expected constant step for pointer induction"); const SCEV *S = SE->getMulExpr(SE->getSCEV(Index), Step); Index = Exp.expandCodeFor(S, Index->getType(), &*B.GetInsertPoint()); return B.CreateGEP(nullptr, StartValue, Index); } + case IK_FpInduction: { + assert(Step->getType()->isFloatingPointTy() && "Expected FP Step value"); + assert(BinaryOp && + "Original bin op should be defined for FP induction"); + + Value *StepValue = cast(Step)->getValue(); + + // Floating point operations had to be 'fast' to enable the induction. + FastMathFlags Flags; + Flags.setUnsafeAlgebra(); + + Value *MulExp = B.CreateFMul(StepValue, Index); + cast(MulExp)->setFastMathFlags(Flags); + + Value *BOp = B.CreateBinOp(BinaryOp, StartValue, + MulExp, "induction"); + cast(BOp)->setFastMathFlags(Flags); + + return BOp; + } case IK_NoInduction: return nullptr; } llvm_unreachable("invalid enum"); } -bool InductionDescriptor::isInductionPHI(PHINode *Phi, +bool InductionDescriptor::isFpInductionPHI(PHINode *Phi, const Loop *TheLoop, + ScalarEvolution *SE, + InductionDescriptor &D) { + + // Here we only handle FP induction variables. + assert(Phi->getType()->isFloatingPointTy() && "Unexpected Phi type"); + + if (TheLoop->getHeader() != Phi->getParent()) + return nullptr; + + // The loop may have multiple entrances or multiple exits; we can analyze + // this phi if it has a unique entry value and a unique backedge value. + if (Phi->getNumIncomingValues() != 2) + return false; + Value *BEValue = nullptr, *StartValue = nullptr; + if (TheLoop->contains(Phi->getIncomingBlock(0))) { + BEValue = Phi->getIncomingValue(0); + StartValue = Phi->getIncomingValue(1); + } else { + assert(TheLoop->contains(Phi->getIncomingBlock(1)) && + "Unexpected Phi node in the loop"); + BEValue = Phi->getIncomingValue(1); + StartValue = Phi->getIncomingValue(0); + } + + if (!dyn_cast(BEValue)) + return false; + + BinaryOperator *BOp = cast(BEValue); + Value *Addend = nullptr; + if (BOp->getOpcode() == Instruction::FAdd) { + if (BOp->getOperand(0) == Phi) + Addend = BOp->getOperand(1); + else if (BOp->getOperand(1) == Phi) + Addend = BOp->getOperand(0); + } else if (BOp->getOpcode() == Instruction::FSub) + if (BOp->getOperand(0) == Phi) + Addend = BOp->getOperand(1); + + if (!Addend) + return false; + + // The addend should be loop invariant + if (auto *I = dyn_cast(Addend)) + if (TheLoop->contains(I)) + return false; + + const SCEV *Step = SE->getUnknown(Addend); + + Instruction *UAI = !BOp->hasUnsafeAlgebra() ? BOp : nullptr; + D = InductionDescriptor(StartValue, IK_FpInduction, Step, UAI, + BOp->getOpcode()); + return true; +} + +bool InductionDescriptor::isInductionPHI(PHINode *Phi, const Loop *TheLoop, PredicatedScalarEvolution &PSE, InductionDescriptor &D, bool Assume) { Type *PhiTy = Phi->getType(); - // We only handle integer and pointer inductions variables. - if (!PhiTy->isIntegerTy() && !PhiTy->isPointerTy()) + + // Handle integer and pointer inductions variables. + // Now we handle also FP induction but not trying to make a + // recurrent expression from the PHI node in-place. + + if (!PhiTy->isIntegerTy() && !PhiTy->isPointerTy() && + !PhiTy->isFloatTy() && !PhiTy->isDoubleTy() && !PhiTy->isHalfTy()) return false; + if (PhiTy->isFloatingPointTy()) + return isFpInductionPHI(Phi, TheLoop, PSE.getSE(), D); + const SCEV *PhiScev = PSE.getSCEV(Phi); const auto *AR = dyn_cast(PhiScev); @@ -752,10 +843,10 @@ return false; } - return isInductionPHI(Phi, PSE.getSE(), D, AR); + return isInductionPHI(Phi, TheLoop, PSE.getSE(), D, AR); } -bool InductionDescriptor::isInductionPHI(PHINode *Phi, +bool InductionDescriptor::isInductionPHI(PHINode *Phi, const Loop *TheLoop, ScalarEvolution *SE, InductionDescriptor &D, const SCEV *Expr) { @@ -773,7 +864,7 @@ return false; } - assert(AR->getLoop()->getHeader() == Phi->getParent() && + assert(TheLoop->getHeader() == Phi->getParent() && "PHI is an AddRec for a different loop?!"); Value *StartValue = Phi->getIncomingValueForBlock(AR->getLoop()->getLoopPreheader()); @@ -781,7 +872,7 @@ // Calculate the pointer stride and check if it is consecutive. // The stride may be a constant or a loop invariant integer value. const SCEVConstant *ConstStep = dyn_cast(Step); - if (!ConstStep && !SE->isLoopInvariant(Step, AR->getLoop())) + if (!ConstStep && !SE->isLoopInvariant(Step, TheLoop)) return false; if (PhiTy->isIntegerTy()) { Index: ../lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- ../lib/Transforms/Vectorize/LoopVectorize.cpp +++ ../lib/Transforms/Vectorize/LoopVectorize.cpp @@ -401,7 +401,10 @@ /// This function adds (StartIdx, StartIdx + Step, StartIdx + 2*Step, ...) /// to each vector element of Val. The sequence starts at StartIndex. - virtual Value *getStepVector(Value *Val, int StartIdx, Value *Step); + /// \p Opcode is relevant for FP induction variable. + virtual Value *getStepVector(Value *Val, int StartIdx, Value *Step, + Instruction::BinaryOps Opcode = + (Instruction::BinaryOps)0); /// Compute scalar induction steps. \p ScalarIV is the scalar induction /// variable on which to base the steps, \p Step is the size of the step, and @@ -622,7 +625,9 @@ bool IfPredicateStore = false) override; void vectorizeMemoryInstruction(Instruction *Instr) override; Value *getBroadcastInstrs(Value *V) override; - Value *getStepVector(Value *Val, int StartIdx, Value *Step) override; + Value *getStepVector(Value *Val, int StartIdx, Value *Step, + Instruction::BinaryOps Opcode = + (Instruction::BinaryOps)0) override; Value *reverseVector(Value *Vec) override; }; @@ -1976,31 +1981,58 @@ } Value *InnerLoopVectorizer::getStepVector(Value *Val, int StartIdx, - Value *Step) { + Value *Step, + Instruction::BinaryOps BinOp) { assert(Val->getType()->isVectorTy() && "Must be a vector"); - assert(Val->getType()->getScalarType()->isIntegerTy() && - "Elem must be an integer"); + assert((Val->getType()->getScalarType()->isIntegerTy() || + Val->getType()->getScalarType()->isFloatingPointTy()) && + "Induction Step must be an integer or FP"); assert(Step->getType() == Val->getType()->getScalarType() && "Step has wrong type"); // Create the types. - Type *ITy = Val->getType()->getScalarType(); + Type *STy = Val->getType()->getScalarType(); VectorType *Ty = cast(Val->getType()); int VLen = Ty->getNumElements(); SmallVector Indices; + if (Step->getType()->isIntegerTy()) { + // Create a vector of consecutive numbers from zero to VF. + for (int i = 0; i < VLen; ++i) + Indices.push_back(ConstantInt::get(STy, StartIdx + i)); + + Constant *Cv = ConstantVector::get(Indices); + assert(Cv->getType() == Val->getType() && "Invalid consecutive vec"); + Step = Builder.CreateVectorSplat(VLen, Step); + assert(Step->getType() == Val->getType() && "Invalid step vec"); + // FIXME: The newly created binary instructions should contain nsw/nuw flags, + // which can be found from the original scalar operations. + Step = Builder.CreateMul(Cv, Step); + return Builder.CreateAdd(Val, Step, "induction"); + } + + // Floating point induction. + assert(BinOp && "Binary Opcode should be specified for FP induction"); // Create a vector of consecutive numbers from zero to VF. for (int i = 0; i < VLen; ++i) - Indices.push_back(ConstantInt::get(ITy, StartIdx + i)); + Indices.push_back(ConstantFP::get(STy, (double)(StartIdx + i))); // Add the consecutive indices to the vector value. Constant *Cv = ConstantVector::get(Indices); - assert(Cv->getType() == Val->getType() && "Invalid consecutive vec"); + Step = Builder.CreateVectorSplat(VLen, Step); - assert(Step->getType() == Val->getType() && "Invalid step vec"); - // FIXME: The newly created binary instructions should contain nsw/nuw flags, - // which can be found from the original scalar operations. - Step = Builder.CreateMul(Cv, Step); - return Builder.CreateAdd(Val, Step, "induction"); + + // Floating point operations had to be 'fast' to enable the induction. + FastMathFlags Flags; + Flags.setUnsafeAlgebra(); + + Value *MulOp = Builder.CreateFMul(Cv, Step); + if (dyn_cast(MulOp)) + // Have to check, MulOp may be a constant + cast(MulOp)->setFastMathFlags(Flags); + + Value *BOp = Builder.CreateBinOp(BinOp, Val, MulOp, "induction"); + cast(BOp)->setFastMathFlags(Flags); + return BOp; } void InnerLoopVectorizer::buildScalarSteps(Value *ScalarIV, Value *Step, @@ -3074,8 +3106,13 @@ EndValue = CountRoundDown; } else { IRBuilder<> B(LoopBypassBlocks.back()->getTerminator()); - Value *CRD = B.CreateSExtOrTrunc(CountRoundDown, - II.getStep()->getType(), "cast.crd"); + Value *CRD; + if (II.getStep()->getType()->isIntegerTy()) + CRD = B.CreateSExtOrTrunc(CountRoundDown, II.getStep()->getType(), + "cast.crd"); + else + CRD = B.CreateCast(Instruction::SIToFP, CountRoundDown, + II.getStep()->getType(), "cast.crd"); const DataLayout &DL = OrigLoop->getHeader()->getModule()->getDataLayout(); EndValue = II.transform(B, CRD, PSE.getSE(), DL); EndValue->setName("ind.end"); @@ -4022,7 +4059,7 @@ llvm_unreachable("Unknown induction"); case InductionDescriptor::IK_IntInduction: return widenIntInduction(P, Entry); - case InductionDescriptor::IK_PtrInduction: + case InductionDescriptor::IK_PtrInduction: { // Handle the pointer induction variable case. assert(P->getType()->isPointerTy() && "Unexpected type."); // This is the normalized GEP that starts counting at zero. @@ -4055,6 +4092,27 @@ } return; } + case InductionDescriptor::IK_FpInduction: { + assert(P->getType() == II.getStartValue()->getType() && + "Types must match"); + // Handle other induction variables that are now based on the + // canonical one. + assert(P != OldInduction && "Main induction can be integer only"); + + Value *V = Builder.CreateCast(Instruction::SIToFP, Induction, P->getType()); + V = II.transform(Builder, V, PSE.getSE(), DL); + V->setName("fp.offset.idx"); + + Value *Broadcasted = getBroadcastInstrs(V); + // After broadcasting the induction variable we need to make the vector + // consecutive by adding 0, 1, 2, etc. + Value *StepVal = cast(II.getStep())->getValue(); + for (unsigned part = 0; part < UF; ++part) + Entry[part] = getStepVector(Broadcasted, VF * part, StepVal, + II.getBinaryOpcode()); + return; + } + } } void InnerLoopVectorizer::vectorizeBlockInLoop(BasicBlock *BB, PhiVector *PV) { @@ -4540,10 +4598,12 @@ const DataLayout &DL = Phi->getModule()->getDataLayout(); // Get the widest type. - if (!WidestIndTy) - WidestIndTy = convertPointerToIntegerType(DL, PhiTy); - else - WidestIndTy = getWiderType(DL, PhiTy, WidestIndTy); + if (!PhiTy->isFloatingPointTy()) { + if (!WidestIndTy) + WidestIndTy = convertPointerToIntegerType(DL, PhiTy); + else + WidestIndTy = getWiderType(DL, PhiTy, WidestIndTy); + } // Int inductions are special because we only allow one IV. if (ID.getKind() == InductionDescriptor::IK_IntInduction && @@ -4624,8 +4684,10 @@ } InductionDescriptor ID; - if (InductionDescriptor::isInductionPHI(Phi, PSE, ID)) { + if (InductionDescriptor::isInductionPHI(Phi, TheLoop, PSE, ID)) { addInductionPhi(Phi, ID, AllowedExit); + if (ID.hasUnsafeAlgebra()) + Requirements->addUnsafeAlgebraInst(ID.getUnsafeAlgebraInst()); continue; } @@ -4636,7 +4698,7 @@ // As a last resort, coerce the PHI to a AddRec expression // and re-try classifying it a an induction PHI. - if (InductionDescriptor::isInductionPHI(Phi, PSE, ID, true)) { + if (InductionDescriptor::isInductionPHI(Phi, TheLoop, PSE, ID, true)) { addInductionPhi(Phi, ID, AllowedExit); continue; } @@ -6331,11 +6393,27 @@ Value *InnerLoopUnroller::getBroadcastInstrs(Value *V) { return V; } -Value *InnerLoopUnroller::getStepVector(Value *Val, int StartIdx, Value *Step) { +Value *InnerLoopUnroller::getStepVector(Value *Val, int StartIdx, Value *Step, + Instruction::BinaryOps BinOp) { // When unrolling and the VF is 1, we only need to add a simple scalar. - Type *ITy = Val->getType(); - assert(!ITy->isVectorTy() && "Val must be a scalar"); - Constant *C = ConstantInt::get(ITy, StartIdx); + Type *Ty = Val->getType(); + assert(!Ty->isVectorTy() && "Val must be a scalar"); + + if (Ty->isFloatingPointTy()) { + Constant *C = ConstantFP::get(Ty, (double)StartIdx); + + // Floating point operations had to be 'fast' to enable the unrolling. + FastMathFlags Flags; + Flags.setUnsafeAlgebra(); + + Value *MulOp = Builder.CreateFMul(C, Step); + if (isa(MulOp)) + cast(MulOp)->setFastMathFlags(Flags); + Value *BOp = Builder.CreateBinOp(BinOp, Val, MulOp); + cast(BOp)->setFastMathFlags(Flags); + return BOp; + } + Constant *C = ConstantInt::get(Ty, StartIdx); return Builder.CreateAdd(Val, Builder.CreateMul(C, Step), "induction"); } Index: ../test/Transforms/LoopVectorize/float-induction.ll =================================================================== --- ../test/Transforms/LoopVectorize/float-induction.ll +++ ../test/Transforms/LoopVectorize/float-induction.ll @@ -0,0 +1,146 @@ +; RUN: opt < %s -loop-vectorize -force-vector-interleave=1 -force-vector-width=4 -dce -instcombine -S | FileCheck %s + + +; CHECK-LABEL: @fp_iv_loop1( +; CHECK: vector.body: +; CHECK: %[[INDEX:.*]] = sitofp i64 {{.*}} to float +; CHECK: %[[VEC_INCR:.*]] = fmul fast float %{{.*}}, %[[INDEX]] +; CHECK: fsub fast float %init, %[[VEC_INCR]] +; CHECK: store <4 x float> + +@fp_inc = common global float 0.000000e+00, align 4 + +;void fp_iv_loop1(float init, float * __restrict__ A, int N) { +; float x = init; +; for (int i=0; i < N; ++i) { +; A[i] = x; +; x -= fp_inc; +; } +;} + +define void @fp_iv_loop1(float %init, float* noalias nocapture %A, i32 %N) #0 { +entry: + %cmp4 = icmp sgt i32 %N, 0 + br i1 %cmp4, label %for.body.lr.ph, label %for.end + +for.body.lr.ph: ; preds = %entry + %0 = load float, float* @fp_inc, align 4 + br label %for.body + +for.body: ; preds = %for.body, %for.body.lr.ph + %indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ] + %x.05 = phi float [ %init, %for.body.lr.ph ], [ %add, %for.body ] + %arrayidx = getelementptr inbounds float, float* %A, i64 %indvars.iv + store float %x.05, float* %arrayidx, align 4 + %add = fsub fast float %x.05, %0 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %N + br i1 %exitcond, label %for.end.loopexit, label %for.body + +for.end.loopexit: ; preds = %for.body + br label %for.end + +for.end: ; preds = %for.end.loopexit, %entry + ret void +} + +;void fp_iv_loop2(float init, float * __restrict__ A, int N) { +; float x = init; +; for (int i=0; i < N; ++i) { +; A[i] = x; +; x += 0.5; +; } +;} + +; CHECK-LABEL: @fp_iv_loop2( +; CHECK: vector.body +; CHECK: %[[index:.*]] = phi i64 [ 0, %vector.ph ] +; CHECK: sitofp i64 %[[index]] to float +; CHECK: %[[VAR1:.*]] = fmul fast float {{.*}}, 5.000000e-01 +; CHECK: %[[VAR2:.*]] = fadd fast float %[[VAR1]] +; CHECK: insertelement <4 x float> undef, float %[[VAR2]], i32 0 +; CHECK: shufflevector <4 x float> {{.*}}, <4 x float> undef, <4 x i32> zeroinitializer +; CHECK: fadd fast <4 x float> {{.*}}, +; CHECK: store <4 x float> + +define void @fp_iv_loop2(float %init, float* noalias nocapture %A, i32 %N) #0 { +entry: + %cmp4 = icmp sgt i32 %N, 0 + br i1 %cmp4, label %for.body.preheader, label %for.end + +for.body.preheader: ; preds = %entry + br label %for.body + +for.body: ; preds = %for.body.preheader, %for.body + %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %for.body.preheader ] + %x.06 = phi float [ %conv1, %for.body ], [ %init, %for.body.preheader ] + %arrayidx = getelementptr inbounds float, float* %A, i64 %indvars.iv + store float %x.06, float* %arrayidx, align 4 + %conv1 = fadd fast float %x.06, 5.000000e-01 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %N + br i1 %exitcond, label %for.end.loopexit, label %for.body + +for.end.loopexit: ; preds = %for.body + br label %for.end + +for.end: ; preds = %for.end.loopexit, %entry + ret void +} + +;void fp_iv_loop3(float init, float * __restrict__ A, float * __restrict__ B, float * __restrict__ C, int N) { +; int i = 0; +; float x = init; +; float y = 0.1; +; for (; i < N; ++i) { +; A[i] = x; +; x += fp_inc; +; y -= 0.5; +; B[i] = x + y; +; C[i] = y; +; } +;} +; CHECK-LABEL: @fp_iv_loop3( +; CHECK: vector.body +; CHECK: %[[index:.*]] = phi i64 [ 0, %vector.ph ] +; CHECK: sitofp i64 %[[index]] to float +; CHECK: %[[VAR1:.*]] = fmul fast float {{.*}}, -5.000000e-01 +; CHECK: fadd fast float %[[VAR1]] +; CHECK: fadd fast <4 x float> {{.*}}, +; CHECK: store <4 x float> + +define void @fp_iv_loop3(float %init, float* noalias nocapture %A, float* noalias nocapture %B, float* noalias nocapture %C, i32 %N) #0 { +entry: + %cmp9 = icmp sgt i32 %N, 0 + br i1 %cmp9, label %for.body.lr.ph, label %for.end + +for.body.lr.ph: ; preds = %entry + %0 = load float, float* @fp_inc, align 4 + br label %for.body + +for.body: ; preds = %for.body, %for.body.lr.ph + %indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ] + %y.012 = phi float [ 0x3FB99999A0000000, %for.body.lr.ph ], [ %conv1, %for.body ] + %x.011 = phi float [ %init, %for.body.lr.ph ], [ %add, %for.body ] + %arrayidx = getelementptr inbounds float, float* %A, i64 %indvars.iv + store float %x.011, float* %arrayidx, align 4 + %add = fadd fast float %x.011, %0 + %conv1 = fadd fast float %y.012, -5.000000e-01 + %add2 = fadd fast float %conv1, %add + %arrayidx4 = getelementptr inbounds float, float* %B, i64 %indvars.iv + store float %add2, float* %arrayidx4, align 4 + %arrayidx6 = getelementptr inbounds float, float* %C, i64 %indvars.iv + store float %conv1, float* %arrayidx6, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %N + br i1 %exitcond, label %for.end.loopexit, label %for.body + +for.end.loopexit: + br label %for.end + +for.end: + ret void +}