[llvm] ConstraintElim: teach fact-transfer about samesign (PR #115893)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 15 01:14:14 PST 2024


https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/115893

>From 19dc9eefa598120cfd10c80cc08ce9801f52f01c Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Tue, 12 Nov 2024 12:39:37 +0000
Subject: [PATCH 1/2] ConstraintElim: teach fact-transfer about samesign

When the samesign flag is present on an icmp, we can transfer all the
facts on the unsigned system to the signed system, and vice-versa: we do
this by specializing transferToOtherSystem when samesign is present.
Supporting samesign in ConstraintElimination has necessitated adding
extra information to ConditionFacts, as the information would otherwise
be lost.
---
 .../Scalar/ConstraintElimination.cpp          |  63 ++--
 .../transfer-samesign-facts.ll                | 305 ++++++++++++++++++
 2 files changed, 346 insertions(+), 22 deletions(-)
 create mode 100644 llvm/test/Transforms/ConstraintElimination/transfer-samesign-facts.ll

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 7c06e0c757e1cc..3a040ff3f60c0a 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -88,14 +88,15 @@ static Instruction *getContextInstForUse(Use &U) {
 namespace {
 /// Struct to express a condition of the form %Op0 Pred %Op1.
 struct ConditionTy {
-  CmpInst::Predicate Pred;
-  Value *Op0;
-  Value *Op1;
-
-  ConditionTy()
-      : Pred(CmpInst::BAD_ICMP_PREDICATE), Op0(nullptr), Op1(nullptr) {}
-  ConditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)
-      : Pred(Pred), Op0(Op0), Op1(Op1) {}
+  CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;
+  bool HasSameSign = false;
+  Value *Op0 = nullptr;
+  Value *Op1 = nullptr;
+
+  ConditionTy() = default;
+  ConditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
+              bool HasSameSign = false)
+      : Pred(Pred), HasSameSign(HasSameSign), Op0(Op0), Op1(Op1) {}
 };
 
 /// Represents either
@@ -132,19 +133,25 @@ struct FactOrCheck {
         Ty(Ty) {}
 
   FactOrCheck(DomTreeNode *DTN, Use *U)
-      : U(U), DoesHold(CmpInst::BAD_ICMP_PREDICATE, nullptr, nullptr),
-        NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
+      : U(U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
         Ty(EntryTy::UseCheck) {}
 
   FactOrCheck(DomTreeNode *DTN, CmpInst::Predicate Pred, Value *Op0, Value *Op1,
-              ConditionTy Precond = ConditionTy())
-      : Cond(Pred, Op0, Op1), DoesHold(Precond), NumIn(DTN->getDFSNumIn()),
-        NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
+              ConditionTy Precond = {}, bool HasSameSign = false)
+      : Cond(Pred, Op0, Op1, HasSameSign), DoesHold(Precond),
+        NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
+        Ty(EntryTy::ConditionFact) {}
 
   static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst::Predicate Pred,
                                       Value *Op0, Value *Op1,
-                                      ConditionTy Precond = ConditionTy()) {
-    return FactOrCheck(DTN, Pred, Op0, Op1, Precond);
+                                      ConditionTy Precond = {}) {
+    return FactOrCheck(DTN, Pred, Op0, Op1, Precond, false);
+  }
+
+  static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst::Predicate Pred,
+                                      Value *Op0, Value *Op1,
+                                      bool HasSameSign) {
+    return FactOrCheck(DTN, Pred, Op0, Op1, {}, HasSameSign);
   }
 
   static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst) {
@@ -1077,8 +1084,9 @@ void State::addInfoFor(BasicBlock &BB) {
       if (GuaranteedToExecute) {
         // The assume is guaranteed to execute when BB is entered, hence Cond
         // holds on entry to BB.
+        bool HasSameSign = cast<ICmpInst>(I.getOperand(0))->hasSameSign();
         WorkList.emplace_back(FactOrCheck::getConditionFact(
-            DT.getNode(I.getParent()), Pred, A, B));
+            DT.getNode(I.getParent()), Pred, A, B, HasSameSign));
       } else {
         WorkList.emplace_back(
             FactOrCheck::getInstFact(DT.getNode(I.getParent()), &I));
@@ -1160,7 +1168,7 @@ void State::addInfoFor(BasicBlock &BB) {
               DT.getNode(Successor),
               IsOr ? CmpInst::getInversePredicate(Cmp->getPredicate())
                    : Cmp->getPredicate(),
-              Cmp->getOperand(0), Cmp->getOperand(1)));
+              Cmp->getOperand(0), Cmp->getOperand(1), Cmp->hasSameSign()));
           continue;
         }
         if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {
@@ -1184,12 +1192,12 @@ void State::addInfoFor(BasicBlock &BB) {
   if (canAddSuccessor(BB, Br->getSuccessor(0)))
     WorkList.emplace_back(FactOrCheck::getConditionFact(
         DT.getNode(Br->getSuccessor(0)), CmpI->getPredicate(),
-        CmpI->getOperand(0), CmpI->getOperand(1)));
+        CmpI->getOperand(0), CmpI->getOperand(1), CmpI->hasSameSign()));
   if (canAddSuccessor(BB, Br->getSuccessor(1)))
     WorkList.emplace_back(FactOrCheck::getConditionFact(
         DT.getNode(Br->getSuccessor(1)),
         CmpInst::getInversePredicate(CmpI->getPredicate()), CmpI->getOperand(0),
-        CmpI->getOperand(1)));
+        CmpI->getOperand(1), CmpI->hasSameSign()));
 }
 
 #ifndef NDEBUG
@@ -1780,7 +1788,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
       continue;
     }
 
-    auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
+    auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B,
+                       bool HasSameSign = false) {
       LLVM_DEBUG(dbgs() << "Processing fact to add to the system: ";
                  dumpUnpackedICmp(dbgs(), Pred, A, B); dbgs() << "\n");
       if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
@@ -1794,7 +1803,14 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())
         ReproducerCondStack.emplace_back(Pred, A, B);
 
-      Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
+      // If samesign is present on the ICmp, simply transfer the signed system
+      // to the unsigned system, and viceversa.
+      if (HasSameSign)
+        Info.addFact(CmpInst::getFlippedSignednessPredicate(Pred), A, B,
+                     CB.NumIn, CB.NumOut, DFSInStack);
+      else
+        Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
+
       if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) {
         // Add dummy entries to ReproducerCondStack to keep it in sync with
         // DFSInStack.
@@ -1828,7 +1844,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
     }
 
     Value *A = nullptr, *B = nullptr;
+    bool HasSameSign = false;
     if (CB.isConditionFact()) {
+      HasSameSign = CB.Cond.HasSameSign;
       Pred = CB.Cond.Pred;
       A = CB.Cond.Op0;
       B = CB.Cond.Op1;
@@ -1847,10 +1865,11 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
     } else {
       bool Matched = match(CB.Inst, m_Intrinsic<Intrinsic::assume>(
                                         m_ICmp(Pred, m_Value(A), m_Value(B))));
+      HasSameSign = cast<ICmpInst>(CB.Inst->getOperand(0))->hasSameSign();
       (void)Matched;
       assert(Matched && "Must have an assume intrinsic with a icmp operand");
     }
-    AddFact(Pred, A, B);
+    AddFact(Pred, A, B, HasSameSign);
   }
 
   if (ReproducerModule && !ReproducerModule->functions().empty()) {
diff --git a/llvm/test/Transforms/ConstraintElimination/transfer-samesign-facts.ll b/llvm/test/Transforms/ConstraintElimination/transfer-samesign-facts.ll
new file mode 100644
index 00000000000000..1b155e050de29e
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/transfer-samesign-facts.ll
@@ -0,0 +1,305 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+define i1 @idx_known_positive_via_len_1(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_known_positive_via_len_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp samesign ult i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 true, [[IDX_ULT_LEN]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_1]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_2]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_3]]
+;
+entry:
+  %len.pos = icmp samesign uge i8 %len, 0
+  %idx.ult.len = icmp samesign ult i8 %idx, %len
+  %and.1 = and i1 %len.pos, %idx.ult.len
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %t.1 = icmp slt i8 %idx, %len
+  %t.2 = icmp samesign uge i8 %idx, 0
+  %r.1 = xor i1 %t.1, %t.2
+
+  %c.1 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.1
+
+  %c.2 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.2
+  ret i1 %r.3
+
+else:
+  %c.3 = icmp sge i8 %idx, 0
+  ret i1 %c.3
+}
+
+; Like @idx_known_positive_via_len_1, but with a different order of known facts.
+define i1 @idx_known_positive_via_len_2(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_known_positive_via_len_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp samesign ult i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 true, [[IDX_ULT_LEN]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_1]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_2]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_3]]
+;
+entry:
+  %idx.ult.len = icmp samesign ult i8 %idx, %len
+  %len.pos = icmp samesign uge i8 %len, 0
+  %and.1 = and i1 %len.pos, %idx.ult.len
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %t.1 = icmp slt i8 %idx, %len
+  %t.2 = icmp samesign uge i8 %idx, 0
+  %r.1 = xor i1 %t.1, %t.2
+
+  %c.1 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.1
+
+  %c.2 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.2
+  ret i1 %r.3
+
+else:
+  %c.3 = icmp sge i8 %idx, 0
+  ret i1 %c.3
+}
+
+
+define i1 @idx_not_known_positive_via_len_uge(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_not_known_positive_via_len_uge(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp samesign ult i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    br i1 [[IDX_ULT_LEN]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, [[C_2]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_3]]
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_5:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_5]]
+;
+entry:
+  %idx.ult.len  = icmp samesign ult i8 %idx, %len
+  br i1 %idx.ult.len, label %then.1, label %else
+
+then.1:
+  %c.1 = icmp slt i8 %idx, %len
+  %c.2 = icmp sge i8 %idx, 0
+  %r.1 = xor i1 %c.1, %c.2
+
+  %c.3 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.3
+
+  %c.4 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.4
+  ret i1 %r.3
+
+else:
+  %c.5 = icmp sge i8 %idx, 0
+  ret i1 %c.5
+}
+
+define i1 @idx_not_known_positive_via_len(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_not_known_positive_via_len(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp samesign ult i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    br i1 [[IDX_ULT_LEN]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, [[C_2]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_3]]
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_5:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_5]]
+;
+entry:
+  %idx.ult.len  = icmp samesign ult i8 %idx, %len
+  br i1 %idx.ult.len, label %then.1, label %else
+
+then.1:
+  %c.1 = icmp slt i8 %idx, %len
+  %c.2 = icmp sge i8 %idx, 0
+  %r.1 = xor i1 %c.1, %c.2
+
+  %c.3 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.3
+
+  %c.4 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.4
+  ret i1 %r.3
+
+else:
+  %c.5 = icmp sge i8 %idx, 0
+  ret i1 %c.5
+}
+
+define i1 @ult_signed_pos_constant(i8 %a) {
+; CHECK-LABEL: @ult_signed_pos_constant(
+; CHECK-NEXT:    [[A_ULT_4:%.*]] = icmp samesign ult i8 [[A:%.*]], 4
+; CHECK-NEXT:    br i1 [[A_ULT_4]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[RES_1:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], true
+; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_2]], true
+; CHECK-NEXT:    ret i1 [[RES_5]]
+; CHECK:       else:
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 true, false
+; CHECK-NEXT:    [[C_4:%.*]] = icmp slt i8 [[A]], 5
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[RES_4]]
+;
+  %a.ult.4 = icmp samesign ult i8 %a, 4
+  br i1 %a.ult.4, label %then, label %else
+
+then:
+  %t.0 = icmp sge i8 %a, 0
+  %t.1 = icmp slt i8 %a, 4
+  %res.1 = xor i1 %t.0, %t.1
+
+  %c.0 = icmp slt i8 %a, 5
+  %res.2 = xor i1 %res.1, %c.0
+  ret i1 %res.2
+
+else:
+  %c.2 = icmp sge i8 %a, 0
+  %c.3 = icmp slt i8 %a, 4
+  %res.3 = xor i1 %c.2, %c.3
+
+  %c.4 = icmp slt i8 %a, 5
+  %res.4 = xor i1 %res.3, %c.4
+
+  ret i1 %res.4
+}
+
+define i1 @ult_signed_neg_constant(i8 %a) {
+; CHECK-LABEL: @ult_signed_neg_constant(
+; CHECK-NEXT:    [[A_ULT_4:%.*]] = icmp samesign ult i8 [[A:%.*]], -2
+; CHECK-NEXT:    br i1 [[A_ULT_4]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 false, true
+; CHECK-NEXT:    ret i1 [[RES_1]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 false
+;
+  %a.ult.4 = icmp samesign ult i8 %a, -2
+  br i1 %a.ult.4, label %then, label %else
+
+then:
+  %c.0 = icmp sge i8 %a, 0
+  %c.1 = icmp slt i8 %a, -2
+  %res.1 = xor i1 %c.0, %c.1
+  ret i1 %res.1
+
+else:
+  ret i1 0
+}
+
+define i1 @ule_signed_pos_constant_1(i8 %a, i8 %b) {
+; CHECK-LABEL: @ule_signed_pos_constant_1(
+; CHECK-NEXT:    [[A_ULE_B:%.*]] = icmp samesign ule i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[A_ULE_B]])
+; CHECK-NEXT:    [[SLT_TEST:%.*]] = icmp slt i8 [[A]], [[B]]
+; CHECK-NEXT:    [[RESULT_XOR:%.*]] = xor i1 true, [[SLT_TEST]]
+; CHECK-NEXT:    ret i1 [[RESULT_XOR]]
+;
+  %a_ule_b = icmp samesign ule i8 %a, %b
+  call void @llvm.assume(i1 %a_ule_b)
+
+  %sle_test = icmp sle i8 %a, %b
+  %slt_test = icmp slt i8 %a, %b
+  %result_xor = xor i1 %sle_test, %slt_test
+
+  ret i1 %result_xor
+}
+
+define i1 @ule_signed_pos_constant_2(i8 %a) {
+; CHECK-LABEL: @ule_signed_pos_constant_2(
+; CHECK-NEXT:    [[A_ULT_4:%.*]] = icmp samesign ule i8 [[A:%.*]], 4
+; CHECK-NEXT:    br i1 [[A_ULT_4]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[RES_1:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], true
+; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_2]], true
+; CHECK-NEXT:    ret i1 [[RES_5]]
+; CHECK:       else:
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 true, false
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sle i8 [[A]], 5
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[RES_4]]
+;
+  %a.ult.4 = icmp samesign ule i8 %a, 4
+  br i1 %a.ult.4, label %then, label %else
+
+then:
+  %t.0 = icmp sge i8 %a, 0
+  %t.1 = icmp sle i8 %a, 4
+  %res.1 = xor i1 %t.0, %t.1
+
+  %c.0 = icmp sle i8 %a, 5
+  %res.2 = xor i1 %res.1, %c.0
+  ret i1 %res.2
+
+else:
+  %c.2 = icmp sge i8 %a, 0
+  %c.3 = icmp sle i8 %a, 4
+  %res.3 = xor i1 %c.2, %c.3
+
+  %c.4 = icmp sle i8 %a, 5
+  %res.4 = xor i1 %res.3, %c.4
+
+  ret i1 %res.4
+}
+
+define i1 @uge_assumed_positive_values(i8 %a, i8 %b) {
+; CHECK-LABEL: @uge_assumed_positive_values(
+; CHECK-NEXT:    [[A_UGT_B:%.*]] = icmp samesign uge i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[A_UGT_B]])
+; CHECK-NEXT:    ret i1 true
+;
+  %a_ugt_b = icmp samesign uge i8 %a, %b
+  call void @llvm.assume(i1 %a_ugt_b)
+
+  %result = icmp sge i8 %a, %b
+
+  ret i1 %result
+}
+
+define i1 @ugt_assumed_positive_values(i8 %a, i8 %b) {
+; CHECK-LABEL: @ugt_assumed_positive_values(
+; CHECK-NEXT:    [[A_UGT_B:%.*]] = icmp samesign ugt i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[A_UGT_B]])
+; CHECK-NEXT:    ret i1 true
+;
+  %a_ugt_b = icmp samesign ugt i8 %a, %b
+  call void @llvm.assume(i1 %a_ugt_b)
+
+  %result = icmp sgt i8 %a, %b
+
+  ret i1 %result
+}

>From 9e9920dbc1298a038a6a23cc7c3802c4a6d080fc Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Fri, 15 Nov 2024 09:11:02 +0000
Subject: [PATCH 2/2] ConstraintElim: don't unnecessarily copy eq preds

---
 llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 3a040ff3f60c0a..85e739bc4083c2 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1805,7 +1805,7 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
 
       // If samesign is present on the ICmp, simply transfer the signed system
       // to the unsigned system, and viceversa.
-      if (HasSameSign)
+      if (HasSameSign && ICmpInst::isRelational(Pred))
         Info.addFact(CmpInst::getFlippedSignednessPredicate(Pred), A, B,
                      CB.NumIn, CB.NumOut, DFSInStack);
       else



More information about the llvm-commits mailing list