diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 2bb31406912135..c5b0956232b254 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1757,8 +1757,18 @@ static bool isKnownExactCastIntToFP(CastInst &I) { return false; } -Instruction *InstCombiner::visitFPExt(CastInst &CI) { - return commonCastTransforms(CI); +Instruction *InstCombiner::visitFPExt(CastInst &FPExt) { + // If the source operand is a cast from integer to FP and known exact, then + // cast the integer operand directly to the destination type. + Type *Ty = FPExt.getType(); + Value *Src = FPExt.getOperand(0); + if (isa(Src) || isa(Src)) { + auto *FPCast = cast(Src); + if (isKnownExactCastIntToFP(*FPCast)) + return CastInst::Create(FPCast->getOpcode(), FPCast->getOperand(0), Ty); + } + + return commonCastTransforms(FPExt); } /// fpto{s/u}i({u/s}itofp(X)) --> X or zext(X) or sext(X) or trunc(X) diff --git a/llvm/test/Transforms/InstCombine/fpextend.ll b/llvm/test/Transforms/InstCombine/fpextend.ll index 7125f305958d89..1b6afd3216d7eb 100644 --- a/llvm/test/Transforms/InstCombine/fpextend.ll +++ b/llvm/test/Transforms/InstCombine/fpextend.ll @@ -259,10 +259,11 @@ define float @test18(half %x, half %y) nounwind { ret float %t56 } +; Convert from integer is exact, so convert directly to double. + define double @ItoFtoF_s25_f32_f64(i25 %i) { ; CHECK-LABEL: @ItoFtoF_s25_f32_f64( -; CHECK-NEXT: [[X:%.*]] = sitofp i25 [[I:%.*]] to float -; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to double +; CHECK-NEXT: [[R:%.*]] = sitofp i25 [[I:%.*]] to double ; CHECK-NEXT: ret double [[R]] ; %x = sitofp i25 %i to float @@ -270,10 +271,11 @@ define double @ItoFtoF_s25_f32_f64(i25 %i) { ret double %r } +; Convert from integer is exact, so convert directly to fp128. + define fp128 @ItoFtoF_u24_f32_f128(i24 %i) { ; CHECK-LABEL: @ItoFtoF_u24_f32_f128( -; CHECK-NEXT: [[X:%.*]] = uitofp i24 [[I:%.*]] to float -; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to fp128 +; CHECK-NEXT: [[R:%.*]] = uitofp i24 [[I:%.*]] to fp128 ; CHECK-NEXT: ret fp128 [[R]] ; %x = uitofp i24 %i to float @@ -281,6 +283,8 @@ define fp128 @ItoFtoF_u24_f32_f128(i24 %i) { ret fp128 %r } +; Negative test - intermediate rounding in float type. + define double @ItoFtoF_s26_f32_f64(i26 %i) { ; CHECK-LABEL: @ItoFtoF_s26_f32_f64( ; CHECK-NEXT: [[X:%.*]] = sitofp i26 [[I:%.*]] to float @@ -292,6 +296,8 @@ define double @ItoFtoF_s26_f32_f64(i26 %i) { ret double %r } +; Negative test - intermediate rounding in float type. + define double @ItoFtoF_u25_f32_f64(i25 %i) { ; CHECK-LABEL: @ItoFtoF_u25_f32_f64( ; CHECK-NEXT: [[X:%.*]] = uitofp i25 [[I:%.*]] to float