[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:18 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