/// 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");
// 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;
}
Value *Src = FPT.getOperand(0);
if (isa<SIToFPInst>(Src) || isa<UIToFPInst>(Src)) {
auto *FPCast = cast<CastInst>(Src);
- if (isKnownExactCastIntToFP(*FPCast))
+ if (isKnownExactCastIntToFP(*FPCast, *this))
return CastInst::Create(FPCast->getOpcode(), FPCast->getOperand(0), Ty);
}
Value *Src = FPExt.getOperand(0);
if (isa<SIToFPInst>(Src) || isa<UIToFPInst>(Src)) {
auto *FPCast = cast<CastInst>(Src);
- if (isKnownExactCastIntToFP(*FPCast))
+ if (isKnownExactCastIntToFP(*FPCast, *this))
return CastInst::Create(FPCast->getOpcode(), FPCast->getOperand(0), Ty);
}
// 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
define half @masked_sint_to_fptrunc1(i32 %x) {
; CHECK-LABEL: @masked_sint_to_fptrunc1(
; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 16777215
-; CHECK-NEXT: [[F:%.*]] = sitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fptrunc float [[F]] to half
+; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[M]] to half
; CHECK-NEXT: ret half [[R]]
;
%m = and i32 %x, 16777215
define half @masked_sint_to_fptrunc2(i32 %x) {
; CHECK-LABEL: @masked_sint_to_fptrunc2(
; CHECK-NEXT: [[M:%.*]] = lshr i32 [[X:%.*]], 8
-; CHECK-NEXT: [[F:%.*]] = sitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fptrunc float [[F]] to half
+; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[M]] to half
; CHECK-NEXT: ret half [[R]]
;
%m = lshr i32 %x, 8
define double @masked_sint_to_fpext1(i32 %x) {
; CHECK-LABEL: @masked_sint_to_fpext1(
; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 16777215
-; CHECK-NEXT: [[F:%.*]] = sitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fpext float [[F]] to double
+; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[M]] to double
; CHECK-NEXT: ret double [[R]]
;
%m = and i32 %x, 16777215
define double @masked_sint_to_fpext2(i32 %x) {
; CHECK-LABEL: @masked_sint_to_fpext2(
; CHECK-NEXT: [[M:%.*]] = lshr i32 [[X:%.*]], 8
-; CHECK-NEXT: [[F:%.*]] = sitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fpext float [[F]] to double
+; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[M]] to double
; CHECK-NEXT: ret double [[R]]
;
%m = lshr i32 %x, 8
define half @masked_uint_to_fptrunc1(i32 %x) {
; CHECK-LABEL: @masked_uint_to_fptrunc1(
; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 16777215
-; CHECK-NEXT: [[F:%.*]] = uitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fptrunc float [[F]] to half
+; CHECK-NEXT: [[R:%.*]] = uitofp i32 [[M]] to half
; CHECK-NEXT: ret half [[R]]
;
%m = and i32 %x, 16777215
define half @masked_uint_to_fptrunc2(i32 %x) {
; CHECK-LABEL: @masked_uint_to_fptrunc2(
; CHECK-NEXT: [[M:%.*]] = lshr i32 [[X:%.*]], 8
-; CHECK-NEXT: [[F:%.*]] = uitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fptrunc float [[F]] to half
+; CHECK-NEXT: [[R:%.*]] = uitofp i32 [[M]] to half
; CHECK-NEXT: ret half [[R]]
;
%m = lshr i32 %x, 8
define double @masked_uint_to_fpext1(i32 %x) {
; CHECK-LABEL: @masked_uint_to_fpext1(
; CHECK-NEXT: [[M:%.*]] = and i32 [[X:%.*]], 16777215
-; CHECK-NEXT: [[F:%.*]] = uitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fpext float [[F]] to double
+; CHECK-NEXT: [[R:%.*]] = uitofp i32 [[M]] to double
; CHECK-NEXT: ret double [[R]]
;
%m = and i32 %x, 16777215
define double @masked_uint_to_fpext2(i32 %x) {
; CHECK-LABEL: @masked_uint_to_fpext2(
; CHECK-NEXT: [[M:%.*]] = lshr i32 [[X:%.*]], 8
-; CHECK-NEXT: [[F:%.*]] = uitofp i32 [[M]] to float
-; CHECK-NEXT: [[R:%.*]] = fpext float [[F]] to double
+; CHECK-NEXT: [[R:%.*]] = uitofp i32 [[M]] to double
; CHECK-NEXT: ret double [[R]]
;
%m = lshr i32 %x, 8
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