Index: llvm/lib/Transforms/Utils/SimplifyIndVar.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -79,6 +79,7 @@ bool eliminateIdentitySCEV(Instruction *UseInst, Instruction *IVOperand); bool replaceIVUserWithLoopInvariant(Instruction *UseInst); + bool replaceFloatIVWithIntegerIV(Instruction *UseInst, Value *IVOperand); bool eliminateOverflowIntrinsic(WithOverflowInst *WO); bool eliminateSaturatingIntrinsic(SaturatingInst *SI); @@ -673,6 +674,35 @@ return true; } +/// Eliminate redundant type cast between integer and float. +bool SimplifyIndvar::replaceFloatIVWithIntegerIV(Instruction *UseInst, + Value *IVOperand) { + if (UseInst->getOpcode() != CastInst::SIToFP) + return false; + + // Get the symbolic expression for this instruction. + ConstantRange IVRange = SE->getSignedRange(SE->getSCEV(IVOperand)); + unsigned DestNumSigBits = UseInst->getType()->getFPMantissaWidth(); + if (IVRange.getActiveBits() <= DestNumSigBits) { + + for (User *U : UseInst->users()) { + // Match for fptosi of sitofp and with same type. + auto *CI = dyn_cast(U); + if (!CI || IVOperand->getType() != CI->getType()) + continue; + + CI->replaceAllUsesWith(IVOperand); + LLVM_DEBUG(dbgs() << "INDVARS: Replace IV user: " << *CI + << " with: " << *IVOperand << '\n'); + + ++NumFoldedUser; + Changed |= true; + } + } + + return Changed; +} + /// Eliminate any operation that SCEV can prove is an identity function. bool SimplifyIndvar::eliminateIdentitySCEV(Instruction *UseInst, Instruction *IVOperand) { @@ -896,6 +926,10 @@ } } + // Try to use integer induction for FPToSI of float induction Directly. + if (replaceFloatIVWithIntegerIV(UseInst, IVOperand)) + continue; + CastInst *Cast = dyn_cast(UseInst); if (V && Cast) { V->visitCast(Cast); Index: llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll +++ llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll @@ -377,7 +377,7 @@ ; CHECK-NEXT: [[FLOAT_IV_INT:%.*]] = phi i32 [ 1000, [[ENTRY:%.*]] ], [ [[FLOAT_IV_NEXT_INT:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[INDVAR_CONV:%.*]] = sitofp i32 [[FLOAT_IV_INT]] to float ; CHECK-NEXT: [[CONV:%.*]] = fptosi float [[INDVAR_CONV]] to i32 -; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[CONV]] to i64 +; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[FLOAT_IV_INT]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DST:%.*]], i64 [[IDXPROM]] ; CHECK-NEXT: store float [[INDVAR_CONV]], ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[FLOAT_IV_NEXT_INT]] = add nsw i32 [[FLOAT_IV_INT]], -1 Index: llvm/test/Transforms/IndVarSimplify/floating-point-small-iv.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/IndVarSimplify/floating-point-small-iv.ll @@ -0,0 +1,37 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -indvars -adce -S | FileCheck %s + +@array = dso_local global [101 x i32] zeroinitializer, align 4 + +define void @small_const_bound(i32 %index) { +; CHECK-LABEL: @small_const_bound( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[I_010_INT:%.*]] = phi i32 [ 100, [[ENTRY:%.*]] ], [ [[DEC_INT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I_010_INT]] to i64 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [101 x i32], [101 x i32]* @array, i64 0, i64 [[IDXPROM]] +; CHECK-NEXT: store i32 [[I_010_INT]], i32* [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[DEC_INT]] = add nsw i32 [[I_010_INT]], -1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[DEC_INT]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP:%.*]] +; CHECK: cleanup: +; CHECK-NEXT: ret void +; +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %i.010 = phi float [ 1.000000e+02, %entry ], [ %dec, %for.body ] + %conv = fptosi float %i.010 to i32 + %idxprom = sext i32 %conv to i64 + %arrayidx = getelementptr inbounds [101 x i32], [101 x i32]* @array, i64 0, i64 %idxprom + store i32 %conv, i32* %arrayidx, align 4 + %dec = fadd fast float %i.010, -1.000000e+00 + %cmp = fcmp fast ogt float %dec, 0.000000e+00 + br i1 %cmp, label %for.body, label %cleanup + +cleanup: ; preds = %for.body + ret void +} +