Index: llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1720,7 +1720,7 @@ /// Return true if the cast from integer to FP can be proven to be exact for all /// possible inputs (the conversion does not lose any precision). -static bool isKnownExactCastIntToFP(CastInst &I) { +static bool isKnownExactCastIntToFP(CastInst &I, InstCombinerImpl &IC) { CastInst::CastOps Opcode = I.getOpcode(); assert((Opcode == CastInst::SIToFP || Opcode == CastInst::UIToFP) && "Unexpected cast"); @@ -1754,9 +1754,14 @@ return true; } - // TODO: // Try harder to find if the source integer type has less significant bits. // For example, compute number of sign bits or compute low bit mask. + KnownBits SrcKnown = IC.computeKnownBits(Src, 0, &I); + int LowBits = + (int)SrcTy->getScalarSizeInBits() - SrcKnown.countMinLeadingZeros(); + if (LowBits <= DestNumSigBits) + return true; + return false; } @@ -1937,7 +1942,7 @@ Value *Src = FPT.getOperand(0); if (isa(Src) || isa(Src)) { auto *FPCast = cast(Src); - if (isKnownExactCastIntToFP(*FPCast)) + if (isKnownExactCastIntToFP(*FPCast, *this)) return CastInst::Create(FPCast->getOpcode(), FPCast->getOperand(0), Ty); } @@ -1951,7 +1956,7 @@ Value *Src = FPExt.getOperand(0); if (isa(Src) || isa(Src)) { auto *FPCast = cast(Src); - if (isKnownExactCastIntToFP(*FPCast)) + if (isKnownExactCastIntToFP(*FPCast, *this)) return CastInst::Create(FPCast->getOpcode(), FPCast->getOperand(0), Ty); } @@ -1978,7 +1983,7 @@ // This means this is also safe for a signed input and unsigned output, since // a negative input would lead to undefined behavior. - if (!isKnownExactCastIntToFP(*OpI)) { + if (!isKnownExactCastIntToFP(*OpI, *this)) { // The first cast may not round exactly based on the source integer width // and FP width, but the overflow UB rules can still allow this to fold. // If the destination type is narrow, that means the intermediate FP value Index: llvm/test/Transforms/InstCombine/fptrunc.ll =================================================================== --- llvm/test/Transforms/InstCombine/fptrunc.ll +++ llvm/test/Transforms/InstCombine/fptrunc.ll @@ -182,8 +182,7 @@ define half @ItoFtoF_u25_f32_f16(i25 %i) { ; CHECK-LABEL: @ItoFtoF_u25_f32_f16( -; CHECK-NEXT: [[X:%.*]] = uitofp i25 [[I:%.*]] to float -; CHECK-NEXT: [[R:%.*]] = fptrunc float [[X]] to half +; CHECK-NEXT: [[R:%.*]] = uitofp i25 [[I:%.*]] to half ; CHECK-NEXT: ret half [[R]] ; %x = uitofp i25 %i to float Index: llvm/test/Transforms/InstCombine/sitofp.ll =================================================================== --- llvm/test/Transforms/InstCombine/sitofp.ll +++ llvm/test/Transforms/InstCombine/sitofp.ll @@ -218,16 +218,38 @@ ret i55 %C } -; TODO: The mask guarantees that the input is small enough to eliminate the FP casts. +; The mask guarantees that the input is small enough to eliminate the FP casts. define i25 @masked_input(i25 %A) { ; CHECK-LABEL: @masked_input( ; CHECK-NEXT: [[M:%.*]] = and i25 [[A:%.*]], 65535 +; CHECK-NEXT: ret i25 [[M]] +; + %m = and i25 %A, 65535 + %B = uitofp i25 %m to float + %C = fptoui float %B to i25 + ret i25 %C +} + +define i25 @max_masked_input(i25 %A) { +; CHECK-LABEL: @max_masked_input( +; CHECK-NEXT: [[M:%.*]] = and i25 [[A:%.*]], 16777215 +; CHECK-NEXT: ret i25 [[M]] +; + %m = and i25 %A, 16777215 ; max intermediate 16777215 (= 1 << 24)-1 + %B = uitofp i25 %m to float + %C = fptoui float %B to i25 + ret i25 %C +} + +define i25 @overflow_masked_input(i25 %A) { +; CHECK-LABEL: @overflow_masked_input( +; CHECK-NEXT: [[M:%.*]] = and i25 [[A:%.*]], -16777216 ; CHECK-NEXT: [[B:%.*]] = uitofp i25 [[M]] to float ; CHECK-NEXT: [[C:%.*]] = fptoui float [[B]] to i25 ; CHECK-NEXT: ret i25 [[C]] ; - %m = and i25 %A, 65535 + %m = and i25 %A, 16777216 ; Negative test - intermediate 16777216 (= 1 << 24) %B = uitofp i25 %m to float %C = fptoui float %B to i25 ret i25 %C