[llvm] [CGP] Reconstruct borrow chain from icmp pattern for subtract-with-carry (PR #189018)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 4 14:36:21 PDT 2026


=?utf-8?q?Paweł?= Bylica <pawel at hepcolgum.band>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/189018 at github.com>


================
@@ -1762,6 +1763,68 @@ bool CodeGenPrepare::combineToUSubWithOverflow(CmpInst *Cmp,
   return true;
 }
 
+/// FIXME: The name is similar to combineToUSubWithOverflow. Consider renaming
+/// one or both to better distinguish them.
+///
+/// Reconstruct a subtract-with-borrow chain from its canonicalized icmp form.
+///
+/// InstCombine simplifies chained usub.with.overflow intrinsics (used for
+/// multi-precision subtraction) into icmp patterns:
+///   carry_out = or(icmp ult A, B, and(icmp eq A, B, carry_in))
+///
+/// This is algebraically correct but prevents the backend from generating
+/// efficient subtract-with-borrow instructions (e.g. x86 sbb, aarch64 sbcs).
+///
+/// This function matches the pattern and reconstructs the chained
+/// usub.with.overflow form that the DAG combiner can lower to USUBO_CARRY.
+bool CodeGenPrepare::combineToUSubWithCarry(BinaryOperator *OrI) {
+  if (!OrI->getType()->isIntOrIntVectorTy(1))
+    return false;
+
+  assert(OrI->getOpcode() == Instruction::Or && "Expected or instruction");
+
+  // Match: or(icmp ult A, B, and(icmp eq A, B, carry_in))
+  // with all commuted variants of and and icmp eq operand order.
+  Value *A, *B, *CarryIn;
+  if (!match(
+          OrI,
+          m_c_BinOp(
+              m_SpecificICmp(ICmpInst::ICMP_ULT, m_Value(A), m_Value(B)),
+              m_c_And(m_CombineOr(m_SpecificICmp(ICmpInst::ICMP_EQ,
+                                                 m_Deferred(A), m_Deferred(B)),
+                                  m_SpecificICmp(ICmpInst::ICMP_EQ,
+                                                 m_Deferred(B), m_Deferred(A))),
+                      m_Value(CarryIn)))))
+    return false;
+
+  // Check that the target supports subtract-with-borrow for this type.
+  Type *OpTy = A->getType();
+  EVT VT = TLI->getValueType(*DL, OpTy);
+  if (!TLI->isOperationLegalOrCustom(ISD::USUBO_CARRY, VT))
----------------
RKSimon wrote:

Do you think this should go in DAG instead? I've no objections, I just figured it'd end up in CGP like some of the other addsub-overfow patterns

https://github.com/llvm/llvm-project/pull/189018


More information about the llvm-commits mailing list