[llvm] [LVI] Support no constant range of cast value in getEdgeValueLocal. (PR #157614)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 9 12:57:49 PDT 2025


https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/157614

>From 3b6e08d0809f7c44068c95df12d550e481c96c3c Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Tue, 9 Sep 2025 07:05:00 +0200
Subject: [PATCH 1/4] [LVI]  Add test of no constant range of cast and freeze
 value in getEdgeValueLocal. (NFC)

---
 .../CorrelatedValuePropagation/range.ll       | 144 ++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
index 8d787fd5586ef..e2303e4a347c3 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
@@ -1235,6 +1235,150 @@ define i1 @neg_icmp_eq_range_call() {
   ret i1 %cmp
 }
 
+define i16 @return_range_for_edge_value_zext(i8 %a) {
+; CHECK-LABEL: define range(i16 0, 256) i16 @return_range_for_edge_value_zext(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    br label %[[DISPATCH:.*]]
+; CHECK:       [[DISPATCH]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[A]], 98
+; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
+; CHECK:       [[TARGET]]:
+; CHECK-NEXT:    ret i16 [[B]]
+;
+entry:
+  %b = zext i8 %a to i16
+  br label %dispatch
+
+dispatch:
+  %cmp = icmp ult i8 %a, 98
+  br i1 %cmp, label %target, label %dispatch
+
+target:
+  ret i16 %b
+}
+
+define i16 @return_range_for_edge_value_sext(i8 %a) {
+; CHECK-LABEL: define range(i16 -128, 128) i16 @return_range_for_edge_value_sext(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    br label %[[DISPATCH:.*]]
+; CHECK:       [[DISPATCH]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[A]], 98
+; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
+; CHECK:       [[TARGET]]:
+; CHECK-NEXT:    ret i16 [[B]]
+;
+entry:
+  %b = sext i8 %a to i16
+  br label %dispatch
+
+dispatch:
+  %cmp = icmp ult i8 %a, 98
+  br i1 %cmp, label %target, label %dispatch
+
+target:
+  ret i16 %b
+}
+
+define i8 @return_range_for_edge_value_trunc(i16 %a) {
+; CHECK-LABEL: define i8 @return_range_for_edge_value_trunc(
+; CHECK-SAME: i16 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B:%.*]] = trunc i16 [[A]] to i8
+; CHECK-NEXT:    br label %[[DISPATCH:.*]]
+; CHECK:       [[DISPATCH]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[A]], 98
+; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
+; CHECK:       [[TARGET]]:
+; CHECK-NEXT:    ret i8 [[B]]
+;
+entry:
+  %b = trunc i16 %a to i8
+  br label %dispatch
+
+dispatch:
+  %cmp = icmp ult i16 %a, 98
+  br i1 %cmp, label %target, label %dispatch
+
+target:
+  ret i8 %b
+}
+
+define i8 @neg_return_range_for_edge_value_trunc(i16 %a) {
+; CHECK-LABEL: define i8 @neg_return_range_for_edge_value_trunc(
+; CHECK-SAME: i16 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B:%.*]] = trunc i16 [[A]] to i8
+; CHECK-NEXT:    br label %[[DISPATCH:.*]]
+; CHECK:       [[DISPATCH]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[A]], 200
+; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
+; CHECK:       [[TARGET]]:
+; CHECK-NEXT:    ret i8 [[B]]
+;
+entry:
+  %b = trunc i16 %a to i8
+  br label %dispatch
+
+dispatch:
+  %cmp = icmp ugt i16 %a, 200
+  br i1 %cmp, label %target, label %dispatch
+
+target:
+  ret i8 %b
+}
+
+define i8 @return_range_for_edge_value_trunc_nuw(i16 %a) {
+; CHECK-LABEL: define i8 @return_range_for_edge_value_trunc_nuw(
+; CHECK-SAME: i16 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B:%.*]] = trunc nuw i16 [[A]] to i8
+; CHECK-NEXT:    br label %[[DISPATCH:.*]]
+; CHECK:       [[DISPATCH]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[A]], 200
+; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
+; CHECK:       [[TARGET]]:
+; CHECK-NEXT:    ret i8 [[B]]
+;
+entry:
+  %b = trunc nuw i16 %a to i8
+  br label %dispatch
+
+dispatch:
+  %cmp = icmp ugt i16 %a, 200
+  br i1 %cmp, label %target, label %dispatch
+
+target:
+  ret i8 %b
+}
+
+define i8 @return_range_for_edge_value_freeze(i8 %a) {
+; CHECK-LABEL: define i8 @return_range_for_edge_value_freeze(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B:%.*]] = freeze i8 [[A]]
+; CHECK-NEXT:    br label %[[DISPATCH:.*]]
+; CHECK:       [[DISPATCH]]:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[A]], 98
+; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
+; CHECK:       [[TARGET]]:
+; CHECK-NEXT:    ret i8 [[B]]
+;
+entry:
+  %b = freeze i8 %a
+  br label %dispatch
+
+dispatch:
+  %cmp = icmp ult i8 %a, 98
+  br i1 %cmp, label %target, label %dispatch
+
+target:
+  ret i8 %b
+}
+
 declare i16 @llvm.ctlz.i16(i16, i1)
 declare i16 @llvm.cttz.i16(i16, i1)
 declare i16 @llvm.ctpop.i16(i16)

>From 7cce3e7c1e2eca2892c54c5feb8298d6a9686e64 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Tue, 9 Sep 2025 07:15:13 +0200
Subject: [PATCH 2/4] [LVI]  Support no constant range of cast and freeze value
 in getEdgeValueLocal.

---
 llvm/lib/Analysis/LazyValueInfo.cpp            | 18 ++++++++++++++++++
 .../CorrelatedValuePropagation/range.ll        | 10 +++++-----
 .../JumpThreading/branch-debug-info2.ll        |  2 +-
 3 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index c7b0ca97a8e43..84241be2c8816 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1493,6 +1493,24 @@ LazyValueInfoImpl::getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,
             //   br %Condition, label %then, label %else
             APInt ConditionVal(1, isTrueDest ? 1 : 0);
             Result = constantFoldUser(Usr, Condition, ConditionVal, DL);
+          } else if (isa<TruncInst, ZExtInst, SExtInst, FreezeInst>(Usr)) {
+            ValueLatticeElement OpLatticeVal =
+                *getValueFromCondition(Usr->getOperand(0), Condition,
+                                       isTrueDest, /*UseBlockValue*/ false);
+
+            if (isa<FreezeInst>(Usr) || !OpLatticeVal.isConstantRange())
+              return OpLatticeVal;
+
+            const unsigned ResultBitWidth =
+                Usr->getType()->getScalarSizeInBits();
+            if (auto *Trunc = dyn_cast<TruncInst>(Usr))
+              return ValueLatticeElement::getRange(
+                  OpLatticeVal.getConstantRange().truncate(
+                      ResultBitWidth, Trunc->getNoWrapKind()));
+
+            return ValueLatticeElement::getRange(
+                OpLatticeVal.getConstantRange().castOp(
+                    cast<CastInst>(Usr)->getOpcode(), ResultBitWidth));
           } else {
             // If one of Val's operand has an inferred value, we may be able to
             // infer the value of Val.
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
index e2303e4a347c3..fd6722cfc1671 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
@@ -1236,7 +1236,7 @@ define i1 @neg_icmp_eq_range_call() {
 }
 
 define i16 @return_range_for_edge_value_zext(i8 %a) {
-; CHECK-LABEL: define range(i16 0, 256) i16 @return_range_for_edge_value_zext(
+; CHECK-LABEL: define range(i16 0, 98) i16 @return_range_for_edge_value_zext(
 ; CHECK-SAME: i8 [[A:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[B:%.*]] = zext i8 [[A]] to i16
@@ -1260,7 +1260,7 @@ target:
 }
 
 define i16 @return_range_for_edge_value_sext(i8 %a) {
-; CHECK-LABEL: define range(i16 -128, 128) i16 @return_range_for_edge_value_sext(
+; CHECK-LABEL: define range(i16 0, 98) i16 @return_range_for_edge_value_sext(
 ; CHECK-SAME: i8 [[A:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[B:%.*]] = sext i8 [[A]] to i16
@@ -1284,7 +1284,7 @@ target:
 }
 
 define i8 @return_range_for_edge_value_trunc(i16 %a) {
-; CHECK-LABEL: define i8 @return_range_for_edge_value_trunc(
+; CHECK-LABEL: define range(i8 0, 98) i8 @return_range_for_edge_value_trunc(
 ; CHECK-SAME: i16 [[A:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[B:%.*]] = trunc i16 [[A]] to i8
@@ -1332,7 +1332,7 @@ target:
 }
 
 define i8 @return_range_for_edge_value_trunc_nuw(i16 %a) {
-; CHECK-LABEL: define i8 @return_range_for_edge_value_trunc_nuw(
+; CHECK-LABEL: define range(i8 -55, 0) i8 @return_range_for_edge_value_trunc_nuw(
 ; CHECK-SAME: i16 [[A:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[B:%.*]] = trunc nuw i16 [[A]] to i8
@@ -1356,7 +1356,7 @@ target:
 }
 
 define i8 @return_range_for_edge_value_freeze(i8 %a) {
-; CHECK-LABEL: define i8 @return_range_for_edge_value_freeze(
+; CHECK-LABEL: define range(i8 0, 98) i8 @return_range_for_edge_value_freeze(
 ; CHECK-SAME: i8 [[A:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[B:%.*]] = freeze i8 [[A]]
diff --git a/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll b/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll
index 2bfa492832def..485b3bba06144 100644
--- a/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll
+++ b/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll
@@ -19,7 +19,7 @@ if.end.i60:                                       ; preds = %shadow_to_ptr.exit
 ; Jump threading is going to fold the select in to the branch. Ensure debug
 ; info is not lost, and is merged from the select and the branch.
 ; CHECK-NOT: br i1 %cmp3.i, label %for.inc, label %ptr_to_shadow.exit
-; CHECK: br i1 %cmp3.i, label %for.inc, label %ptr_to_shadow.exit, !dbg [[DBG:![0-9]+]]
+; CHECK: br i1 %cmp3.i, label %for.inc, label %if.end22, !dbg [[DBG:![0-9]+]]
 ; CHECK: [[DBG]] = !DILocation(line: 9, column: 1, scope: !{{.*}})
 
   br label %ptr_to_shadow.exit, !dbg !17

>From d75a408a7a9cdc524fecd8f62d7d3fe325201433 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Tue, 9 Sep 2025 19:37:31 +0200
Subject: [PATCH 3/4] fixup! [LVI]  Support no constant range of cast and
 freeze value in getEdgeValueLocal.

---
 llvm/lib/Analysis/LazyValueInfo.cpp           |  4 ++--
 .../CorrelatedValuePropagation/range.ll       | 24 -------------------
 2 files changed, 2 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 84241be2c8816..90bae77bcf703 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1493,12 +1493,12 @@ LazyValueInfoImpl::getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,
             //   br %Condition, label %then, label %else
             APInt ConditionVal(1, isTrueDest ? 1 : 0);
             Result = constantFoldUser(Usr, Condition, ConditionVal, DL);
-          } else if (isa<TruncInst, ZExtInst, SExtInst, FreezeInst>(Usr)) {
+          } else if (isa<TruncInst, ZExtInst, SExtInst>(Usr)) {
             ValueLatticeElement OpLatticeVal =
                 *getValueFromCondition(Usr->getOperand(0), Condition,
                                        isTrueDest, /*UseBlockValue*/ false);
 
-            if (isa<FreezeInst>(Usr) || !OpLatticeVal.isConstantRange())
+            if (!OpLatticeVal.isConstantRange())
               return OpLatticeVal;
 
             const unsigned ResultBitWidth =
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
index fd6722cfc1671..cb03161ac2797 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
@@ -1355,30 +1355,6 @@ target:
   ret i8 %b
 }
 
-define i8 @return_range_for_edge_value_freeze(i8 %a) {
-; CHECK-LABEL: define range(i8 0, 98) i8 @return_range_for_edge_value_freeze(
-; CHECK-SAME: i8 [[A:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[B:%.*]] = freeze i8 [[A]]
-; CHECK-NEXT:    br label %[[DISPATCH:.*]]
-; CHECK:       [[DISPATCH]]:
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[A]], 98
-; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
-; CHECK:       [[TARGET]]:
-; CHECK-NEXT:    ret i8 [[B]]
-;
-entry:
-  %b = freeze i8 %a
-  br label %dispatch
-
-dispatch:
-  %cmp = icmp ult i8 %a, 98
-  br i1 %cmp, label %target, label %dispatch
-
-target:
-  ret i8 %b
-}
-
 declare i16 @llvm.ctlz.i16(i16, i1)
 declare i16 @llvm.cttz.i16(i16, i1)
 declare i16 @llvm.ctpop.i16(i16)

>From 46b35568aa2cf26708b6579418c601830e20ea41 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Tue, 9 Sep 2025 21:57:34 +0200
Subject: [PATCH 4/4] fixup! fixup! [LVI]  Support no constant range of cast
 and freeze value in getEdgeValueLocal.

---
 llvm/test/Transforms/CorrelatedValuePropagation/range.ll | 6 +++---
 llvm/test/Transforms/JumpThreading/branch-debug-info2.ll | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
index cb03161ac2797..860caf2624d42 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
@@ -1260,13 +1260,13 @@ target:
 }
 
 define i16 @return_range_for_edge_value_sext(i8 %a) {
-; CHECK-LABEL: define range(i16 0, 98) i16 @return_range_for_edge_value_sext(
+; CHECK-LABEL: define range(i16 -55, 0) i16 @return_range_for_edge_value_sext(
 ; CHECK-SAME: i8 [[A:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[B:%.*]] = sext i8 [[A]] to i16
 ; CHECK-NEXT:    br label %[[DISPATCH:.*]]
 ; CHECK:       [[DISPATCH]]:
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[A]], 98
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[A]], -56
 ; CHECK-NEXT:    br i1 [[CMP]], label %[[TARGET:.*]], label %[[DISPATCH]]
 ; CHECK:       [[TARGET]]:
 ; CHECK-NEXT:    ret i16 [[B]]
@@ -1276,7 +1276,7 @@ entry:
   br label %dispatch
 
 dispatch:
-  %cmp = icmp ult i8 %a, 98
+  %cmp = icmp ugt i8 %a, -56
   br i1 %cmp, label %target, label %dispatch
 
 target:
diff --git a/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll b/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll
index 485b3bba06144..59b6ef51d670f 100644
--- a/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll
+++ b/llvm/test/Transforms/JumpThreading/branch-debug-info2.ll
@@ -18,7 +18,7 @@ if.end.i60:                                       ; preds = %shadow_to_ptr.exit
   %spec.select.i = select i1 %cmp3.i, i32 -1, i32 %conv7.i, !dbg !17
 ; Jump threading is going to fold the select in to the branch. Ensure debug
 ; info is not lost, and is merged from the select and the branch.
-; CHECK-NOT: br i1 %cmp3.i, label %for.inc, label %ptr_to_shadow.exit
+; CHECK-NOT: br i1 %cmp3.i, label %for.inc, label %if.end22
 ; CHECK: br i1 %cmp3.i, label %for.inc, label %if.end22, !dbg [[DBG:![0-9]+]]
 ; CHECK: [[DBG]] = !DILocation(line: 9, column: 1, scope: !{{.*}})
 



More information about the llvm-commits mailing list