[llvm] DAG: Gracefully diagnose missing fp-compare libcall when softening (PR #228416)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 2 05:28:05 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/228416

Avoid fatal errors, and legalize to poison with a proper context
error.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>

>From cbbd94d47b1c614d2a009d017e91873821ed0a4b Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 12 Aug 2026 03:37:35 +0200
Subject: [PATCH] DAG: Gracefully diagnose missing fp-compare libcall when
 softening

Avoid fatal errors, and legalize to poison with a proper context
error.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
---
 llvm/include/llvm/CodeGen/ISDOpcodes.h        |  5 ++
 .../SelectionDAG/SelectionDAGDumper.cpp       | 89 ++++++++++++-------
 .../CodeGen/SelectionDAG/TargetLowering.cpp   | 35 +++++---
 .../NVPTX/fp128-compare-no-libcall-error.ll   | 23 +++++
 4 files changed, 112 insertions(+), 40 deletions(-)
 create mode 100644 llvm/test/CodeGen/NVPTX/fp128-compare-no-libcall-error.ll

diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 953201a26a3e71..cbc9902968a132 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -18,6 +18,8 @@
 
 namespace llvm {
 
+class StringRef;
+
 /// ISD namespace - This namespace contains an enum which represents all of the
 /// SelectionDAG node types and value types.
 ///
@@ -1893,6 +1895,9 @@ inline unsigned getUnorderedFlavor(CondCode Cond) {
 /// SetCC operation.
 LLVM_ABI CondCode getSetCCInverse(CondCode Operation, EVT Type);
 
+/// Return the name of the given condition code, e.g. "setoeq".
+LLVM_ABI StringRef getCondCodeName(CondCode Operation);
+
 inline bool isExtOpcode(unsigned Opcode) {
   return Opcode == ISD::ANY_EXTEND || Opcode == ISD::ZERO_EXTEND ||
          Opcode == ISD::SIGN_EXTEND;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 0017e35ab371e3..7e3a6520e11427 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -59,6 +59,64 @@ static cl::opt<bool>
     PrintSDNodeAddrs("print-sdnode-addrs", cl::Hidden,
                      cl::desc("Print addresses of SDNodes when dumping"));
 
+StringRef ISD::getCondCodeName(ISD::CondCode Operation) {
+  switch (Operation) {
+  default:
+    llvm_unreachable("Unknown setcc condition!");
+  case ISD::SETOEQ:
+    return "setoeq";
+  case ISD::SETOGT:
+    return "setogt";
+  case ISD::SETOGE:
+    return "setoge";
+  case ISD::SETOLT:
+    return "setolt";
+  case ISD::SETOLE:
+    return "setole";
+  case ISD::SETONE:
+    return "setone";
+
+  case ISD::SETO:
+    return "seto";
+  case ISD::SETUO:
+    return "setuo";
+  case ISD::SETUEQ:
+    return "setueq";
+  case ISD::SETUGT:
+    return "setugt";
+  case ISD::SETUGE:
+    return "setuge";
+  case ISD::SETULT:
+    return "setult";
+  case ISD::SETULE:
+    return "setule";
+  case ISD::SETUNE:
+    return "setune";
+
+  case ISD::SETEQ:
+    return "seteq";
+  case ISD::SETGT:
+    return "setgt";
+  case ISD::SETGE:
+    return "setge";
+  case ISD::SETLT:
+    return "setlt";
+  case ISD::SETLE:
+    return "setle";
+  case ISD::SETNE:
+    return "setne";
+
+  case ISD::SETTRUE:
+    return "settrue";
+  case ISD::SETTRUE2:
+    return "settrue2";
+  case ISD::SETFALSE:
+    return "setfalse";
+  case ISD::SETFALSE2:
+    return "setfalse2";
+  }
+}
+
 std::string SDNode::getOperationName(const SelectionDAG *G) const {
   switch (getOpcode()) {
   default:
@@ -544,36 +602,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
     // clang-format on
 
   case ISD::CONDCODE:
-    switch (cast<CondCodeSDNode>(this)->get()) {
-    default: llvm_unreachable("Unknown setcc condition!");
-    case ISD::SETOEQ:                   return "setoeq";
-    case ISD::SETOGT:                   return "setogt";
-    case ISD::SETOGE:                   return "setoge";
-    case ISD::SETOLT:                   return "setolt";
-    case ISD::SETOLE:                   return "setole";
-    case ISD::SETONE:                   return "setone";
-
-    case ISD::SETO:                     return "seto";
-    case ISD::SETUO:                    return "setuo";
-    case ISD::SETUEQ:                   return "setueq";
-    case ISD::SETUGT:                   return "setugt";
-    case ISD::SETUGE:                   return "setuge";
-    case ISD::SETULT:                   return "setult";
-    case ISD::SETULE:                   return "setule";
-    case ISD::SETUNE:                   return "setune";
-
-    case ISD::SETEQ:                    return "seteq";
-    case ISD::SETGT:                    return "setgt";
-    case ISD::SETGE:                    return "setge";
-    case ISD::SETLT:                    return "setlt";
-    case ISD::SETLE:                    return "setle";
-    case ISD::SETNE:                    return "setne";
-
-    case ISD::SETTRUE:                  return "settrue";
-    case ISD::SETTRUE2:                 return "settrue2";
-    case ISD::SETFALSE:                 return "setfalse";
-    case ISD::SETFALSE2:                return "setfalse2";
-    }
+    return ISD::getCondCodeName(cast<CondCodeSDNode>(this)->get()).str();
   case ISD::VECREDUCE_FADD:             return "vecreduce_fadd";
   case ISD::VECREDUCE_SEQ_FADD:         return "vecreduce_seq_fadd";
   case ISD::VECREDUCE_FMUL:             return "vecreduce_fmul";
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 1eeab43bd480e1..e89be8b69929f8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -412,6 +412,7 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
          && "Unsupported setcc type!");
 
   // Expand into one or more soft-fp libcall(s).
+  ISD::CondCode OrigCCCode = CCCode;
   RTLIB::Libcall LC1 = RTLIB::UNKNOWN_LIBCALL, LC2 = RTLIB::UNKNOWN_LIBCALL;
   ISD::CondCode CC1 = ISD::SETCC_INVALID, CC2 = ISD::SETCC_INVALID;
   bool ShouldInvertCC = false;
@@ -525,15 +526,28 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
   EVT OpsVT[2] = { OldLHS.getValueType(),
                    OldRHS.getValueType() };
   CallOptions.setTypeListBeforeSoften(OpsVT, RetVT);
-  auto Call = makeLibCall(DAG, LC1, RetVT, Ops, CallOptions, dl, Chain);
-  NewLHS = Call.first;
-  NewRHS = DAG.getConstant(0, dl, RetVT);
 
-  if (DAG.getLibcalls().getLibcallImpl(LC1) == RTLIB::Unsupported) {
-    reportFatalUsageError(
-        "no libcall available to soften floating-point compare");
+  auto ReportNoLibcall = [&]() {
+    DAG.getContext()->emitError(
+        Twine("no libcall available to soften floating-point ") +
+        ISD::getCondCodeName(OrigCCCode) + " compare with type " +
+        VT.getEVTString());
+    NewLHS = DAG.getPOISON(RetVT);
+    NewRHS = DAG.getConstant(0, dl, RetVT);
+    CCCode = ISD::SETNE;
+  };
+
+  // Check availability before makeLibCall, which fatally errors otherwise.
+  RTLIB::LibcallImpl LC1Impl = DAG.getLibcalls().getLibcallImpl(LC1);
+  if (LC1Impl == RTLIB::Unsupported) {
+    ReportNoLibcall();
+    return;
   }
 
+  auto Call = makeLibCall(DAG, LC1Impl, RetVT, Ops, CallOptions, dl, Chain);
+  NewLHS = Call.first;
+  NewRHS = DAG.getConstant(0, dl, RetVT);
+
   CCCode = CC1;
   if (ShouldInvertCC) {
     assert(RetVT.isInteger());
@@ -544,9 +558,10 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
     // Update Chain.
     Chain = Call.second;
   } else {
-    if (DAG.getLibcalls().getLibcallImpl(LC2) == RTLIB::Unsupported) {
-      reportFatalUsageError(
-          "no libcall available to soften floating-point compare");
+    RTLIB::LibcallImpl LC2Impl = DAG.getLibcalls().getLibcallImpl(LC2);
+    if (LC2Impl == RTLIB::Unsupported) {
+      ReportNoLibcall();
+      return;
     }
 
     assert(CCCode == (ShouldInvertCC ? ISD::SETEQ : ISD::SETNE) &&
@@ -560,7 +575,7 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
     }
 
     SDValue Tmp = DAG.getSetCC(dl, SetCCVT, NewLHS, NewRHS, CCCode);
-    auto Call2 = makeLibCall(DAG, LC2, RetVT, Ops, CallOptions, dl, Chain);
+    auto Call2 = makeLibCall(DAG, LC2Impl, RetVT, Ops, CallOptions, dl, Chain);
     CCCode = CC2;
     if (ShouldInvertCC)
       CCCode = getSetCCInverse(CCCode, RetVT);
diff --git a/llvm/test/CodeGen/NVPTX/fp128-compare-no-libcall-error.ll b/llvm/test/CodeGen/NVPTX/fp128-compare-no-libcall-error.ll
new file mode 100644
index 00000000000000..e05dc591584e6c
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/fp128-compare-no-libcall-error.ll
@@ -0,0 +1,23 @@
+; RUN: not llc -mtriple=nvptx64 -filetype=null %s 2>&1 | FileCheck %s
+
+; NVPTX has no fp128 compare libcall, so this should diagnose a missing libcall
+; rather than crash. The reported compare kind is the original one, not the
+; inverted or rewritten form used to select the libcall.
+
+; CHECK: error: no libcall available to soften floating-point setoeq compare with type f128
+define i1 @test_fcmp_oeq_f128(fp128 %a, fp128 %b) {
+  %r = fcmp oeq fp128 %a, %b
+  ret i1 %r
+}
+
+; CHECK: error: no libcall available to soften floating-point setult compare with type f128
+define i1 @test_fcmp_ult_f128(fp128 %a, fp128 %b) {
+  %r = fcmp ult fp128 %a, %b
+  ret i1 %r
+}
+
+; CHECK: error: no libcall available to soften floating-point setone compare with type f128
+define i1 @test_fcmp_one_f128(fp128 %a, fp128 %b) {
+  %r = fcmp one fp128 %a, %b
+  ret i1 %r
+}



More information about the llvm-commits mailing list