[llvm] Use range attribute to constant fold comparisons with constant values. (PR #84627)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 9 04:46:29 PST 2024


https://github.com/andjo403 created https://github.com/llvm/llvm-project/pull/84627

use the new range attribute from https://github.com/llvm/llvm-project/pull/84617



>From 129f34ed1ddcd16fe41b1d36d98c9fe8848e68b1 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 9 Mar 2024 12:50:42 +0100
Subject: [PATCH 1/2] Test for use range attribute to constant fold comparisons
 with constant values.

---
 .../test/Transforms/InstCombine/icmp-range.ll | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index 7af06e03fd4b2a..63cd8cf47e1a00 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -160,6 +160,40 @@ define i1 @test_two_ranges2(ptr nocapture readonly %arg1, ptr nocapture readonly
   ret i1 %rval
 }
 
+; Values' ranges do not overlap each other, so it can simplified to false.
+define i1 @test_two_argument_ranges(i32 range(i32 1, 6) %arg1, i32 range(i32 8, 16) %arg2) {
+; CHECK-LABEL: @test_two_argument_ranges(
+; CHECK-NEXT:    [[RVAL:%.*]] = icmp ult i32 [[ARG2:%.*]], [[ARG1:%.*]]
+; CHECK-NEXT:    ret i1 [[RVAL]]
+;
+  %rval = icmp ult i32 %arg2, %arg1
+  ret i1 %rval
+}
+
+; Values' ranges do not overlap each other, so it can simplified to false.
+define i1 @test_one_range_and_one_argument_range(ptr nocapture readonly %arg1, i32 range(i32 8, 16) %arg2) {
+; CHECK-LABEL: @test_one_range_and_one_argument_range(
+; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[ARG1:%.*]], align 4, !range [[RNG2]]
+; CHECK-NEXT:    [[RVAL:%.*]] = icmp ugt i32 [[VAL1]], [[ARG2:%.*]]
+; CHECK-NEXT:    ret i1 [[RVAL]]
+;
+  %val1 = load i32, ptr %arg1, !range !0
+  %rval = icmp ult i32 %arg2, %val1
+  ret i1 %rval
+}
+
+; Values' ranges do not overlap each other, so it can simplified to false.
+define i1 @test_one_argument_range_and_one_range(i32 range(i32 1, 6) %arg1, ptr nocapture readonly %arg2) {
+; CHECK-LABEL: @test_one_argument_range_and_one_range(
+; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[ARG2:%.*]], align 4, !range [[RNG5]]
+; CHECK-NEXT:    [[RVAL:%.*]] = icmp ult i32 [[VAL1]], [[ARG1:%.*]]
+; CHECK-NEXT:    ret i1 [[RVAL]]
+;
+  %val1 = load i32, ptr %arg2, !range !6
+  %rval = icmp ult i32 %val1, %arg1
+  ret i1 %rval
+}
+
 ; Values' ranges do not overlap each other, so it can simplified to true.
 define i1 @test_two_ranges3(ptr nocapture readonly %arg1, ptr nocapture readonly %arg2) {
 ; CHECK-LABEL: @test_two_ranges3(

>From 594074cfe88a04cacb0f268ca41fa403cc2c7cf9 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 9 Mar 2024 12:52:06 +0100
Subject: [PATCH 2/2] Use range attribute to constant fold comparisons with
 constant values.

---
 llvm/lib/Analysis/InstructionSimplify.cpp     | 38 ++++++++++---------
 .../test/Transforms/InstCombine/icmp-range.ll | 11 ++----
 2 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 201472a3f10c2e..6a709f29db1e33 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3729,6 +3729,19 @@ static Value *simplifyICmpWithIntrinsicOnLHS(CmpInst::Predicate Pred,
   }
 }
 
+/// Helper method to get range from metadata or attribute.
+static std::optional<ConstantRange> getRange(Value *V,
+                                             const InstrInfoQuery &IIQ) {
+  if (Instruction *I = dyn_cast<Instruction>(V))
+    if (MDNode *MD = IIQ.getMetadata(I, LLVMContext::MD_range))
+      return getConstantRangeFromMetadata(*MD);
+  if (const Argument *A = dyn_cast<Argument>(V))
+    if (A->hasAttribute(llvm::Attribute::Range))
+      return A->getAttribute(llvm::Attribute::Range).getRange();
+
+  return std::nullopt;
+}
+
 /// Given operands for an ICmpInst, see if we can fold the result.
 /// If not, this returns null.
 static Value *simplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
@@ -3776,23 +3789,14 @@ static Value *simplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
 
   // If both operands have range metadata, use the metadata
   // to simplify the comparison.
-  if (isa<Instruction>(RHS) && isa<Instruction>(LHS)) {
-    auto RHS_Instr = cast<Instruction>(RHS);
-    auto LHS_Instr = cast<Instruction>(LHS);
-
-    if (Q.IIQ.getMetadata(RHS_Instr, LLVMContext::MD_range) &&
-        Q.IIQ.getMetadata(LHS_Instr, LLVMContext::MD_range)) {
-      auto RHS_CR = getConstantRangeFromMetadata(
-          *RHS_Instr->getMetadata(LLVMContext::MD_range));
-      auto LHS_CR = getConstantRangeFromMetadata(
-          *LHS_Instr->getMetadata(LLVMContext::MD_range));
-
-      if (LHS_CR.icmp(Pred, RHS_CR))
-        return ConstantInt::getTrue(RHS->getContext());
-
-      if (LHS_CR.icmp(CmpInst::getInversePredicate(Pred), RHS_CR))
-        return ConstantInt::getFalse(RHS->getContext());
-    }
+  std::optional<ConstantRange> RhsCr = getRange(RHS, Q.IIQ);
+  std::optional<ConstantRange> LhsCr = getRange(LHS, Q.IIQ);
+  if (RhsCr && LhsCr) {
+    if (LhsCr->icmp(Pred, *RhsCr))
+      return ConstantInt::getTrue(RHS->getContext());
+
+    if (LhsCr->icmp(CmpInst::getInversePredicate(Pred), *RhsCr))
+      return ConstantInt::getFalse(RHS->getContext());
   }
 
   // Compare of cast, for example (zext X) != 0 -> X != 0
diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll
index 63cd8cf47e1a00..73da24f69c877a 100644
--- a/llvm/test/Transforms/InstCombine/icmp-range.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-range.ll
@@ -163,8 +163,7 @@ define i1 @test_two_ranges2(ptr nocapture readonly %arg1, ptr nocapture readonly
 ; Values' ranges do not overlap each other, so it can simplified to false.
 define i1 @test_two_argument_ranges(i32 range(i32 1, 6) %arg1, i32 range(i32 8, 16) %arg2) {
 ; CHECK-LABEL: @test_two_argument_ranges(
-; CHECK-NEXT:    [[RVAL:%.*]] = icmp ult i32 [[ARG2:%.*]], [[ARG1:%.*]]
-; CHECK-NEXT:    ret i1 [[RVAL]]
+; CHECK-NEXT:    ret i1 false
 ;
   %rval = icmp ult i32 %arg2, %arg1
   ret i1 %rval
@@ -173,9 +172,7 @@ define i1 @test_two_argument_ranges(i32 range(i32 1, 6) %arg1, i32 range(i32 8,
 ; Values' ranges do not overlap each other, so it can simplified to false.
 define i1 @test_one_range_and_one_argument_range(ptr nocapture readonly %arg1, i32 range(i32 8, 16) %arg2) {
 ; CHECK-LABEL: @test_one_range_and_one_argument_range(
-; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[ARG1:%.*]], align 4, !range [[RNG2]]
-; CHECK-NEXT:    [[RVAL:%.*]] = icmp ugt i32 [[VAL1]], [[ARG2:%.*]]
-; CHECK-NEXT:    ret i1 [[RVAL]]
+; CHECK-NEXT:    ret i1 false
 ;
   %val1 = load i32, ptr %arg1, !range !0
   %rval = icmp ult i32 %arg2, %val1
@@ -185,9 +182,7 @@ define i1 @test_one_range_and_one_argument_range(ptr nocapture readonly %arg1, i
 ; Values' ranges do not overlap each other, so it can simplified to false.
 define i1 @test_one_argument_range_and_one_range(i32 range(i32 1, 6) %arg1, ptr nocapture readonly %arg2) {
 ; CHECK-LABEL: @test_one_argument_range_and_one_range(
-; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[ARG2:%.*]], align 4, !range [[RNG5]]
-; CHECK-NEXT:    [[RVAL:%.*]] = icmp ult i32 [[VAL1]], [[ARG1:%.*]]
-; CHECK-NEXT:    ret i1 [[RVAL]]
+; CHECK-NEXT:    ret i1 false
 ;
   %val1 = load i32, ptr %arg2, !range !6
   %rval = icmp ult i32 %val1, %arg1



More information about the llvm-commits mailing list