[llvm] [IndVarSimplify] Fix Masking Issue by Adding nsw/nuw Flags to Trunc Instruction (PR #150179)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 24 02:28:37 PDT 2025
https://github.com/buggfg updated https://github.com/llvm/llvm-project/pull/150179
>From c6a39d83ea7c90dd00bb1a6832816d5d69be02f7 Mon Sep 17 00:00:00 2001
From: buggfg <3171290993 at qq.com>
Date: Wed, 23 Jul 2025 15:20:40 +0800
Subject: [PATCH 1/2] [IndVarSimplify] Fix Masking Issue by Adding nsw/nuw
Flags to Trunc Instruction
---
llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 21 ++++++++++++++++++-
.../IndVarSimplify/X86/eliminate-trunc.ll | 8 +++----
.../Transforms/IndVarSimplify/lftr-pr41998.ll | 2 +-
llvm/test/Transforms/IndVarSimplify/lftr.ll | 2 +-
.../constraint-elimination-placement.ll | 3 +--
5 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 334c911191cb8..04a1f4831b8d8 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1049,9 +1049,28 @@ linearFunctionTestReplace(Loop *L, BasicBlock *ExitingBB,
if (Extended) {
bool Discard;
L->makeLoopInvariant(ExitCnt, Discard);
- } else
+ } else{
CmpIndVar = Builder.CreateTrunc(CmpIndVar, ExitCnt->getType(),
"lftr.wideiv");
+
+ // Set the correct wrap flag to avoid the masking issue.
+ Instruction *TruncInst = dyn_cast<Instruction>(CmpIndVar);
+
+ // The TruncatedIV is incrementing.
+ if (const SCEVAddRecExpr *TruncAR =
+ dyn_cast<SCEVAddRecExpr>(TruncatedIV)) {
+ // If TruncIV does not cause self-wrap, explicitly add the nsw and nuw
+ // flags to TruncInst.
+ if (TruncAR->hasNoSelfWrap()) {
+ TruncInst->setHasNoSignedWrap();
+ TruncInst->setHasNoUnsignedWrap();
+ } else if (TruncAR->hasNoSignedWrap()) {
+ TruncInst->setHasNoSignedWrap();
+ } else if (TruncAR->hasNoUnsignedWrap()) {
+ TruncInst->setHasNoUnsignedWrap();
+ }
+ }
+ }
}
LLVM_DEBUG(dbgs() << "INDVARS: Rewriting loop exit condition to:\n"
<< " LHS:" << *CmpIndVar << '\n'
diff --git a/llvm/test/Transforms/IndVarSimplify/X86/eliminate-trunc.ll b/llvm/test/Transforms/IndVarSimplify/X86/eliminate-trunc.ll
index 565ac5c8743d4..7e7a3f192f998 100644
--- a/llvm/test/Transforms/IndVarSimplify/X86/eliminate-trunc.ll
+++ b/llvm/test/Transforms/IndVarSimplify/X86/eliminate-trunc.ll
@@ -227,7 +227,7 @@ define void @test_01_unsigned(i32 %n) {
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
-; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
+; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc nuw nsw i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP0]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
@@ -255,7 +255,7 @@ define void @test_02_unsigned(i32 %n) {
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 4294967294, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
-; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
+; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc nuw nsw i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP0]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
@@ -304,7 +304,7 @@ define void @test_04_unsigned(i32 %n) {
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
-; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
+; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc nuw nsw i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP0]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
@@ -332,7 +332,7 @@ define void @test_05_unsigned(i32 %n) {
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
-; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
+; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc nuw nsw i64 [[IV_NEXT]] to i32
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP0]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
diff --git a/llvm/test/Transforms/IndVarSimplify/lftr-pr41998.ll b/llvm/test/Transforms/IndVarSimplify/lftr-pr41998.ll
index b7f4756b2757f..376ef1ac5ffac 100644
--- a/llvm/test/Transforms/IndVarSimplify/lftr-pr41998.ll
+++ b/llvm/test/Transforms/IndVarSimplify/lftr-pr41998.ll
@@ -13,7 +13,7 @@ define void @test_int(i32 %start, ptr %p) {
; CHECK-NEXT: [[I2:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I2_INC:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[I2_INC]] = add nuw nsw i32 [[I2]], 1
; CHECK-NEXT: store volatile i32 [[I2_INC]], ptr [[P:%.*]], align 4
-; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i32 [[I2_INC]] to i3
+; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc nuw nsw i32 [[I2_INC]] to i3
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i3 [[LFTR_WIDEIV]], [[TMP1]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[END:%.*]], label [[LOOP]]
; CHECK: end:
diff --git a/llvm/test/Transforms/IndVarSimplify/lftr.ll b/llvm/test/Transforms/IndVarSimplify/lftr.ll
index 5ee62ba357ab6..cfa4baa2d3b11 100644
--- a/llvm/test/Transforms/IndVarSimplify/lftr.ll
+++ b/llvm/test/Transforms/IndVarSimplify/lftr.ll
@@ -415,7 +415,7 @@ define void @wide_trip_count_test1(ptr %autoc,
; CHECK-NEXT: [[ADD3:%.*]] = fadd float [[TEMP2]], [[MUL]]
; CHECK-NEXT: store float [[ADD3]], ptr [[ARRAYIDX2]], align 4
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
-; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[INDVARS_IV_NEXT]] to i32
+; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc nuw nsw i64 [[INDVARS_IV_NEXT]] to i32
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[SUB]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
; CHECK: for.end.loopexit:
diff --git a/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll b/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll
index bbdbd95c6017a..ddd98f21c36a4 100644
--- a/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll
+++ b/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll
@@ -33,8 +33,7 @@ define i1 @test_order_1(ptr %this, ptr noalias %other, i1 %tobool9.not, i32 %cal
; CHECK-NEXT: br i1 [[CMP44]], label [[FOR_BODY45]], label [[FOR_COND]]
; CHECK: for.inc57:
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], 1
-; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[INDVARS_IV_NEXT]], 4294967295
-; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[TMP1]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV]], 0
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND41_PREHEADER_PREHEADER]], label [[FOR_COND41_PREHEADER]]
; CHECK: exit:
; CHECK-NEXT: ret i1 false
>From ac8981b9d1d7f053d324f22ac63c00720a5ab914 Mon Sep 17 00:00:00 2001
From: bernadate <3171290993 at qq.com>
Date: Thu, 24 Jul 2025 17:28:29 +0800
Subject: [PATCH 2/2] Update llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
Co-authored-by: Luke Lau <luke_lau at icloud.com>
---
llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 04a1f4831b8d8..bd04981f8b0d4 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1050,11 +1050,8 @@ linearFunctionTestReplace(Loop *L, BasicBlock *ExitingBB,
bool Discard;
L->makeLoopInvariant(ExitCnt, Discard);
} else{
- CmpIndVar = Builder.CreateTrunc(CmpIndVar, ExitCnt->getType(),
- "lftr.wideiv");
-
- // Set the correct wrap flag to avoid the masking issue.
- Instruction *TruncInst = dyn_cast<Instruction>(CmpIndVar);
+CmpIndVar = Builder.CreateTrunc(CmpIndVar, ExitCnt->getType(),
+"lftr.wideiv", TruncAR->hasNoUnsignedWrap(), TruncAR->hasSignedWrap());
// The TruncatedIV is incrementing.
if (const SCEVAddRecExpr *TruncAR =
More information about the llvm-commits
mailing list