[llvm] [ValueTracking] Support scalable vector splats of ConstantInt in isGuaranteedNotToBeUndefOrPoison. (PR #142894)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 5 14:09:21 PDT 2025


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/142894

>From 0a7708d3e60d79f5fad365e7fba2f404089d8ffc Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 4 Jun 2025 20:24:48 -0700
Subject: [PATCH 1/3] Pre-commit tests

---
 .../Transforms/InstCombine/select-and-or.ll   | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index b14186d737e98..e0ab907fb5779 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -104,6 +104,20 @@ define i1 @logical_or_implies(i32 %x) {
   ret i1 %res
 }
 
+; Safe to convert to or due to poison implication.
+define <vscale x 2 x i1> @logical_or_implies_scalablevec(<vscale x 2 x i32> %x) {
+; CHECK-LABEL: @logical_or_implies_scalablevec(
+; CHECK-NEXT:    [[C1:%.*]] = icmp eq <vscale x 2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    [[C2:%.*]] = icmp eq <vscale x 2 x i32> [[X]], splat (i32 42)
+; CHECK-NEXT:    [[RES:%.*]] = select <vscale x 2 x i1> [[C1]], <vscale x 2 x i1> splat (i1 true), <vscale x 2 x i1> [[C2]]
+; CHECK-NEXT:    ret <vscale x 2 x i1> [[RES]]
+;
+  %c1 = icmp eq <vscale x 2 x i32> %x, zeroinitializer
+  %c2 = icmp eq <vscale x 2 x i32> %x, splat (i32 42)
+  %res = select <vscale x 2 x i1> %c1, <vscale x 2 x i1> splat (i1 true), <vscale x 2 x i1> %c2
+  ret <vscale x 2 x i1> %res
+}
+
 ; Will fold after conversion to or.
 define i1 @logical_or_implies_folds(i32 %x) {
 ; CHECK-LABEL: @logical_or_implies_folds(
@@ -129,6 +143,20 @@ define i1 @logical_and_implies(i32 %x) {
   ret i1 %res
 }
 
+; Safe to convert to and due to poison implication.
+define <vscale x 2 x i1> @logical_and_implies_scalablevec(<vscale x 2 x i32> %x) {
+; CHECK-LABEL: @logical_and_implies_scalablevec(
+; CHECK-NEXT:    [[C1:%.*]] = icmp ne <vscale x 2 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    [[C2:%.*]] = icmp ne <vscale x 2 x i32> [[X]], splat (i32 42)
+; CHECK-NEXT:    [[RES:%.*]] = select <vscale x 2 x i1> [[C1]], <vscale x 2 x i1> [[C2]], <vscale x 2 x i1> zeroinitializer
+; CHECK-NEXT:    ret <vscale x 2 x i1> [[RES]]
+;
+  %c1 = icmp ne <vscale x 2 x i32> %x, zeroinitializer
+  %c2 = icmp ne <vscale x 2 x i32> %x, splat (i32 42)
+  %res = select <vscale x 2 x i1> %c1, <vscale x 2 x i1> %c2, <vscale x 2 x i1> zeroinitializer
+  ret <vscale x 2 x i1> %res
+}
+
 ; Will fold after conversion to and.
 define i1 @logical_and_implies_folds(i32 %x) {
 ; CHECK-LABEL: @logical_and_implies_folds(

>From 7a546dfb2f70c01c7cddc620dd7aec87e7c4a345 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 4 Jun 2025 20:34:01 -0700
Subject: [PATCH 2/3] [ValueTracking] Support scalable vector splats of
 ConstantInt in isGuaranteedNotToBeUndefOrPoison.

Scalable vectors use insertelt+shufflevector ConstantExpr to
represent a splat.
---
 llvm/lib/Analysis/ValueTracking.cpp           | 21 ++++++++++++-------
 .../Transforms/InstCombine/select-and-or.ll   |  4 ++--
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 0a460786d00ea..b32d206f927ed 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7579,16 +7579,23 @@ static bool isGuaranteedNotToBeUndefOrPoison(
     if (isa<UndefValue>(C))
       return !includesUndef(Kind);
 
-    if (isa<ConstantInt>(C) || isa<GlobalVariable>(C) || isa<ConstantFP>(V) ||
+    if (isa<ConstantInt>(C) || isa<GlobalVariable>(C) || isa<ConstantFP>(C) ||
         isa<ConstantPointerNull>(C) || isa<Function>(C))
       return true;
 
-    if (C->getType()->isVectorTy() && !isa<ConstantExpr>(C)) {
-      if (includesUndef(Kind) && C->containsUndefElement())
-        return false;
-      if (includesPoison(Kind) && C->containsPoisonElement())
-        return false;
-      return !C->containsConstantExpression();
+    if (C->getType()->isVectorTy()) {
+      if (isa<ConstantExpr>(C)) {
+        // Scalable vectors can use a ConstantExpr to build a splat.
+        if (Constant *SplatC = C->getSplatValue())
+          if (isa<ConstantInt>(SplatC))
+            return true;
+      } else {
+        if (includesUndef(Kind) && C->containsUndefElement())
+          return false;
+        if (includesPoison(Kind) && C->containsPoisonElement())
+          return false;
+        return !C->containsConstantExpression();
+      }
     }
   }
 
diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index e0ab907fb5779..453ca666a7477 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -109,7 +109,7 @@ define <vscale x 2 x i1> @logical_or_implies_scalablevec(<vscale x 2 x i32> %x)
 ; CHECK-LABEL: @logical_or_implies_scalablevec(
 ; CHECK-NEXT:    [[C1:%.*]] = icmp eq <vscale x 2 x i32> [[X:%.*]], zeroinitializer
 ; CHECK-NEXT:    [[C2:%.*]] = icmp eq <vscale x 2 x i32> [[X]], splat (i32 42)
-; CHECK-NEXT:    [[RES:%.*]] = select <vscale x 2 x i1> [[C1]], <vscale x 2 x i1> splat (i1 true), <vscale x 2 x i1> [[C2]]
+; CHECK-NEXT:    [[RES:%.*]] = or <vscale x 2 x i1> [[C1]], [[C2]]
 ; CHECK-NEXT:    ret <vscale x 2 x i1> [[RES]]
 ;
   %c1 = icmp eq <vscale x 2 x i32> %x, zeroinitializer
@@ -148,7 +148,7 @@ define <vscale x 2 x i1> @logical_and_implies_scalablevec(<vscale x 2 x i32> %x)
 ; CHECK-LABEL: @logical_and_implies_scalablevec(
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ne <vscale x 2 x i32> [[X:%.*]], zeroinitializer
 ; CHECK-NEXT:    [[C2:%.*]] = icmp ne <vscale x 2 x i32> [[X]], splat (i32 42)
-; CHECK-NEXT:    [[RES:%.*]] = select <vscale x 2 x i1> [[C1]], <vscale x 2 x i1> [[C2]], <vscale x 2 x i1> zeroinitializer
+; CHECK-NEXT:    [[RES:%.*]] = and <vscale x 2 x i1> [[C1]], [[C2]]
 ; CHECK-NEXT:    ret <vscale x 2 x i1> [[RES]]
 ;
   %c1 = icmp ne <vscale x 2 x i32> %x, zeroinitializer

>From fa4e6e0fe7016abfd58842a1a6d8a5a7eaab45a3 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Thu, 5 Jun 2025 13:52:19 -0700
Subject: [PATCH 3/3] fixup! Add ConstantFP too

---
 llvm/lib/Analysis/ValueTracking.cpp          | 2 +-
 llvm/test/Transforms/Attributor/nofpclass.ll | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b32d206f927ed..7df58fa55d0d7 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7587,7 +7587,7 @@ static bool isGuaranteedNotToBeUndefOrPoison(
       if (isa<ConstantExpr>(C)) {
         // Scalable vectors can use a ConstantExpr to build a splat.
         if (Constant *SplatC = C->getSplatValue())
-          if (isa<ConstantInt>(SplatC))
+          if (isa<ConstantInt>(SplatC) || isa<ConstantFP>(SplatC))
             return true;
       } else {
         if (includesUndef(Kind) && C->containsUndefElement())
diff --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
index cfc7877383881..6d720ca9d0eac 100644
--- a/llvm/test/Transforms/Attributor/nofpclass.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -2665,7 +2665,7 @@ define [4 x float] @constant_aggregate_zero() {
 
 define <vscale x 4 x float> @scalable_splat_pnorm() {
 ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define <vscale x 4 x float> @scalable_splat_pnorm
+; CHECK-LABEL: define noundef <vscale x 4 x float> @scalable_splat_pnorm
 ; CHECK-SAME: () #[[ATTR3]] {
 ; CHECK-NEXT:    ret <vscale x 4 x float> splat (float 1.000000e+00)
 ;



More information about the llvm-commits mailing list