forked from OSchip/llvm-project
[InstCombine] improve analysis of FP->int->FP to eliminate fpextend
This was originally in D79116. Converting from a narrow-enough FP source value to integer and back to FP guarantees that the conversion to FP is exact because of UB/poison-on-overflow. This was suggested in PR36617: https://bugs.llvm.org/show_bug.cgi?id=36617#c19
This commit is contained in:
parent
b54a663312
commit
bfd512160f
|
@ -1749,9 +1749,28 @@ static bool isKnownExactCastIntToFP(CastInst &I) {
|
|||
|
||||
// Easy case - if the source integer type has less bits than the FP mantissa,
|
||||
// then the cast must be exact.
|
||||
if (SrcSize <= FPTy->getFPMantissaWidth())
|
||||
int DestNumSigBits = FPTy->getFPMantissaWidth();
|
||||
if (SrcSize <= DestNumSigBits)
|
||||
return true;
|
||||
|
||||
// Cast from FP to integer and back to FP is independent of the intermediate
|
||||
// integer width because of poison on overflow.
|
||||
Value *F;
|
||||
if (match(Src, m_FPToSI(m_Value(F))) || match(Src, m_FPToUI(m_Value(F)))) {
|
||||
// If this is uitofp (fptosi F), the source needs an extra bit to avoid
|
||||
// potential rounding of negative FP input values.
|
||||
int SrcNumSigBits = F->getType()->getFPMantissaWidth();
|
||||
if (!IsSigned && match(Src, m_FPToSI(m_Value())))
|
||||
SrcNumSigBits++;
|
||||
|
||||
// [su]itofp (fpto[su]i F) --> exact if the source type has less or equal
|
||||
// significant bits than the destination (and make sure neither type is
|
||||
// weird -- ppc_fp128).
|
||||
if (SrcNumSigBits > 0 && DestNumSigBits > 0 &&
|
||||
SrcNumSigBits <= DestNumSigBits)
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// Try harder to find if the source integer type has less significant bits.
|
||||
return false;
|
||||
|
|
|
@ -309,11 +309,12 @@ define double @ItoFtoF_u25_f32_f64(i25 %i) {
|
|||
ret double %r
|
||||
}
|
||||
|
||||
; UB on overflow guarantees that the input is small enough to fit in i32.
|
||||
|
||||
define double @FtoItoFtoF_f32_s32_f32_f64(float %f) {
|
||||
; CHECK-LABEL: @FtoItoFtoF_f32_s32_f32_f64(
|
||||
; CHECK-NEXT: [[I:%.*]] = fptosi float [[F:%.*]] to i32
|
||||
; CHECK-NEXT: [[X:%.*]] = sitofp i32 [[I]] to float
|
||||
; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to double
|
||||
; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[I]] to double
|
||||
; CHECK-NEXT: ret double [[R]]
|
||||
;
|
||||
%i = fptosi float %f to i32
|
||||
|
@ -333,7 +334,7 @@ define double @FtoItoFtoF_f32_u32_f32_f64_extra_uses(float %f) {
|
|||
; CHECK-NEXT: call void @use_i32(i32 [[I]])
|
||||
; CHECK-NEXT: [[X:%.*]] = uitofp i32 [[I]] to float
|
||||
; CHECK-NEXT: call void @use_f32(float [[X]])
|
||||
; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to double
|
||||
; CHECK-NEXT: [[R:%.*]] = uitofp i32 [[I]] to double
|
||||
; CHECK-NEXT: ret double [[R]]
|
||||
;
|
||||
%i = fptoui float %f to i32
|
||||
|
@ -349,8 +350,7 @@ define double @FtoItoFtoF_f32_u32_f32_f64_extra_uses(float %f) {
|
|||
define <3 x double> @FtoItoFtoF_v3f16_v3s32_v3f32_v3f64(<3 x half> %f) {
|
||||
; CHECK-LABEL: @FtoItoFtoF_v3f16_v3s32_v3f32_v3f64(
|
||||
; CHECK-NEXT: [[I:%.*]] = fptosi <3 x half> [[F:%.*]] to <3 x i32>
|
||||
; CHECK-NEXT: [[X:%.*]] = sitofp <3 x i32> [[I]] to <3 x float>
|
||||
; CHECK-NEXT: [[R:%.*]] = fpext <3 x float> [[X]] to <3 x double>
|
||||
; CHECK-NEXT: [[R:%.*]] = sitofp <3 x i32> [[I]] to <3 x double>
|
||||
; CHECK-NEXT: ret <3 x double> [[R]]
|
||||
;
|
||||
%i = fptosi <3 x half> %f to <3 x i32>
|
||||
|
@ -359,11 +359,12 @@ define <3 x double> @FtoItoFtoF_v3f16_v3s32_v3f32_v3f64(<3 x half> %f) {
|
|||
ret <3 x double> %r
|
||||
}
|
||||
|
||||
; Wider than double is ok.
|
||||
|
||||
define fp128 @FtoItoFtoF_f32_s64_f64_f128(float %f) {
|
||||
; CHECK-LABEL: @FtoItoFtoF_f32_s64_f64_f128(
|
||||
; CHECK-NEXT: [[I:%.*]] = fptosi float [[F:%.*]] to i64
|
||||
; CHECK-NEXT: [[X:%.*]] = sitofp i64 [[I]] to double
|
||||
; CHECK-NEXT: [[R:%.*]] = fpext double [[X]] to fp128
|
||||
; CHECK-NEXT: [[R:%.*]] = sitofp i64 [[I]] to fp128
|
||||
; CHECK-NEXT: ret fp128 [[R]]
|
||||
;
|
||||
%i = fptosi float %f to i64
|
||||
|
@ -372,11 +373,12 @@ define fp128 @FtoItoFtoF_f32_s64_f64_f128(float %f) {
|
|||
ret fp128 %r
|
||||
}
|
||||
|
||||
; Target-specific type is ok.
|
||||
|
||||
define x86_fp80 @FtoItoFtoF_f64_u54_f64_f80(double %f) {
|
||||
; CHECK-LABEL: @FtoItoFtoF_f64_u54_f64_f80(
|
||||
; CHECK-NEXT: [[I:%.*]] = fptoui double [[F:%.*]] to i54
|
||||
; CHECK-NEXT: [[X:%.*]] = uitofp i54 [[I]] to double
|
||||
; CHECK-NEXT: [[R:%.*]] = fpext double [[X]] to x86_fp80
|
||||
; CHECK-NEXT: [[R:%.*]] = uitofp i54 [[I]] to x86_fp80
|
||||
; CHECK-NEXT: ret x86_fp80 [[R]]
|
||||
;
|
||||
%i = fptoui double %f to i54
|
||||
|
@ -385,11 +387,12 @@ define x86_fp80 @FtoItoFtoF_f64_u54_f64_f80(double %f) {
|
|||
ret x86_fp80 %r
|
||||
}
|
||||
|
||||
; Weird target-specific type is ok (not possible to extend *from* that type).
|
||||
|
||||
define ppc_fp128 @FtoItoFtoF_f64_u54_f64_p128(double %f) {
|
||||
; CHECK-LABEL: @FtoItoFtoF_f64_u54_f64_p128(
|
||||
; CHECK-NEXT: [[I:%.*]] = fptoui double [[F:%.*]] to i54
|
||||
; CHECK-NEXT: [[X:%.*]] = uitofp i54 [[I]] to double
|
||||
; CHECK-NEXT: [[R:%.*]] = fpext double [[X]] to ppc_fp128
|
||||
; CHECK-NEXT: [[R:%.*]] = uitofp i54 [[I]] to ppc_fp128
|
||||
; CHECK-NEXT: ret ppc_fp128 [[R]]
|
||||
;
|
||||
%i = fptoui double %f to i54
|
||||
|
@ -398,11 +401,12 @@ define ppc_fp128 @FtoItoFtoF_f64_u54_f64_p128(double %f) {
|
|||
ret ppc_fp128 %r
|
||||
}
|
||||
|
||||
; Unsigned to signed is ok because signed int has smaller magnitude.
|
||||
|
||||
define double @FtoItoFtoF_f32_us32_f32_f64(float %f) {
|
||||
; CHECK-LABEL: @FtoItoFtoF_f32_us32_f32_f64(
|
||||
; CHECK-NEXT: [[I:%.*]] = fptoui float [[F:%.*]] to i32
|
||||
; CHECK-NEXT: [[X:%.*]] = sitofp i32 [[I]] to float
|
||||
; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to double
|
||||
; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[I]] to double
|
||||
; CHECK-NEXT: ret double [[R]]
|
||||
;
|
||||
%i = fptoui float %f to i32
|
||||
|
@ -411,6 +415,8 @@ define double @FtoItoFtoF_f32_us32_f32_f64(float %f) {
|
|||
ret double %r
|
||||
}
|
||||
|
||||
; Negative test: consider -1.0
|
||||
|
||||
define double @FtoItoFtoF_f32_su32_f32_f64(float %f) {
|
||||
; CHECK-LABEL: @FtoItoFtoF_f32_su32_f32_f64(
|
||||
; CHECK-NEXT: [[I:%.*]] = fptosi float [[F:%.*]] to i32
|
||||
|
|
Loading…
Reference in New Issue