[llvm] [Float2Int] Fix miscompile with floats that can be converted to large ints (PR #85996)

via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 20 12:40:34 PDT 2024


https://github.com/AtariDreams created https://github.com/llvm/llvm-project/pull/85996

There is an issue with Float2Int whenever it has to deal with floats that evaluate to numbers that are over INT_MAX, but under UINT_MAX.

Simply, because the conversion method always assumes a signed integer, this works until the 32 bit number is actually a positive 32 bit number that would be interpreted as a negative number when evaluated as an integer, being put in an i32.

This was messing up the Float2Int conversions and causing miscompiles.

To fix this, tell the APSInt constructor if the value is positive or negative.

>From e520d39a5ddcdd056d45a76d35ddd154c12a22f2 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Wed, 20 Mar 2024 13:24:30 -0400
Subject: [PATCH 1/2] [Float2Int] Pre-commit test

---
 llvm/test/Transforms/Float2Int/basic.ll | 26 +++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/llvm/test/Transforms/Float2Int/basic.ll b/llvm/test/Transforms/Float2Int/basic.ll
index 2854a83179b7eb..b7ee3edc1d03dc 100644
--- a/llvm/test/Transforms/Float2Int/basic.ll
+++ b/llvm/test/Transforms/Float2Int/basic.ll
@@ -349,3 +349,29 @@ bogusBB:                                          ; preds = %bogusBB
   %tobool = fcmp une double %inc, 0.000000e+00
   br label %bogusBB
 }
+
+define i32 @pr71958() {
+; CHECK-LABEL: @pr71958(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[X_I:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[X_I]])
+; CHECK-NEXT:    store volatile i32 1, ptr [[X_I]], align 4
+; CHECK-NEXT:    [[X_I_0_X_I_0_X_0_X_0_X_0__I:%.*]] = load volatile i32, ptr [[X_I]], align 4
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp sgt i32 [[X_I_0_X_I_0_X_0_X_0_X_0__I]], 0
+; CHECK-NEXT:    [[TMP0:%.*]] = zext i1 [[CMP_I]] to i32
+; CHECK-NEXT:    [[MUL_I1:%.*]] = mul i32 [[TMP0]], 2147483647
+; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[X_I]])
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %x.i = alloca i32, align 4
+  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %x.i)
+  store volatile i32 1, ptr %x.i, align 4
+  %x.i.0.x.i.0.x.0.x.0.x.0..i = load volatile i32, ptr %x.i, align 4
+  %cmp.i = icmp sgt i32 %x.i.0.x.i.0.x.0.x.0.x.0..i, 0
+  %conv.i = uitofp i1 %cmp.i to double
+  %mul.i = fmul double %conv.i, 0x41EFFFFFFFE00000
+  %conv1.i = fptoui double %mul.i to i32
+  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %x.i)
+  ret i32 0
+}

>From ea1cb4f6c99b5d3baa3752f9f439a257521b26bb Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Wed, 20 Mar 2024 15:34:39 -0400
Subject: [PATCH 2/2] [Float2Int] Fix miscompile with floats that can be
 converted to large integers

There is an issue with Float2Int whenever it has to deal with floats that evaluate to numbers that are over INT_MAX, but under UINT_MAX.

Simply, because the conversion method always assumes a signed integer, this works until the 32 bit number is actually a positive 32 bit number that would be interpreted as a negative number when evaluated as an integer, being put in an i32.

This was messing up the Float2Int conversions and causing miscompiles.

To fix this, tell the APSInt constructor if the value is positive or negative.
---
 llvm/lib/Transforms/Scalar/Float2Int.cpp | 3 ++-
 llvm/test/Transforms/Float2Int/basic.ll  | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/Float2Int.cpp b/llvm/lib/Transforms/Scalar/Float2Int.cpp
index ccca8bcc1a56ac..dc72a65c618053 100644
--- a/llvm/lib/Transforms/Scalar/Float2Int.cpp
+++ b/llvm/lib/Transforms/Scalar/Float2Int.cpp
@@ -409,7 +409,8 @@ Value *Float2IntPass::convert(Instruction *I, Type *ToTy) {
     } else if (Instruction *VI = dyn_cast<Instruction>(V)) {
       NewOperands.push_back(convert(VI, ToTy));
     } else if (ConstantFP *CF = dyn_cast<ConstantFP>(V)) {
-      APSInt Val(ToTy->getPrimitiveSizeInBits(), /*isUnsigned=*/false);
+      APSInt Val(ToTy->getPrimitiveSizeInBits(),
+                 !CF->getValueAPF().isNegative());
       bool Exact;
       CF->getValueAPF().convertToInteger(Val,
                                          APFloat::rmNearestTiesToEven,
diff --git a/llvm/test/Transforms/Float2Int/basic.ll b/llvm/test/Transforms/Float2Int/basic.ll
index b7ee3edc1d03dc..a35c9cd2f3c3e0 100644
--- a/llvm/test/Transforms/Float2Int/basic.ll
+++ b/llvm/test/Transforms/Float2Int/basic.ll
@@ -359,7 +359,7 @@ define i32 @pr71958() {
 ; CHECK-NEXT:    [[X_I_0_X_I_0_X_0_X_0_X_0__I:%.*]] = load volatile i32, ptr [[X_I]], align 4
 ; CHECK-NEXT:    [[CMP_I:%.*]] = icmp sgt i32 [[X_I_0_X_I_0_X_0_X_0_X_0__I]], 0
 ; CHECK-NEXT:    [[TMP0:%.*]] = zext i1 [[CMP_I]] to i32
-; CHECK-NEXT:    [[MUL_I1:%.*]] = mul i32 [[TMP0]], 2147483647
+; CHECK-NEXT:    [[MUL_I1:%.*]] = mul i32 [[TMP0]], -1
 ; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[X_I]])
 ; CHECK-NEXT:    ret i32 0
 ;



More information about the llvm-commits mailing list