Index: llvm/lib/Transforms/Utils/SimplifyIndVar.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -693,20 +693,36 @@ MaskBits = SE->getUnsignedRange(IV).getActiveBits(); unsigned DestNumSigBits = UseInst->getType()->getFPMantissaWidth(); if (MaskBits <= DestNumSigBits) { - for (User *U : UseInst->users()) { + for (User *U : make_early_inc_range(UseInst->users())) { // Match for fptosi/fptoui of sitofp and with same type. auto *CI = dyn_cast(U); - if (!CI || IVOperand->getType() != CI->getType()) + if (!CI) continue; CastInst::CastOps Opcode = CI->getOpcode(); if (Opcode != CastInst::FPToSI && Opcode != CastInst::FPToUI) continue; - CI->replaceAllUsesWith(IVOperand); + PHINode *Phi = cast(IVOperand); + Value *Conv = nullptr; + if (IVOperand->getType() != CI->getType()) { + IRBuilder<> Builder(&*Phi->getParent()->getFirstInsertionPt()); + StringRef Name = Phi->getName(); + if (SE->getTypeSizeInBits(IVOperand->getType()) > + SE->getTypeSizeInBits(CI->getType())) { + Conv = Builder.CreateTrunc(Phi, CI->getType(), Name + ".trunc"); + } else if (Opcode == CastInst::FPToSI) { + Conv = Builder.CreateSExt(Phi, CI->getType(), Name + ".sext"); + } else { + Conv = Builder.CreateZExt(Phi, CI->getType(), Name + ".zext"); + } + } else + Conv = Phi; + + CI->replaceAllUsesWith(Conv); DeadInsts.push_back(CI); LLVM_DEBUG(dbgs() << "INDVARS: Replace IV user: " << *CI - << " with: " << *IVOperand << '\n'); + << " with: " << *Conv << '\n'); ++NumFoldedUser; Changed = true; Index: llvm/test/Transforms/IndVarSimplify/floating-point-small-iv.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/floating-point-small-iv.ll +++ llvm/test/Transforms/IndVarSimplify/floating-point-small-iv.ll @@ -72,18 +72,17 @@ ret void } -; Negative test: Type mismatch between the integer IV and the fptosi result -define void @sitofp_fptosi_range_mismatch_type() { +; Type mismatch between the integer IV and the fptosi result +define void @sitofp_fptosi_range_trunc() { ; -; CHECK-LABEL: @sitofp_fptosi_range_mismatch_type( +; CHECK-LABEL: @sitofp_fptosi_range_trunc( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ 100, [[ENTRY:%.*]] ], [ [[DEC_INT:%.*]], [[FOR_BODY]] ] -; CHECK-NEXT: [[INDVAR_CONV:%.*]] = sitofp i32 [[IV_INT]] to float -; CHECK-NEXT: [[CONV:%.*]] = fptosi float [[INDVAR_CONV]] to i16 -; CHECK-NEXT: [[IDXPROM32:%.*]] = sext i16 [[CONV]] to i32 -; CHECK-NEXT: [[IDXPROM64:%.*]] = sext i16 [[CONV]] to i64 +; CHECK-NEXT: [[IV_INT_TRUNC:%.*]] = trunc i32 [[IV_INT]] to i16 +; CHECK-NEXT: [[IDXPROM32:%.*]] = sext i16 [[IV_INT_TRUNC]] to i32 +; CHECK-NEXT: [[IDXPROM64:%.*]] = sext i16 [[IV_INT_TRUNC]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [16777219 x i32], [16777219 x i32]* @array, i64 0, i64 [[IDXPROM64]] ; CHECK-NEXT: store i32 [[IDXPROM32]], i32* [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[DEC_INT]] = add nsw i32 [[IV_INT]], -1 @@ -111,6 +110,78 @@ ret void } +define void @sitofp_fptosi_range_sext() { +; +; CHECK-LABEL: @sitofp_fptosi_range_sext( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[IV_INT:%.*]] = phi i16 [ 100, [[ENTRY:%.*]] ], [ [[DEC_INT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[IDXPROM32:%.*]] = sext i16 [[IV_INT]] to i32 +; CHECK-NEXT: [[IDXPROM64:%.*]] = sext i16 [[IV_INT]] to i64 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [16777219 x i32], [16777219 x i32]* @array, i64 0, i64 [[IDXPROM64]] +; CHECK-NEXT: store i32 [[IDXPROM32]], i32* [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[DEC_INT]] = add nsw i16 [[IV_INT]], -1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i16 [[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 = %for.body, %entry + %iv.int = phi i16 [ 100, %entry ], [ %dec.int, %for.body ] + %indvar.conv = sitofp i16 %iv.int to float + %conv = fptosi float %indvar.conv to i16 + %idxprom32 = sext i16 %conv to i32 + %idxprom64 = sext i16 %conv to i64 + %arrayidx = getelementptr inbounds [16777219 x i32], [16777219 x i32]* @array, i64 0, i64 %idxprom64 + store i32 %idxprom32, i32* %arrayidx, align 4 + %dec.int = add nsw i16 %iv.int, -1 + %cmp = icmp ugt i16 %dec.int, 0 + br i1 %cmp, label %for.body, label %cleanup + +cleanup: ; preds = %for.body + ret void +} + +define void @sitofp_fptosi_range_zext() { +; +; CHECK-LABEL: @sitofp_fptosi_range_zext( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[IV_INT:%.*]] = phi i16 [ 100, [[ENTRY:%.*]] ], [ [[DEC_INT:%.*]], [[FOR_BODY]] ] +; CHECK-NEXT: [[IDXPROM32:%.*]] = zext i16 [[IV_INT]] to i32 +; CHECK-NEXT: [[IDXPROM64:%.*]] = zext i16 [[IV_INT]] to i64 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [16777219 x i32], [16777219 x i32]* @array, i64 0, i64 [[IDXPROM64]] +; CHECK-NEXT: store i32 [[IDXPROM32]], i32* [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[DEC_INT]] = add nsw i16 [[IV_INT]], -1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i16 [[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 = %for.body, %entry + %iv.int = phi i16 [ 100, %entry ], [ %dec.int, %for.body ] + %indvar.conv = sitofp i16 %iv.int to float + %conv = fptosi float %indvar.conv to i16 + %idxprom32 = zext i16 %conv to i32 + %idxprom64 = zext i16 %conv to i64 + %arrayidx = getelementptr inbounds [16777219 x i32], [16777219 x i32]* @array, i64 0, i64 %idxprom64 + store i32 %idxprom32, i32* %arrayidx, align 4 + %dec.int = add nsw i16 %iv.int, -1 + %cmp = icmp ugt i16 %dec.int, 0 + br i1 %cmp, label %for.body, label %cleanup + +cleanup: ; preds = %for.body + ret void +} + define void @sitofp_fptoui_range() { ; CHECK-LABEL: @sitofp_fptoui_range( ; CHECK-NEXT: entry: