From 9100001cd08ccb9a4091200c2421ff2aee7829c6 Mon Sep 17 00:00:00 2001 From: Antonio Frighetto Date: Tue, 11 Nov 2025 10:28:12 +0100 Subject: [PATCH 1/2] [IndVarSimplify] Precommit tests for PR166649 (NFC) --- .../IndVarSimplify/floating-point-iv.ll | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll b/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll index b1ef50382c070..3ffd446bc3e98 100644 --- a/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll +++ b/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll @@ -417,3 +417,141 @@ loop: exit: ret void } + +; FIXME: These are miscompilation issues. +define void @test_fp_to_int_irrealizable_initval() { +; CHECK-LABEL: @test_fp_to_int_irrealizable_initval( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ 100000000, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: call void @opaque() +; CHECK-NEXT: [[IV_NEXT_INT]] = add nsw i32 [[IV_INT]], -17 +; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i32 [[IV_NEXT_INT]], 25 +; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: + %iv = phi float [ 1.000000e+08, %entry ], [ %iv.next, %loop ] + call void @opaque() + %iv.next = fadd float %iv, -1.700000e+01 + %cmp = fcmp ult float %iv.next, 2.500000e+01 + br i1 %cmp, label %exit, label %loop + +exit: + ret void +} + +define void @test_fp_to_int_irrealizable_exitval() { +; CHECK-LABEL: @test_fp_to_int_irrealizable_exitval( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ 25, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: call void @opaque() +; CHECK-NEXT: [[IV_NEXT_INT]] = add nuw nsw i32 [[IV_INT]], 17 +; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[IV_NEXT_INT]], 100000000 +; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: + %iv = phi float [ 2.500000e+01, %entry ], [ %iv.next, %loop ] + call void @opaque() + %iv.next = fadd float %iv, 1.700000e+01 + %cmp = fcmp ugt float %iv.next, 1.000000e+08 + br i1 %cmp, label %exit, label %loop + +exit: + ret void +} + +define void @test_fp_to_int_irrealizable_negative_exitval() { +; CHECK-LABEL: @test_fp_to_int_irrealizable_negative_exitval( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ -25, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: call void @opaque() +; CHECK-NEXT: [[IV_NEXT_INT]] = add nsw i32 [[IV_INT]], -17 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV_NEXT_INT]], -100000000 +; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: + %iv = phi float [ -2.500000e+01, %entry ], [ %iv.next, %loop ] + call void @opaque() + %iv.next = fadd float %iv, -1.700000e+01 + %cmp = fcmp ult float %iv.next, -1.000000e+08 + br i1 %cmp, label %exit, label %loop + +exit: + ret void +} + +define void @test_fp_to_int_irrealizable_exitval_pow_2_24() { +; CHECK-LABEL: @test_fp_to_int_irrealizable_exitval_pow_2_24( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: call void @opaque() +; CHECK-NEXT: [[IV_NEXT_INT]] = add nuw nsw i32 [[IV_INT]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[IV_NEXT_INT]], 16777216 +; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: + %iv = phi float [ 0.000000e+00, %entry ], [ %iv.next, %loop ] + call void @opaque() + %iv.next = fadd float %iv, 1.000000e+00 + %cmp = fcmp ugt float %iv.next, 0x4170000000000000 + br i1 %cmp, label %exit, label %loop + +exit: + ret void +} + +define void @test_fp_to_int_irrealizable_exitval_int64_min() { +; CHECK-LABEL: @test_fp_to_int_irrealizable_exitval_int64_min( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[IV:%.*]] = phi double [ 2.500000e+01, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] +; CHECK-NEXT: call void @opaque() +; CHECK-NEXT: [[IV_NEXT]] = fadd double [[IV]], 1.700000e+01 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ult double [[IV_NEXT]], 0xC3E0000000000000 +; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: + %iv = phi double [ 2.500000e+01, %entry ], [ %iv.next, %loop ] + call void @opaque() + %iv.next = fadd double %iv, 1.700000e+01 + %cmp = fcmp ult double %iv.next, 0xC3E0000000000000 + br i1 %cmp, label %exit, label %loop + +exit: + ret void +} + +declare void @opaque() From eaf3a91722fbb0f6598907c9dfa14ca632cc71c4 Mon Sep 17 00:00:00 2001 From: Antonio Frighetto Date: Tue, 11 Nov 2025 10:28:35 +0100 Subject: [PATCH 2/2] [IndVarSimplify] Ensure fp values can be represented as exact integers When transforming floating-point induction variables into integer ones, make sure we stay within the bounds of fp values that can be represented as integers without gaps, i.e., 2^24 and 2^53 for IEEE-754 single and double precision respectively (both on negative and positive side). Fixes: https://github.com/llvm/llvm-project/issues/166496. --- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 18 +++++++++++-- .../IndVarSimplify/floating-point-iv.ll | 25 +++++++++---------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 4ba4ba3850e58..eab1d4975ac96 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -196,6 +196,18 @@ static bool ConvertToSInt(const APFloat &APF, int64_t &IntVal) { return true; } +// Ensure we stay within the bounds of fp values that can be represented as +// integers without gaps, which are 2^24 and 2^53 for IEEE-754 single and double +// precision respectively (both on negative and positive side). +static bool isRepresentableAsExactInteger(ConstantFP *FPVal, int64_t IntVal) { + const auto &InitValueFltSema = FPVal->getValueAPF().getSemantics(); + if (!APFloat::isIEEELikeFP(InitValueFltSema)) + return false; + + return isUIntN(APFloat::semanticsPrecision(InitValueFltSema), + AbsoluteValue(IntVal)); +} + /// If the loop has floating induction variable then insert corresponding /// integer induction variable if possible. /// For example, @@ -212,7 +224,8 @@ bool IndVarSimplify::handleFloatingPointIV(Loop *L, PHINode *PN) { auto *InitValueVal = dyn_cast(PN->getIncomingValue(IncomingEdge)); int64_t InitValue; - if (!InitValueVal || !ConvertToSInt(InitValueVal->getValueAPF(), InitValue)) + if (!InitValueVal || !ConvertToSInt(InitValueVal->getValueAPF(), InitValue) || + !isRepresentableAsExactInteger(InitValueVal, InitValue)) return false; // Check IV increment. Reject this PN if increment operation is not @@ -262,7 +275,8 @@ bool IndVarSimplify::handleFloatingPointIV(Loop *L, PHINode *PN) { ConstantFP *ExitValueVal = dyn_cast(Compare->getOperand(1)); int64_t ExitValue; if (ExitValueVal == nullptr || - !ConvertToSInt(ExitValueVal->getValueAPF(), ExitValue)) + !ConvertToSInt(ExitValueVal->getValueAPF(), ExitValue) || + !isRepresentableAsExactInteger(ExitValueVal, ExitValue)) return false; // Find new predicate for integer comparison. diff --git a/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll b/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll index 3ffd446bc3e98..c4933678d0391 100644 --- a/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll +++ b/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll @@ -418,16 +418,15 @@ exit: ret void } -; FIXME: These are miscompilation issues. define void @test_fp_to_int_irrealizable_initval() { ; CHECK-LABEL: @test_fp_to_int_irrealizable_initval( ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ 100000000, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[IV:%.*]] = phi float [ 1.000000e+08, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: call void @opaque() -; CHECK-NEXT: [[IV_NEXT_INT]] = add nsw i32 [[IV_INT]], -17 -; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i32 [[IV_NEXT_INT]], 25 +; CHECK-NEXT: [[IV_NEXT]] = fadd float [[IV]], -1.700000e+01 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ult float [[IV_NEXT]], 2.500000e+01 ; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -451,10 +450,10 @@ define void @test_fp_to_int_irrealizable_exitval() { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ 25, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[IV:%.*]] = phi float [ 2.500000e+01, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: call void @opaque() -; CHECK-NEXT: [[IV_NEXT_INT]] = add nuw nsw i32 [[IV_INT]], 17 -; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[IV_NEXT_INT]], 100000000 +; CHECK-NEXT: [[IV_NEXT]] = fadd float [[IV]], 1.700000e+01 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ugt float [[IV_NEXT]], 1.000000e+08 ; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -478,10 +477,10 @@ define void @test_fp_to_int_irrealizable_negative_exitval() { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ -25, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[IV:%.*]] = phi float [ -2.500000e+01, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: call void @opaque() -; CHECK-NEXT: [[IV_NEXT_INT]] = add nsw i32 [[IV_INT]], -17 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV_NEXT_INT]], -100000000 +; CHECK-NEXT: [[IV_NEXT]] = fadd float [[IV]], -1.700000e+01 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ult float [[IV_NEXT]], -1.000000e+08 ; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -505,10 +504,10 @@ define void @test_fp_to_int_irrealizable_exitval_pow_2_24() { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[IV_INT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT_INT:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[IV:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] ; CHECK-NEXT: call void @opaque() -; CHECK-NEXT: [[IV_NEXT_INT]] = add nuw nsw i32 [[IV_INT]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[IV_NEXT_INT]], 16777216 +; CHECK-NEXT: [[IV_NEXT]] = fadd float [[IV]], 1.000000e+00 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ugt float [[IV_NEXT]], 0x4170000000000000 ; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: ; CHECK-NEXT: ret void