[llvm-branch-commits] [llvm] RuntimeLibcalls: Add generic FCMP3_F* three-way compare for single-symbol ABIs (PR #211618)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Aug 2 21:30:17 PDT 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/211618

>From 2ab8e287f15812147cd97e519604d820d5d46bf1 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 22 Jul 2026 13:38:36 +0200
Subject: [PATCH] RuntimeLibcalls: Add generic FCMP3_F* three-way compare for
 single-symbol ABIs

MSP430's __mspabi_cmpd/__mspabi_cmpf are one three-way compare symbol serving
every predicate, previously modeled as six suffixed impls each. Replace them
with a single generic operator FCMP3_*, and give softenSetCCOperands a 3rd
lowering option. After the boolean O*_F* and the per-predicate FCMP3_<pred>_F*
helpers, use the generic FCMP3_F* helper tested with the predicate's condition
code.

Also opt __nedf2 out of the MSP430 default set: it was the only libgcc F64
compare not already opted out, so it would otherwise provide FCMP3_UNE_F64 and
win over __mspabi_cmpd for not-equal.

Co-authored-by: Claude (Opus 4.8) <noreply at anthropic.com>
---
 llvm/include/llvm/IR/RuntimeLibcalls.td       | 35 +++-----
 .../CodeGen/SelectionDAG/TargetLowering.cpp   | 85 ++++++++++---------
 llvm/lib/Target/MSP430/MSP430Subtarget.cpp    | 28 +++---
 3 files changed, 69 insertions(+), 79 deletions(-)

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index 19b32fe029799..a11e15ca21fb0 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -483,7 +483,9 @@ def CONVERT_PPCF128_F128 : RuntimeLibcall;
 //
 // The O*_F* and UO_F* libcalls return a simple 0/1 boolean value.
 //
-// The FCMP3_PRED_*_F* libcalls return a three-way (-1/0/1) result.
+// The FCMP3_PRED_*_F* libcalls return a three-way (-1/0/1) result, one symbol
+// per predicate. FCMP3_F* is a generic three-way compare for ABIs with one
+// symbol serving every predicate (e.g. MSP430's __mspabi_cmpd).
 foreach FPTy = ["F32", "F64", "F128", "PPCF128"] in {
   def OEQ_#FPTy : RuntimeLibcall;
   def UNE_#FPTy : RuntimeLibcall;
@@ -499,6 +501,8 @@ foreach FPTy = ["F32", "F64", "F128", "PPCF128"] in {
   def FCMP3_PRED_OLT_#FPTy : RuntimeLibcall;
   def FCMP3_PRED_OLE_#FPTy : RuntimeLibcall;
   def FCMP3_PRED_OGT_#FPTy : RuntimeLibcall;
+
+  def FCMP3_#FPTy : RuntimeLibcall;
 }
 
 // Memory
@@ -2884,18 +2888,9 @@ def __mspabi_fltulf : RuntimeLibcallImpl<UINTTOFP_I32_F32>;
 def __mspabi_fltullf : RuntimeLibcallImpl<UINTTOFP_I64_F32>;
 
 // Floating point comparisons - EABI Table 7
-def __mspabi_cmpd__oeq : RuntimeLibcallImpl<FCMP3_PRED_OEQ_F64, "__mspabi_cmpd">;
-def __mspabi_cmpd__une : RuntimeLibcallImpl<FCMP3_PRED_UNE_F64, "__mspabi_cmpd">;
-def __mspabi_cmpd__oge : RuntimeLibcallImpl<FCMP3_PRED_OGE_F64, "__mspabi_cmpd">;
-def __mspabi_cmpd__olt : RuntimeLibcallImpl<FCMP3_PRED_OLT_F64, "__mspabi_cmpd">;
-def __mspabi_cmpd__ole : RuntimeLibcallImpl<FCMP3_PRED_OLE_F64, "__mspabi_cmpd">;
-def __mspabi_cmpd__ogt : RuntimeLibcallImpl<FCMP3_PRED_OGT_F64, "__mspabi_cmpd">;
-def __mspabi_cmpf__oeq : RuntimeLibcallImpl<FCMP3_PRED_OEQ_F32, "__mspabi_cmpf">;
-def __mspabi_cmpf__une : RuntimeLibcallImpl<FCMP3_PRED_UNE_F32, "__mspabi_cmpf">;
-def __mspabi_cmpf__oge : RuntimeLibcallImpl<FCMP3_PRED_OGE_F32, "__mspabi_cmpf">;
-def __mspabi_cmpf__olt : RuntimeLibcallImpl<FCMP3_PRED_OLT_F32, "__mspabi_cmpf">;
-def __mspabi_cmpf__ole : RuntimeLibcallImpl<FCMP3_PRED_OLE_F32, "__mspabi_cmpf">;
-def __mspabi_cmpf__ogt : RuntimeLibcallImpl<FCMP3_PRED_OGT_F32, "__mspabi_cmpf">;
+// A single three-way compare symbol serves every predicate.
+def __mspabi_cmpd : RuntimeLibcallImpl<FCMP3_F64>;
+def __mspabi_cmpf : RuntimeLibcallImpl<FCMP3_F32>;
 
 // Floating point arithmetic - EABI Table 8
 def __mspabi_addd : RuntimeLibcallImpl<ADD_F64>;
@@ -3022,18 +3017,8 @@ def MSP430SystemLibrary
       __mspabi_fltullf,
 
       // Floating point comparisons - EABI Table 7
-      LibcallsWithCC<(add __mspabi_cmpd__oeq,
-                          __mspabi_cmpd__une,
-                          __mspabi_cmpd__oge,
-                          __mspabi_cmpd__olt,
-                          __mspabi_cmpd__ole,
-                          __mspabi_cmpd__ogt), MSP430_BUILTIN>,
-      __mspabi_cmpf__oeq,
-      __mspabi_cmpf__une,
-      __mspabi_cmpf__oge,
-      __mspabi_cmpf__olt,
-      __mspabi_cmpf__ole,
-      __mspabi_cmpf__ogt,
+      LibcallsWithCC<(add __mspabi_cmpd), MSP430_BUILTIN>,
+      __mspabi_cmpf,
 
       // Floating point arithmetic - EABI Table 8
       LibcallsWithCC<(add __mspabi_addd,
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 86c0a2adb35b9..46e11ede878a1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -324,14 +324,19 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
 
 /// Select the libcall and the condition code to test its result against 0 for
 /// an ordered floating-point compare. \p BoolLC is the boolean helper (result
-/// is 0/1); \p TriStateLC is the three-way helper (result is -1/0/1, tested
-/// against 0 with \p TriStateCC). The boolean form is preferred when available.
+/// is 0/1). \p TriStateLC is the per-predicate three-way helper and \p
+/// GenericLC the generic single-symbol three-way helper (both return -1/0/1,
+/// tested against 0 with \p TriStateCC). The boolean form is preferred, then
+/// the per-predicate three-way, then the generic three-way.
 static std::pair<RTLIB::Libcall, ISD::CondCode>
 selectFPCmpLibcall(const LibcallLoweringInfo &Libcalls, RTLIB::Libcall BoolLC,
-                   RTLIB::Libcall TriStateLC, ISD::CondCode TriStateCC) {
+                   RTLIB::Libcall TriStateLC, RTLIB::Libcall GenericLC,
+                   ISD::CondCode TriStateCC) {
   if (Libcalls.getLibcallImpl(BoolLC) != RTLIB::Unsupported)
     return {BoolLC, ISD::SETNE};
-  return {TriStateLC, TriStateCC};
+  if (Libcalls.getLibcallImpl(TriStateLC) != RTLIB::Unsupported)
+    return {TriStateLC, TriStateCC};
+  return {GenericLC, TriStateCC};
 }
 
 void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
@@ -363,47 +368,47 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
   switch (CCCode) {
   case ISD::SETEQ:
   case ISD::SETOEQ:
-    std::tie(LC1, CC1) =
-        selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OEQ),
-                           FP_CMP_LIBCALL(FCMP3_PRED_OEQ), ISD::SETEQ);
+    std::tie(LC1, CC1) = selectFPCmpLibcall(
+        DAG.getLibcalls(), FP_CMP_LIBCALL(OEQ), FP_CMP_LIBCALL(FCMP3_PRED_OEQ),
+        FP_CMP_LIBCALL(FCMP3), ISD::SETEQ);
     break;
   case ISD::SETNE:
   case ISD::SETUNE:
-    std::tie(LC1, CC1) =
-        selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(UNE),
-                           FP_CMP_LIBCALL(FCMP3_PRED_UNE), ISD::SETNE);
+    std::tie(LC1, CC1) = selectFPCmpLibcall(
+        DAG.getLibcalls(), FP_CMP_LIBCALL(UNE), FP_CMP_LIBCALL(FCMP3_PRED_UNE),
+        FP_CMP_LIBCALL(FCMP3), ISD::SETNE);
     // Some ABIs (e.g. AEABI) provide neither a not-equal nor a three-way
     // compare; obtain not-equal (UNE = !OEQ) by inverting ordered-equal.
     if (DAG.getLibcalls().getLibcallImpl(LC1) == RTLIB::Unsupported) {
-      std::tie(LC1, CC1) =
-          selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OEQ),
-                             FP_CMP_LIBCALL(FCMP3_PRED_OEQ), ISD::SETEQ);
+      std::tie(LC1, CC1) = selectFPCmpLibcall(
+          DAG.getLibcalls(), FP_CMP_LIBCALL(OEQ),
+          FP_CMP_LIBCALL(FCMP3_PRED_OEQ), FP_CMP_LIBCALL(FCMP3), ISD::SETEQ);
       ShouldInvertCC = true;
     }
     break;
   case ISD::SETGE:
   case ISD::SETOGE:
-    std::tie(LC1, CC1) =
-        selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OGE),
-                           FP_CMP_LIBCALL(FCMP3_PRED_OGE), ISD::SETGE);
+    std::tie(LC1, CC1) = selectFPCmpLibcall(
+        DAG.getLibcalls(), FP_CMP_LIBCALL(OGE), FP_CMP_LIBCALL(FCMP3_PRED_OGE),
+        FP_CMP_LIBCALL(FCMP3), ISD::SETGE);
     break;
   case ISD::SETLT:
   case ISD::SETOLT:
-    std::tie(LC1, CC1) =
-        selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OLT),
-                           FP_CMP_LIBCALL(FCMP3_PRED_OLT), ISD::SETLT);
+    std::tie(LC1, CC1) = selectFPCmpLibcall(
+        DAG.getLibcalls(), FP_CMP_LIBCALL(OLT), FP_CMP_LIBCALL(FCMP3_PRED_OLT),
+        FP_CMP_LIBCALL(FCMP3), ISD::SETLT);
     break;
   case ISD::SETLE:
   case ISD::SETOLE:
-    std::tie(LC1, CC1) =
-        selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OLE),
-                           FP_CMP_LIBCALL(FCMP3_PRED_OLE), ISD::SETLE);
+    std::tie(LC1, CC1) = selectFPCmpLibcall(
+        DAG.getLibcalls(), FP_CMP_LIBCALL(OLE), FP_CMP_LIBCALL(FCMP3_PRED_OLE),
+        FP_CMP_LIBCALL(FCMP3), ISD::SETLE);
     break;
   case ISD::SETGT:
   case ISD::SETOGT:
-    std::tie(LC1, CC1) =
-        selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OGT),
-                           FP_CMP_LIBCALL(FCMP3_PRED_OGT), ISD::SETGT);
+    std::tie(LC1, CC1) = selectFPCmpLibcall(
+        DAG.getLibcalls(), FP_CMP_LIBCALL(OGT), FP_CMP_LIBCALL(FCMP3_PRED_OGT),
+        FP_CMP_LIBCALL(FCMP3), ISD::SETGT);
     break;
   case ISD::SETO:
     ShouldInvertCC = true;
@@ -420,33 +425,33 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
   case ISD::SETUEQ:
     LC1 = FP_CMP_LIBCALL(UO);
     CC1 = ISD::SETNE;
-    std::tie(LC2, CC2) =
-        selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OEQ),
-                           FP_CMP_LIBCALL(FCMP3_PRED_OEQ), ISD::SETEQ);
+    std::tie(LC2, CC2) = selectFPCmpLibcall(
+        DAG.getLibcalls(), FP_CMP_LIBCALL(OEQ), FP_CMP_LIBCALL(FCMP3_PRED_OEQ),
+        FP_CMP_LIBCALL(FCMP3), ISD::SETEQ);
     break;
   default:
     // Invert CC for unordered comparisons, handled by the ordered inverse.
     ShouldInvertCC = true;
     switch (CCCode) {
     case ISD::SETULT:
-      std::tie(LC1, CC1) =
-          selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OGE),
-                             FP_CMP_LIBCALL(FCMP3_PRED_OGE), ISD::SETGE);
+      std::tie(LC1, CC1) = selectFPCmpLibcall(
+          DAG.getLibcalls(), FP_CMP_LIBCALL(OGE),
+          FP_CMP_LIBCALL(FCMP3_PRED_OGE), FP_CMP_LIBCALL(FCMP3), ISD::SETGE);
       break;
     case ISD::SETULE:
-      std::tie(LC1, CC1) =
-          selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OGT),
-                             FP_CMP_LIBCALL(FCMP3_PRED_OGT), ISD::SETGT);
+      std::tie(LC1, CC1) = selectFPCmpLibcall(
+          DAG.getLibcalls(), FP_CMP_LIBCALL(OGT),
+          FP_CMP_LIBCALL(FCMP3_PRED_OGT), FP_CMP_LIBCALL(FCMP3), ISD::SETGT);
       break;
     case ISD::SETUGT:
-      std::tie(LC1, CC1) =
-          selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OLE),
-                             FP_CMP_LIBCALL(FCMP3_PRED_OLE), ISD::SETLE);
+      std::tie(LC1, CC1) = selectFPCmpLibcall(
+          DAG.getLibcalls(), FP_CMP_LIBCALL(OLE),
+          FP_CMP_LIBCALL(FCMP3_PRED_OLE), FP_CMP_LIBCALL(FCMP3), ISD::SETLE);
       break;
     case ISD::SETUGE:
-      std::tie(LC1, CC1) =
-          selectFPCmpLibcall(DAG.getLibcalls(), FP_CMP_LIBCALL(OLT),
-                             FP_CMP_LIBCALL(FCMP3_PRED_OLT), ISD::SETLT);
+      std::tie(LC1, CC1) = selectFPCmpLibcall(
+          DAG.getLibcalls(), FP_CMP_LIBCALL(OLT),
+          FP_CMP_LIBCALL(FCMP3_PRED_OLT), FP_CMP_LIBCALL(FCMP3), ISD::SETLT);
       break;
     default:
       llvm_unreachable("Do not know how to soften this setcc!");
diff --git a/llvm/lib/Target/MSP430/MSP430Subtarget.cpp b/llvm/lib/Target/MSP430/MSP430Subtarget.cpp
index dbe0489be356b..6d4d6e2298156 100644
--- a/llvm/lib/Target/MSP430/MSP430Subtarget.cpp
+++ b/llvm/lib/Target/MSP430/MSP430Subtarget.cpp
@@ -158,20 +158,20 @@ void MSP430Subtarget::initLibcallLoweringInfo(LibcallLoweringInfo &Info) const {
       {RTLIB::SINTTOFP_I64_F32, RTLIB::impl___mspabi_fltllif},
       {RTLIB::UINTTOFP_I32_F32, RTLIB::impl___mspabi_fltulf},
       {RTLIB::UINTTOFP_I64_F32, RTLIB::impl___mspabi_fltullf},
-      // Floating point comparisons - EABI Table 7. These are three-way
-      // compares returning -1/0/1, so they implement the FCMP3_PRED_* libcalls.
-      {RTLIB::FCMP3_PRED_OEQ_F64, RTLIB::impl___mspabi_cmpd__oeq},
-      {RTLIB::FCMP3_PRED_UNE_F64, RTLIB::impl___mspabi_cmpd__une},
-      {RTLIB::FCMP3_PRED_OGE_F64, RTLIB::impl___mspabi_cmpd__oge},
-      {RTLIB::FCMP3_PRED_OLT_F64, RTLIB::impl___mspabi_cmpd__olt},
-      {RTLIB::FCMP3_PRED_OLE_F64, RTLIB::impl___mspabi_cmpd__ole},
-      {RTLIB::FCMP3_PRED_OGT_F64, RTLIB::impl___mspabi_cmpd__ogt},
-      {RTLIB::FCMP3_PRED_OEQ_F32, RTLIB::impl___mspabi_cmpf__oeq},
-      {RTLIB::FCMP3_PRED_UNE_F32, RTLIB::impl___mspabi_cmpf__une},
-      {RTLIB::FCMP3_PRED_OGE_F32, RTLIB::impl___mspabi_cmpf__oge},
-      {RTLIB::FCMP3_PRED_OLT_F32, RTLIB::impl___mspabi_cmpf__olt},
-      {RTLIB::FCMP3_PRED_OLE_F32, RTLIB::impl___mspabi_cmpf__ole},
-      {RTLIB::FCMP3_PRED_OGT_F32, RTLIB::impl___mspabi_cmpf__ogt},
+      // Floating point comparisons - EABI Table 7. A single three-way compare
+      // symbol serves every predicate.
+      {RTLIB::FCMP3_PRED_OEQ_F64, RTLIB::impl___mspabi_cmpd},
+      {RTLIB::FCMP3_PRED_UNE_F64, RTLIB::impl___mspabi_cmpd},
+      {RTLIB::FCMP3_PRED_OGE_F64, RTLIB::impl___mspabi_cmpd},
+      {RTLIB::FCMP3_PRED_OLT_F64, RTLIB::impl___mspabi_cmpd},
+      {RTLIB::FCMP3_PRED_OLE_F64, RTLIB::impl___mspabi_cmpd},
+      {RTLIB::FCMP3_PRED_OGT_F64, RTLIB::impl___mspabi_cmpd},
+      {RTLIB::FCMP3_PRED_OEQ_F32, RTLIB::impl___mspabi_cmpf},
+      {RTLIB::FCMP3_PRED_UNE_F32, RTLIB::impl___mspabi_cmpf},
+      {RTLIB::FCMP3_PRED_OGE_F32, RTLIB::impl___mspabi_cmpf},
+      {RTLIB::FCMP3_PRED_OLT_F32, RTLIB::impl___mspabi_cmpf},
+      {RTLIB::FCMP3_PRED_OLE_F32, RTLIB::impl___mspabi_cmpf},
+      {RTLIB::FCMP3_PRED_OGT_F32, RTLIB::impl___mspabi_cmpf},
       // Floating point arithmetic - EABI Table 8.
       {RTLIB::ADD_F64, RTLIB::impl___mspabi_addd},
       {RTLIB::SUB_F64, RTLIB::impl___mspabi_subd},



More information about the llvm-branch-commits mailing list