[llvm] ValueTracking: teach implied-cond about samesign (PR #116614)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 18 05:38:24 PST 2024
https://github.com/artagnon created https://github.com/llvm/llvm-project/pull/116614
isImpliedCondition benefits little from the icmp samesign feature: the only routine that can use this information is isImpliedCondICmps when it is matching against signed predicates, since icmp samesign is already canonicalized with an unsigned predicate. Add this support.
>From de410817ea4cd3ed97c0cfae1b6747242c42efba Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Mon, 18 Nov 2024 12:13:48 +0000
Subject: [PATCH] ValueTracking: teach implied-cond about samesign
isImpliedCondition benefits little from the icmp samesign feature: the
only routine that can use this information is isImpliedCondICmps when it
is matching against signed predicates, since icmp samesign is already
canonicalized with an unsigned predicate. Add this support.
---
llvm/lib/Analysis/ValueTracking.cpp | 7 +-
.../implied-condition-samesign.ll | 215 ++++++++++++++++++
2 files changed, 220 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/Analysis/ValueTracking/implied-condition-samesign.ll
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c48068afc04816..a3285f943bf880 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9268,6 +9268,7 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
// case, invert the predicate to make it so.
CmpInst::Predicate LPred =
LHSIsTrue ? LHS->getPredicate() : LHS->getInversePredicate();
+ bool LHasSameSign = LHS->hasSameSign();
// We can have non-canonical operands, so try to normalize any common operand
// to L0/R0.
@@ -9321,7 +9322,8 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
// must be positive if X >= Y and no overflow".
// Take SGT as an example: L0:x > L1:y and C >= 0
// ==> R0:(x -nsw y) < R1:(-C) is false
- if ((LPred == ICmpInst::ICMP_SGT || LPred == ICmpInst::ICMP_SGE) &&
+ if ((ICmpInst::isSigned(LPred) || LHasSameSign) &&
+ (ICmpInst::isGE(LPred) || ICmpInst::isGT(LPred)) &&
match(R0, m_NSWSub(m_Specific(L0), m_Specific(L1)))) {
if (match(R1, m_NonPositive()) &&
isImpliedCondMatchingOperands(LPred, RPred) == false)
@@ -9330,7 +9332,8 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
// Take SLT as an example: L0:x < L1:y and C <= 0
// ==> R0:(x -nsw y) < R1:(-C) is true
- if ((LPred == ICmpInst::ICMP_SLT || LPred == ICmpInst::ICMP_SLE) &&
+ if ((ICmpInst::isSigned(LPred) || LHasSameSign) &&
+ (ICmpInst::isLE(LPred) || ICmpInst::isLT(LPred)) &&
match(R0, m_NSWSub(m_Specific(L0), m_Specific(L1)))) {
if (match(R1, m_NonNegative()) &&
isImpliedCondMatchingOperands(LPred, RPred) == true)
diff --git a/llvm/test/Analysis/ValueTracking/implied-condition-samesign.ll b/llvm/test/Analysis/ValueTracking/implied-condition-samesign.ll
new file mode 100644
index 00000000000000..51f90f8e8fe8f8
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/implied-condition-samesign.ll
@@ -0,0 +1,215 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=instsimplify -S %s | FileCheck %s
+
+define i32 @gt_sub_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @gt_sub_nsw(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[X]], [[Y]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], 1
+; CHECK-NEXT: ret i32 [[ADD]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ %cmp = icmp samesign ugt i32 %x, %y ; x>y ? abs (x-y+1): 0
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub nsw i32 %x, %y
+ %add = add nsw i32 %sub, 1
+ %neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
+ %abscond = icmp samesign ult i32 %sub, -1
+ %abs = select i1 %abscond, i32 %neg, i32 %add
+ ret i32 %abs
+
+cond.end: ; preds = %entry, %cond.true
+ ret i32 0
+}
+
+define i32 @ge_sub_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @ge_sub_nsw(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign uge i32 [[X]], [[Y]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], 1
+; CHECK-NEXT: ret i32 [[ADD]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ %cmp = icmp samesign uge i32 %x, %y ; x>=y ? abs (x-y+1): 0
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub nsw i32 %x, %y
+ %add = add nsw i32 %sub, 1
+ %neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
+ %abscond = icmp samesign ult i32 %sub, -1
+ %abs = select i1 %abscond, i32 %neg, i32 %add
+ ret i32 %abs
+
+cond.end: ; preds = %entry, %cond.true
+ ret i32 0
+}
+
+define i8 @gt_sub_no_nsw(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @gt_sub_no_nsw(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i8 [[X]], [[Y]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SUB]], 1
+; CHECK-NEXT: [[NEG:%.*]] = xor i8 [[SUB]], -1
+; CHECK-NEXT: [[ABSCOND:%.*]] = icmp samesign ult i8 [[SUB]], -1
+; CHECK-NEXT: [[ABS:%.*]] = select i1 [[ABSCOND]], i8 [[NEG]], i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[ABS]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: ret i8 0
+;
+entry:
+ %cmp = icmp samesign ugt i8 %x, %y
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub i8 %x, %y
+ %add = add i8 %sub, 1
+ %neg = xor i8 %sub, -1
+ %abscond = icmp samesign ult i8 %sub, -1
+ %abs = select i1 %abscond, i8 %neg, i8 %add
+ ret i8 %abs
+
+cond.end: ; preds = %entry, %cond.true
+ ret i8 0
+}
+
+define i8 @ugt_sub_nsw(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @ugt_sub_nsw(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], [[Y]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SUB]], 1
+; CHECK-NEXT: [[NEG:%.*]] = xor i8 [[SUB]], -1
+; CHECK-NEXT: [[ABSCOND:%.*]] = icmp ult i8 [[SUB]], -1
+; CHECK-NEXT: [[ABS:%.*]] = select i1 [[ABSCOND]], i8 [[NEG]], i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[ABS]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: ret i8 0
+;
+entry:
+ %cmp = icmp ugt i8 %x, %y
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub i8 %x, %y
+ %add = add i8 %sub, 1
+ %neg = xor i8 %sub, -1
+ %abscond = icmp ult i8 %sub, -1
+ %abs = select i1 %abscond, i8 %neg, i8 %add
+ ret i8 %abs
+
+cond.end: ; preds = %entry, %cond.true
+ ret i8 0
+}
+
+define i32 @lt_sub_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @lt_sub_nsw(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i32 [[X]], [[Y]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT: [[NEG:%.*]] = add nsw i32 [[SUB]], 1
+; CHECK-NEXT: ret i32 [[NEG]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ %cmp = icmp samesign ult i32 %x, %y ; x<y ? abs (x-y+1): 0
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub nsw i32 %x, %y
+ %add = add nsw i32 %sub, 1
+ %neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
+ %abscond = icmp samesign ugt i32 %sub, -1
+ %abs = select i1 %abscond, i32 %neg, i32 %add
+ ret i32 %abs
+
+cond.end: ; preds = %entry, %cond.true
+ ret i32 0
+}
+
+define i32 @le_sub_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @le_sub_nsw(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ule i32 [[X]], [[Y]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], 1
+; CHECK-NEXT: ret i32 [[ADD]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ %cmp = icmp samesign ule i32 %x, %y ; x<=y ? abs (x-y+1): 0
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub nsw i32 %x, %y
+ %add = add nsw i32 %sub, 1
+ %neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
+ %abscond = icmp samesign ugt i32 %sub, -1
+ %abs = select i1 %abscond, i32 %neg, i32 %add
+ ret i32 %abs
+
+cond.end: ; preds = %entry, %cond.true
+ ret i32 0
+}
+
+define i8 @gt_sub_nsw_wrong_const(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @gt_sub_nsw_wrong_const(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i8 [[X]], [[Y]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
+; CHECK: [[COND_TRUE]]:
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SUB]], 2
+; CHECK-NEXT: [[NEG:%.*]] = xor i8 [[SUB]], -1
+; CHECK-NEXT: [[ABSCOND:%.*]] = icmp samesign ult i8 [[SUB]], -2
+; CHECK-NEXT: [[ABS:%.*]] = select i1 [[ABSCOND]], i8 [[NEG]], i8 [[ADD]]
+; CHECK-NEXT: ret i8 [[ABS]]
+; CHECK: [[COND_END]]:
+; CHECK-NEXT: ret i8 0
+;
+entry:
+ %cmp = icmp samesign ugt i8 %x, %y ; x>y ? abs (x-y+2): 0
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub i8 %x, %y
+ %add = add i8 %sub, 2 ; x-y+2
+ %neg = xor i8 %sub, -1 ; y-x-1
+ %neg1 = sub i8 %neg, 1 ; y-x-2
+ %abscond = icmp samesign ult i8 %sub, -2
+ %abs = select i1 %abscond, i8 %neg, i8 %add
+ ret i8 %abs
+
+cond.end: ; preds = %entry, %cond.true
+ ret i8 0
+}
More information about the llvm-commits
mailing list