[llvm] bfd5121 - [InstCombine] improve analysis of FP->int->FP to eliminate fpextend

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Sun May 17 06:07:20 PDT 2020


Author: Sanjay Patel
Date: 2020-05-17T09:06:57-04:00
New Revision: bfd512160fe091bdd45199e5db884a24cd9d5f59

URL: https://github.com/llvm/llvm-project/commit/bfd512160fe091bdd45199e5db884a24cd9d5f59
DIFF: https://github.com/llvm/llvm-project/commit/bfd512160fe091bdd45199e5db884a24cd9d5f59.diff

LOG: [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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
    llvm/test/Transforms/InstCombine/fpextend.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 16d94d6946b1..fa8e9e6d9f26 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -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;

diff  --git a/llvm/test/Transforms/InstCombine/fpextend.ll b/llvm/test/Transforms/InstCombine/fpextend.ll
index 1b6afd3216d7..9fe85e983fb7 100644
--- a/llvm/test/Transforms/InstCombine/fpextend.ll
+++ b/llvm/test/Transforms/InstCombine/fpextend.ll
@@ -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


        


More information about the llvm-commits mailing list