[llvm] Match range check pattern with SExt (PR #118910)
Matthias Braun via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 5 18:01:45 PST 2024
https://github.com/MatzeB created https://github.com/llvm/llvm-project/pull/118910
= Background
LLVM optimizes range check patterns like the following:
```
%nn = and i32 %n, 2147483647 ; %nn is non-negative
%a = icmp sge i32 %x, 0
%b = icmp slt i32 %x, %nn
%c = and i1 %a, %b
```
to a single unsigned comparison:
```
%nn = and i32 %n, 2147483647
%c = icmp ult i32 %x, %nn
```
= Extended Pattern
This adds support for an extended version of this pattern where the
upper range is compared with an `sext` value. Example:
```
%nn = and i64 %n, 2147483647
%x_sext = sext i32 %x to i64
%a = icmp sge i32 %x, 0
%b = icmp slt i64 %x_sext, %nn
%c = and i1 %a, %b
```
is now optimized to:
```
%nn = and i64 %n, 2147483647
%x_sext = sext i32 %x to i64
%c = icmp ugt i64 %nn, %x_sext
```
In Alive2: https://alive2.llvm.org/ce/z/Ff7KJ_
>From 689547b2df9826bc7df694a9a15cb1e8eb921a2b Mon Sep 17 00:00:00 2001
From: Matthias Braun <matze at braunis.de>
Date: Thu, 5 Dec 2024 17:49:07 -0800
Subject: [PATCH] Match range check pattern with SExt
= Background
LLVM optimizes range check patterns like the following:
```
%nn = and i32 %n, 2147483647 ; %nn is non-negative
%a = icmp sge i32 %x, 0
%b = icmp slt i32 %x, %nn
%c = and i1 %a, %b
```
to a single unsigned comparison:
```
%nn = and i32 %n, 2147483647
%c = icmp ult i32 %x, %nn
```
= Extended Pattern
This adds support for an extended version of this pattern where the
upper range is compared with an `sext` value. Example:
```
%nn = and i64 %n, 2147483647
%x_sext = sext i32 %x to i64
%a = icmp sge i32 %x, 0
%b = icmp slt i64 %x_sext, %nn
%c = and i1 %a, %b
```
is now optimized to:
```
%nn = and i64 %n, 2147483647
%x_sext = sext i32 %x to i64
%c = icmp ugt i64 %nn, %x_sext
```
In Alive2: https://alive2.llvm.org/ce/z/Ff7KJ_
---
.../InstCombine/InstCombineAndOrXor.cpp | 21 ++-
.../Transforms/InstCombine/range-check.ll | 120 ++++++++++++++++++
2 files changed, 137 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index b4033fc2a418a1..dddab2efd80fb9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -695,14 +695,27 @@ Value *InstCombinerImpl::simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1,
Cmp1->getPredicate());
Value *Input = Cmp0->getOperand(0);
+ Value *Cmp1Op0 = Cmp1->getOperand(0);
+ Value *Cmp1Op1 = Cmp1->getOperand(1);
Value *RangeEnd;
- if (Cmp1->getOperand(0) == Input) {
+ if (Cmp1Op0 == Input) {
// For the upper range compare we have: icmp x, n
- RangeEnd = Cmp1->getOperand(1);
- } else if (Cmp1->getOperand(1) == Input) {
+ RangeEnd = Cmp1Op1;
+ } else if (isa<SExtInst>(Cmp1Op0) &&
+ cast<SExtInst>(Cmp1Op0)->getOperand(0) == Input) {
+ // For the upper range compare we have: icmp (sext x), n
+ Input = Cmp1Op0;
+ RangeEnd = Cmp1Op1;
+ } else if (Cmp1Op1 == Input) {
// For the upper range compare we have: icmp n, x
- RangeEnd = Cmp1->getOperand(0);
Pred1 = ICmpInst::getSwappedPredicate(Pred1);
+ RangeEnd = Cmp1Op0;
+ } else if (isa<SExtInst>(Cmp1Op1) &&
+ cast<SExtInst>(Cmp1Op1)->getOperand(0) == Input) {
+ // For the upper range compare we have: icmp n, (sext x)
+ Pred1 = ICmpInst::getSwappedPredicate(Pred1);
+ Input = Cmp1Op1;
+ RangeEnd = Cmp1Op0;
} else {
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/range-check.ll b/llvm/test/Transforms/InstCombine/range-check.ll
index ebb310fb7c1f8f..161fc2d7fdc1dc 100644
--- a/llvm/test/Transforms/InstCombine/range-check.ll
+++ b/llvm/test/Transforms/InstCombine/range-check.ll
@@ -32,6 +32,21 @@ define i1 @test_and1_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_and1_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_and1_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp ugt i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp sge i32 %x, 0
+ %b = icmp slt i64 %x_sext, %nn
+ %c = and i1 %a, %b
+ ret i1 %c
+}
+
define i1 @test_and2(i32 %x, i32 %n) {
; CHECK-LABEL: @test_and2(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
@@ -60,6 +75,21 @@ define i1 @test_and2_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_and2_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_and2_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp uge i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp sgt i32 %x, -1
+ %b = icmp sle i64 %x_sext, %nn
+ %c = and i1 %a, %b
+ ret i1 %c
+}
+
define i1 @test_and3(i32 %x, i32 %n) {
; CHECK-LABEL: @test_and3(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
@@ -86,6 +116,21 @@ define i1 @test_and3_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_and3_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_and3_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp ugt i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp sgt i64 %nn, %x_sext
+ %b = icmp sge i32 %x, 0
+ %c = and i1 %a, %b
+ ret i1 %c
+}
+
define i1 @test_and4(i32 %x, i32 %n) {
; CHECK-LABEL: @test_and4(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
@@ -112,6 +157,21 @@ define i1 @test_and4_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_and4_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_and4_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp uge i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp sge i64 %nn, %x_sext
+ %b = icmp sge i32 %x, 0
+ %c = and i1 %a, %b
+ ret i1 %c
+}
+
define i1 @test_or1(i32 %x, i32 %n) {
; CHECK-LABEL: @test_or1(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
@@ -140,6 +200,21 @@ define i1 @test_or1_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_or1_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_or1_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp ule i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp slt i32 %x, 0
+ %b = icmp sge i64 %x_sext, %nn
+ %c = or i1 %a, %b
+ ret i1 %c
+}
+
define i1 @test_or2(i32 %x, i32 %n) {
; CHECK-LABEL: @test_or2(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
@@ -168,6 +243,21 @@ define i1 @test_or2_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_or2_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_or2_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp sle i32 %x, -1
+ %b = icmp sgt i64 %x_sext, %nn
+ %c = or i1 %a, %b
+ ret i1 %c
+}
+
define i1 @test_or3(i32 %x, i32 %n) {
; CHECK-LABEL: @test_or3(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
@@ -194,6 +284,21 @@ define i1 @test_or3_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_or3_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_or3_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp ule i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp sle i64 %nn, %x_sext
+ %b = icmp slt i32 %x, 0
+ %c = or i1 %a, %b
+ ret i1 %c
+}
+
define i1 @test_or4(i32 %x, i32 %n) {
; CHECK-LABEL: @test_or4(
; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
@@ -220,6 +325,21 @@ define i1 @test_or4_logical(i32 %x, i32 %n) {
ret i1 %c
}
+define i1 @test_or4_sext(i32 %x, i64 %n) {
+; CHECK-LABEL: @test_or4_sext(
+; CHECK-NEXT: [[NN:%.*]] = and i64 [[N:%.*]], 2147483647
+; CHECK-NEXT: [[X_SEXT:%.*]] = sext i32 [[X:%.*]] to i64
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[NN]], [[X_SEXT]]
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %nn = and i64 %n, 2147483647
+ %x_sext = sext i32 %x to i64
+ %a = icmp slt i64 %nn, %x_sext
+ %b = icmp slt i32 %x, 0
+ %c = or i1 %a, %b
+ ret i1 %c
+}
+
; Negative tests
define i1 @negative1(i32 %x, i32 %n) {
More information about the llvm-commits
mailing list