Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConstraintElim: teach fact-transfer about samesign #115893

Merged
merged 1 commit into from
Dec 15, 2024

Conversation

artagnon
Copy link
Contributor

@artagnon artagnon commented Nov 12, 2024

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.

@llvmbot
Copy link
Member

llvmbot commented Nov 12, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Ramkumar Ramachandra (artagnon)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/115893.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (+41-22)
  • (added) llvm/test/Transforms/ConstraintElimination/transfer-samesign-facts.ll (+305)
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
+}

Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG. Please wait for additional approval from other reviewers.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably makes sense to land #116867 first and then use it here...

@artagnon
Copy link
Contributor Author

artagnon commented Dec 3, 2024

Probably makes sense to land #116867 first and then use it here...

I realized that it's also better to first land #118534.

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.
@artagnon
Copy link
Contributor Author

Rebased for a clean implementation.

@dtcxzyw
Copy link
Member

dtcxzyw commented Dec 15, 2024

Ping. Is it ready to land?

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@artagnon artagnon merged commit a22578d into llvm:main Dec 15, 2024
8 checks passed
@artagnon artagnon deleted the ce-samesign branch December 15, 2024 17:32
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Dec 16, 2024
revert: stacked on SPIRV patches
a22578d ConstraintElim: teach fact-transfer about samesign (llvm#115893)

Change-Id: If585e91c8cf2ac18d204be5564131956b18f14e8
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Dec 16, 2024
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.

Change-Id: I13b0133a5756aa6cf279db0e16c45c498b981428
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants