[llvm-branch-commits] [llvm] RuntimeLibcallsEmitter: Handle calling conv in per-library functions (PR #223760)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Sep 15 09:57:28 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-tablegen
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
Pull handling of the default calling convention into the
setAvailableLibFuncs_<name> functions, so the library logic will be
fully contained.
Co-authored-by: Claude (Opus 4.8) <noreply@<!-- -->anthropic.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/223760.diff
2 Files Affected:
- (added) llvm/test/TableGen/RuntimeLibcallEmitter-library-default-cc.td (+50)
- (modified) llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp (+80-5)
``````````diff
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-library-default-cc.td b/llvm/test/TableGen/RuntimeLibcallEmitter-library-default-cc.td
new file mode 100644
index 0000000000000..349ee626c97f0
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-library-default-cc.td
@@ -0,0 +1,50 @@
+// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s | FileCheck %s
+
+// A member CC naming the DefaultCC sentinel gets a DefaultCC local
+// seeded from the consuming system library's
+// DefaultLibcallCallingConv.
+
+include "llvm/IR/RuntimeLibcallsImpl.td"
+
+def SOME_CALL : RuntimeLibcall;
+def OTHER_CALL : RuntimeLibcall;
+
+def some_impl : RuntimeLibcallImpl<SOME_CALL>;
+def other_impl : RuntimeLibcallImpl<OTHER_CALL>;
+
+def IsFoo : LibcallPredicate<[{TT.getArch() == Triple::arm}]>;
+def isFoo : RuntimeLibcallAvailability<(all_of IsFoo)>;
+
+// Predicate using the isAAPCS_ABI member helper.
+def IsAAPCS : LibcallPredicate<[{isAAPCS_ABI(TT, ABIName)}]>;
+def isAAPCS : RuntimeLibcallAvailability<(all_of IsAAPCS)>;
+
+// CC naming the DefaultCC sentinel.
+def FooDefaultOrAAPCS : LibcallCallingConv<
+ [{isAAPCS_ABI(TT, ABIName) ? static_cast<CallingConv::ID>(CallingConv::ARM_AAPCS) : static_cast<CallingConv::ID>(DefaultCC)}]
+>;
+
+// One member gated on isAAPCS_ABI, one whose CC names DefaultCC.
+def FooLib : LibcallLibrary<"foo", (add
+ LibcallImpls<(add some_impl), isAAPCS>,
+ LibcallsWithCC<(add other_impl), FooDefaultOrAAPCS>)>;
+
+def FooSystem : SystemRuntimeLibrary<isFoo, (add FooLib)> {
+ let DefaultLibcallCallingConv
+ = LibcallCallingConv<[{FloatABI == FloatABI::Hard ? CallingConv::ARM_AAPCS_VFP : CallingConv::ARM_AAPCS}]>;
+}
+
+// The library function seeds DefaultCC
+
+// CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setAvailableLibFuncs_foo(const llvm::Triple &TT, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName, LongDoubleFormat LongDoubleFormat) {
+// CHECK-NEXT: const CallingConv::ID DefaultCC = FloatABI == FloatABI::Hard ? CallingConv::ARM_AAPCS_VFP : CallingConv::ARM_AAPCS;
+
+// CHECK: setLibcallImplCallingConv(Impl, isAAPCS_ABI(TT, ABIName) ? static_cast<CallingConv::ID>(CallingConv::ARM_AAPCS) : static_cast<CallingConv::ID>(DefaultCC));
+// CHECK: if (isAAPCS_ABI(TT, ABIName)) {
+
+// The dispatcher seeds its own whole-table DefaultCC.
+
+// CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(
+// CHECK: const CallingConv::ID DefaultCC = FloatABI == FloatABI::Hard ? CallingConv::ARM_AAPCS_VFP : CallingConv::ARM_AAPCS;
+// CHECK: if (isLibraryAvailable("foo"))
+// CHECK-NEXT: setAvailableLibFuncs_foo(TT, ExceptionModel, FloatABI, EABIVersion, ABIName, LongDoubleFormat);
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 7a72b1061c737..c44cf8b3008d3 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -124,10 +124,14 @@ class RuntimeLibcallEmitter {
// Emit a `setAvailableLibFuncs_<name>` member function for all LibcallLibrary
// defs sharing \p Name, each gated by its own availability predicate. \p
- // Exclusions are emitted as guarded setUnavailable calls at the end.
+ // Exclusions are emitted as guarded setUnavailable calls at the end. \p
+ // DefaultCCs holds the distinct DefaultLibcallCallingConv snippets the
+ // consuming system libraries supply; exactly one must exist if any member CC
+ // names the DefaultCC sentinel.
void emitLibraryFunction(raw_ostream &OS, StringRef Name,
ArrayRef<const Record *> Libs,
- ArrayRef<LibraryExclusion> Exclusions) const;
+ ArrayRef<LibraryExclusion> Exclusions,
+ ArrayRef<StringRef> DefaultCCs) const;
// Group all LibcallLibrary defs by their shared LibraryName, preserving
// definition order. Both the member-declaration fragment and the definitions
@@ -544,7 +548,8 @@ void RuntimeLibcallEmitter::emitLibraryVariant(raw_ostream &OS,
void RuntimeLibcallEmitter::emitLibraryFunction(
raw_ostream &OS, StringRef Name, ArrayRef<const Record *> Libs,
- ArrayRef<LibraryExclusion> Exclusions) const {
+ ArrayRef<LibraryExclusion> Exclusions,
+ ArrayRef<StringRef> DefaultCCs) const {
OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setAvailableLibFuncs_";
emitLibFuncSuffix(OS, Name);
OS << "(const llvm::Triple &TT, "
@@ -600,6 +605,37 @@ void RuntimeLibcallEmitter::emitLibraryFunction(
Expanded.push_back(std::move(EL));
}
+ // If any member CC names the DefaultCC sentinel, emit a local for it (seeded
+ // from the consuming system library's DefaultLibcallCallingConv) so those
+ // snippets are in scope. \p DefaultCCs holds the distinct snippets the
+ // consumers supply: exactly one must exist.
+ bool ReferencesDefaultCC = any_of(Expanded, [](const ExpandedLibrary &EL) {
+ return any_of(EL.Pred2Funcs, [](const auto &KeyAndFuncs) {
+ const Record *CC = KeyAndFuncs.second.CallingConv;
+ return CC && CC->getValueAsString("CallingConv").contains("DefaultCC");
+ });
+ });
+
+ if (ReferencesDefaultCC) {
+ if (DefaultCCs.empty()) {
+ PrintFatalError(Libs.front(),
+ "library '" + Name +
+ "' has a member calling convention referencing "
+ "DefaultCC but no consuming SystemRuntimeLibrary "
+ "provides a DefaultLibcallCallingConv");
+ }
+ if (DefaultCCs.size() > 1) {
+ PrintFatalError(Libs.front(),
+ "library '" + Name +
+ "' is dispatched by multiple SystemRuntimeLibrary "
+ "defs with different DefaultLibcallCallingConv; "
+ "DefaultCC is ambiguous for its member calling "
+ "conventions");
+ }
+
+ OS << " const CallingConv::ID DefaultCC = " << DefaultCCs.front() << ";\n";
+ }
+
// Impls unconditional in every variant are emitted once and stripped from
// each variant, so the shared core is not repeated.
SetVector<const RuntimeLibcallImpl *> SharedCore;
@@ -735,8 +771,47 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
}
}
- for (const auto &[Name, Libs] : collectLibrariesByName())
- emitLibraryFunction(OS, Name, Libs, ExclusionsByLibName.lookup(Name));
+ // Collect, per library name, the distinct DefaultLibcallCallingConv snippets
+ // its consuming system libraries supply (a plain Record walk; no member
+ // expansion). emitLibraryFunction, which already expands the members, picks
+ // the snippet for a library that names the DefaultCC sentinel and diagnoses a
+ // missing (none) or ambiguous (more than one) snippet.
+ MapVector<StringRef, SetVector<StringRef>> DefaultCCsByLibName;
+ for (const Record *R : AllLibs) {
+ const Record *DefaultCCClass =
+ R->getValueAsDef("DefaultLibcallCallingConv");
+ StringRef DefaultCC =
+ DefaultCCClass ? DefaultCCClass->getValueAsString("CallingConv").trim()
+ : StringRef();
+ if (DefaultCC.empty())
+ continue;
+ const DagInit *MemberDag =
+ R->getValueAsDef("MemberList")->getValueAsDag("MemberList");
+ for (const Init *Arg : MemberDag->getArgs()) {
+ const auto *DI = dyn_cast<DefInit>(Arg);
+ if (!DI)
+ continue;
+ const Record *Def = DI->getDef();
+ const Record *Lib = nullptr;
+ if (Def->isSubClassOf("LibcallLibrary"))
+ Lib = Def;
+ else if (Def->isSubClassOf("LibraryRef"))
+ Lib = Def->getValueAsDef("Library");
+ if (!Lib)
+ continue;
+ DefaultCCsByLibName[Lib->getValueAsString("LibraryName")].insert(
+ DefaultCC);
+ }
+ }
+
+ for (const auto &[Name, Libs] : collectLibrariesByName()) {
+ auto It = DefaultCCsByLibName.find(Name);
+ ArrayRef<StringRef> DefaultCCs = It == DefaultCCsByLibName.end()
+ ? ArrayRef<StringRef>()
+ : It->second.getArrayRef();
+ emitLibraryFunction(OS, Name, Libs, ExclusionsByLibName.lookup(Name),
+ DefaultCCs);
+ }
OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets("
"const llvm::Triple &TT, ExceptionHandling ExceptionModel, "
``````````
</details>
https://github.com/llvm/llvm-project/pull/223760
More information about the llvm-branch-commits
mailing list