[llvm] [Offload] Add Offload API Sphinx documentation (PR #147323)
Kenneth Benzie via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 10 02:36:16 PDT 2025
https://github.com/kbenzie updated https://github.com/llvm/llvm-project/pull/147323
>From bdfacea2e7a3291b3d7a4c66635aaff95e7029be Mon Sep 17 00:00:00 2001
From: "Kenneth Benzie (Benie)" <k.benzie83 at gmail.com>
Date: Mon, 7 Jul 2025 16:13:30 +0100
Subject: [PATCH 1/2] [Offload] Add spec generation to offload-tblgen tool
This patch adds generation of Sphinx compatible reStructuedText
utilizing the C domain to document the Offload API directly from the
spec definition `.td` files.
---
offload/tools/offload-tblgen/APIGen.cpp | 2 +-
offload/tools/offload-tblgen/CMakeLists.txt | 1 +
offload/tools/offload-tblgen/GenCommon.hpp | 5 +
offload/tools/offload-tblgen/Generators.hpp | 1 +
offload/tools/offload-tblgen/SpecGen.cpp | 195 ++++++++++++++++++
.../tools/offload-tblgen/offload-tblgen.cpp | 6 +
6 files changed, 209 insertions(+), 1 deletion(-)
create mode 100644 offload/tools/offload-tblgen/SpecGen.cpp
diff --git a/offload/tools/offload-tblgen/APIGen.cpp b/offload/tools/offload-tblgen/APIGen.cpp
index c52642592e934..8c61d1f12de7a 100644
--- a/offload/tools/offload-tblgen/APIGen.cpp
+++ b/offload/tools/offload-tblgen/APIGen.cpp
@@ -48,7 +48,7 @@ static void ProcessHandle(const HandleRec &H, raw_ostream &OS) {
exit(1);
}
- auto ImplName = H.getName().substr(0, H.getName().size() - 9) + "_impl_t";
+ auto ImplName = getHandleImplName(H);
OS << CommentsHeader;
OS << formatv("/// @brief {0}\n", H.getDesc());
OS << formatv("typedef struct {0} *{1};\n", ImplName, H.getName());
diff --git a/offload/tools/offload-tblgen/CMakeLists.txt b/offload/tools/offload-tblgen/CMakeLists.txt
index 613b166d62b4d..01ef87941e733 100644
--- a/offload/tools/offload-tblgen/CMakeLists.txt
+++ b/offload/tools/offload-tblgen/CMakeLists.txt
@@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS Support)
add_tablegen(offload-tblgen OFFLOAD
EXPORT OFFLOAD
APIGen.cpp
+ SpecGen.cpp
EntryPointGen.cpp
MiscGen.cpp
GenCommon.hpp
diff --git a/offload/tools/offload-tblgen/GenCommon.hpp b/offload/tools/offload-tblgen/GenCommon.hpp
index db432e9958b5d..b57f96ad0c456 100644
--- a/offload/tools/offload-tblgen/GenCommon.hpp
+++ b/offload/tools/offload-tblgen/GenCommon.hpp
@@ -65,3 +65,8 @@ MakeParamComment(const llvm::offload::tblgen::ParamRec &Param) {
(Param.isOut() ? "[out]" : ""),
(Param.isOpt() ? "[optional]" : ""), Param.getDesc());
}
+
+inline std::string
+getHandleImplName(const llvm::offload::tblgen::HandleRec &H) {
+ return (H.getName().substr(0, H.getName().size() - 9) + "_impl_t").str();
+}
diff --git a/offload/tools/offload-tblgen/Generators.hpp b/offload/tools/offload-tblgen/Generators.hpp
index 3f94fc47c6b21..fda63f8b198e5 100644
--- a/offload/tools/offload-tblgen/Generators.hpp
+++ b/offload/tools/offload-tblgen/Generators.hpp
@@ -11,6 +11,7 @@
#include "llvm/TableGen/Record.h"
void EmitOffloadAPI(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitOffloadDoc(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitOffloadFuncNames(const llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitOffloadImplFuncDecls(const llvm::RecordKeeper &Records,
diff --git a/offload/tools/offload-tblgen/SpecGen.cpp b/offload/tools/offload-tblgen/SpecGen.cpp
new file mode 100644
index 0000000000000..d247c916ca1c4
--- /dev/null
+++ b/offload/tools/offload-tblgen/SpecGen.cpp
@@ -0,0 +1,195 @@
+//===- offload-tblgen/APIGen.cpp - Tablegen backend for Offload header ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a Tablegen backend that produces the contents of the Offload API
+// specification. The generated reStructuredText is Sphinx compatible, see
+// https://www.sphinx-doc.org/en/master/usage/domains/c.html for further
+// details on the C language domain.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+
+#include "GenCommon.hpp"
+#include "RecordTypes.hpp"
+
+using namespace llvm;
+using namespace offload::tblgen;
+
+namespace {
+std::string makeFunctionSignature(StringRef RetTy, StringRef Name,
+ ArrayRef<ParamRec> Params) {
+ std::string S;
+ raw_string_ostream OS{S};
+ OS << RetTy << " " << Name << "(";
+ for (const ParamRec &Param : Params) {
+ OS << Param.getType() << " " << Param.getName();
+ if (Param != Params.back()) {
+ OS << ", ";
+ }
+ }
+ OS << ")";
+ return S;
+}
+
+std::string makeDoubleBackticks(StringRef R) {
+ std::string S;
+ for (char C : R) {
+ if (C == '`') {
+ S.push_back('`');
+ }
+ S.push_back(C);
+ }
+ return S;
+}
+
+void processMacro(const MacroRec &M, raw_ostream &OS) {
+ OS << formatv(".. c:macro:: {0}\n\n", M.getNameWithArgs());
+ OS << " " << M.getDesc() << "\n\n";
+}
+
+void processTypedef(const TypedefRec &T, raw_ostream &OS) {
+ OS << formatv(".. c:type:: {0} {1}\n\n", T.getValue(), T.getName());
+ OS << " " << T.getDesc() << "\n\n";
+}
+
+void processHandle(const HandleRec &H, raw_ostream &OS) {
+
+ OS << formatv(".. c:type:: struct {0} *{1}\n\n", getHandleImplName(H),
+ H.getName());
+ OS << " " << H.getDesc() << "\n\n";
+}
+
+void processFptrTypedef(const FptrTypedefRec &F, raw_ostream &OS) {
+ OS << ".. c:type:: "
+ << makeFunctionSignature(F.getReturn(),
+ StringRef{formatv("(*{0})", F.getName())},
+ F.getParams())
+ << "\n\n";
+ for (const ParamRec &P : F.getParams()) {
+ OS << formatv(" :param {0}: {1}\n", P.getName(), P.getDesc());
+ }
+ OS << "\n";
+}
+
+void processEnum(const EnumRec &E, raw_ostream &OS) {
+ OS << formatv(".. c:enum:: {0}\n\n", E.getName());
+ OS << " " << E.getDesc() << "\n\n";
+ for (const EnumValueRec Etor : E.getValues()) {
+ OS << formatv(" .. c:enumerator:: {0}_{1}\n\n", E.getEnumValNamePrefix(),
+ Etor.getName());
+ OS << " " << Etor.getDesc() << "\n\n";
+ }
+}
+
+void processStruct(const StructRec &S, raw_ostream &OS) {
+ OS << formatv(".. c:struct:: {0}\n\n", S.getName());
+ OS << " " << S.getDesc() << "\n\n";
+ for (const StructMemberRec &M : S.getMembers()) {
+ OS << formatv(" .. c:member:: {0} {1}\n\n", M.getType(), M.getName());
+ OS << " " << M.getDesc() << "\n\n";
+ }
+}
+
+void processFunction(const FunctionRec &F, raw_ostream &OS) {
+ OS << ".. c:function:: "
+ << makeFunctionSignature({formatv("{0}_result_t", PrefixLower)},
+ F.getName(), F.getParams())
+ << "\n\n";
+
+ OS << " " << F.getDesc() << "\n\n";
+ for (StringRef D : F.getDetails()) {
+ OS << " " << D << "\n";
+ }
+ if (!F.getDetails().empty()) {
+ OS << "\n";
+ }
+
+ for (const ParamRec &P : F.getParams()) {
+ OS << formatv(" :param {0}: {1}\n", P.getName(), P.getDesc());
+ }
+
+ for (const ReturnRec &R : F.getReturns()) {
+ OS << formatv(" :retval {0}:\n", R.getValue());
+ for (StringRef C : R.getConditions()) {
+ OS << " * ";
+ if (C.starts_with("`") && C.ends_with("`")) {
+ OS << ":c:expr:" << C;
+ } else {
+ OS << makeDoubleBackticks(C);
+ }
+ OS << "\n";
+ }
+ }
+ OS << "\n";
+}
+} // namespace
+
+void EmitOffloadDoc(const RecordKeeper &Records, raw_ostream &OS) {
+ OS << "Offload API\n";
+ OS << "===========\n\n";
+
+ ArrayRef<const Record *> Macros = Records.getAllDerivedDefinitions("Macro");
+ if (!Macros.empty()) {
+ OS << "Macros\n";
+ OS << "------\n\n";
+ for (const Record *M : Macros) {
+ processMacro(MacroRec{M}, OS);
+ }
+ }
+
+ ArrayRef<const Record *> Handles = Records.getAllDerivedDefinitions("Handle");
+ ArrayRef<const Record *> Typedefs =
+ Records.getAllDerivedDefinitions("Typedef");
+ ArrayRef<const Record *> FptrTypedefs =
+ Records.getAllDerivedDefinitions("FptrTypedef");
+ if (!Handles.empty() || !Typedefs.empty() || !FptrTypedefs.empty()) {
+ OS << "Type Definitions\n";
+ OS << "----------------\n\n";
+ for (const Record *H : Handles) {
+ processHandle(HandleRec{H}, OS);
+ }
+ for (const Record *T : Typedefs) {
+ processTypedef(TypedefRec{T}, OS);
+ }
+ for (const Record *F : FptrTypedefs) {
+ processFptrTypedef(FptrTypedefRec{F}, OS);
+ }
+ }
+
+ ArrayRef<const Record *> Enums = Records.getAllDerivedDefinitions("Enum");
+ OS << "Enums\n";
+ OS << "-----\n\n";
+ if (!Enums.empty()) {
+ for (const Record *E : Enums) {
+ processEnum(EnumRec{E}, OS);
+ }
+ }
+
+ ArrayRef<const Record *> Structs = Records.getAllDerivedDefinitions("Struct");
+ if (!Structs.empty()) {
+ OS << "Structs\n";
+ OS << "-------\n\n";
+ for (const Record *S : Structs) {
+ processStruct(StructRec{S}, OS);
+ }
+ }
+
+ ArrayRef<const Record *> Functions =
+ Records.getAllDerivedDefinitions("Function");
+ if (!Functions.empty()) {
+ OS << "Functions\n";
+ OS << "---------\n\n";
+ for (const Record *F : Functions) {
+ processFunction(FunctionRec{F}, OS);
+ }
+ }
+}
diff --git a/offload/tools/offload-tblgen/offload-tblgen.cpp b/offload/tools/offload-tblgen/offload-tblgen.cpp
index ee7f6d4d79bff..18aaf9e00f08a 100644
--- a/offload/tools/offload-tblgen/offload-tblgen.cpp
+++ b/offload/tools/offload-tblgen/offload-tblgen.cpp
@@ -26,6 +26,7 @@ enum ActionType {
PrintRecords,
DumpJSON,
GenAPI,
+ GenDoc,
GenFuncNames,
GenImplFuncDecls,
GenEntryPoints,
@@ -44,6 +45,8 @@ cl::opt<ActionType> Action(
clEnumValN(DumpJSON, "dump-json",
"Dump all records as machine-readable JSON"),
clEnumValN(GenAPI, "gen-api", "Generate Offload API header contents"),
+ clEnumValN(GenDoc, "gen-doc",
+ "Generate Offload API documentation contents"),
clEnumValN(GenFuncNames, "gen-func-names",
"Generate a list of all Offload API function names"),
clEnumValN(
@@ -71,6 +74,9 @@ static bool OffloadTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case GenAPI:
EmitOffloadAPI(Records, OS);
break;
+ case GenDoc:
+ EmitOffloadDoc(Records, OS);
+ break;
case GenFuncNames:
EmitOffloadFuncNames(Records, OS);
break;
>From 57d11ae95b7b5312450498fb11a17a25d9d86b6d Mon Sep 17 00:00:00 2001
From: "Kenneth Benzie (Benie)" <k.benzie83 at gmail.com>
Date: Mon, 7 Jul 2025 16:16:37 +0100
Subject: [PATCH 2/2] [Offload] Add Sphinx HTML documentation target
Introduces the `docs-offload-html` target when CMake is configured with
`LLVM_ENABLE_SPHINX=ON` and `SPHINX_OUTPUT_HTML=ON`. Utilized
`offload-tblgen -gen-spen` to generate Offload API specification docs.
---
offload/CMakeLists.txt | 3 +++
offload/docs/.gitignore | 3 +++
offload/docs/CMakeLists.txt | 37 ++++++++++++++++++++++++++++++++
offload/docs/conf.py | 32 +++++++++++++++++++++++++++
offload/docs/index.rst | 21 ++++++++++++++++++
offload/liboffload/API/Common.td | 15 -------------
6 files changed, 96 insertions(+), 15 deletions(-)
create mode 100644 offload/docs/.gitignore
create mode 100644 offload/docs/CMakeLists.txt
create mode 100644 offload/docs/conf.py
create mode 100644 offload/docs/index.rst
diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index d49069f6eb420..38fa77e41bb53 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -23,6 +23,8 @@ elseif(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
return()
endif()
+set(OFFLOAD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
if(OPENMP_STANDALONE_BUILD)
set(OFFLOAD_LIBDIR_SUFFIX "" CACHE STRING
"Suffix of lib installation directory, e.g. 64 => lib64")
@@ -371,6 +373,7 @@ add_subdirectory(tools/offload-tblgen)
add_subdirectory(plugins-nextgen)
add_subdirectory(DeviceRTL)
add_subdirectory(tools)
+add_subdirectory(docs)
# Build target agnostic offloading library.
add_subdirectory(libomptarget)
diff --git a/offload/docs/.gitignore b/offload/docs/.gitignore
new file mode 100644
index 0000000000000..5b7d6815f8188
--- /dev/null
+++ b/offload/docs/.gitignore
@@ -0,0 +1,3 @@
+_static/
+_themes/
+offload-api.rst
diff --git a/offload/docs/CMakeLists.txt b/offload/docs/CMakeLists.txt
new file mode 100644
index 0000000000000..9c5db87b5ab4e
--- /dev/null
+++ b/offload/docs/CMakeLists.txt
@@ -0,0 +1,37 @@
+if(LLVM_ENABLE_SPHINX)
+ include(AddSphinxTarget)
+ if(SPHINX_FOUND AND SPHINX_OUTPUT_HTML)
+ # Generate offload-api.rst from OffloadAPI.td
+ set(LLVM_TARGET_DEFINITIONS
+ ${OFFLOAD_SOURCE_DIR}/liboffload/API/OffloadAPI.td)
+ tablegen(OFFLOAD source/offload-api.rst -gen-doc
+ EXTRA_INCLUDES ${OFFLOAD_SOURCE_DIR}/liboffload/API)
+ add_public_tablegen_target(OffloadDocsGenerate)
+
+ # Due to Sphinx only allowing a single source direcotry and the fact we
+ # only generate a single file, copy offload-api.rst to the source directory
+ # to be included in the generated documentation.
+ # Additionally, copy the llvm-theme into the Sphinx source directory.
+ # A .gitignore file ensures the copied files will not be added to the
+ # repository.
+ add_custom_target(OffloadDocsCopy
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_BINARY_DIR}/source/offload-api.rst
+ ${CMAKE_CURRENT_SOURCE_DIR}/offload-api.rst
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${OFFLOAD_SOURCE_DIR}/../clang/www/favicon.ico
+ ${CMAKE_CURRENT_SOURCE_DIR}/_static/favicon.ico
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${OFFLOAD_SOURCE_DIR}/../llvm/docs/_static/llvm.css
+ ${CMAKE_CURRENT_SOURCE_DIR}/_static/llvm.css
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${OFFLOAD_SOURCE_DIR}/../llvm/docs/_themes
+ ${CMAKE_CURRENT_SOURCE_DIR}/_themes
+ )
+ add_dependencies(OffloadDocsCopy OffloadDocsGenerate)
+
+ # Generate the HTML documentation, the docs-offload-html target.
+ add_sphinx_target(html offload)
+ add_dependencies(docs-offload-html OffloadDocsCopy)
+ endif()
+endif()
diff --git a/offload/docs/conf.py b/offload/docs/conf.py
new file mode 100644
index 0000000000000..08a991a7d5ad5
--- /dev/null
+++ b/offload/docs/conf.py
@@ -0,0 +1,32 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = "Offload"
+copyright = "2025, LLVM project"
+author = "LLVM project"
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = []
+
+templates_path = ["_templates"]
+exclude_patterns = []
+
+# -- C domain configuration --------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#c-config
+
+c_maximum_signature_line_length = 60
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = "llvm-theme"
+html_theme_path = ["_themes"]
+html_static_path = ["_static"]
+html_favicon = "_static/favicon.ico"
diff --git a/offload/docs/index.rst b/offload/docs/index.rst
new file mode 100644
index 0000000000000..481d1f7ddd8b8
--- /dev/null
+++ b/offload/docs/index.rst
@@ -0,0 +1,21 @@
+.. Offload documentation master file, created by
+ sphinx-quickstart on Fri Jul 4 14:59:13 2025.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to Offload's documentation!
+===================================
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ offload-api
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/offload/liboffload/API/Common.td b/offload/liboffload/API/Common.td
index 850a01d06759e..a621de081a0c6 100644
--- a/offload/liboffload/API/Common.td
+++ b/offload/liboffload/API/Common.td
@@ -44,21 +44,6 @@ def : Macro {
let alt_value = "";
}
-def : Macro {
- let name = "OL_DLLEXPORT";
- let desc = "Microsoft-specific dllexport storage-class attribute";
- let condition = "defined(_WIN32)";
- let value = "__declspec(dllexport)";
-}
-
-def : Macro {
- let name = "OL_DLLEXPORT";
- let desc = "GCC-specific dllexport storage-class attribute";
- let condition = "__GNUC__ >= 4";
- let value = "__attribute__ ((visibility (\"default\")))";
- let alt_value = "";
-}
-
def : Handle {
let name = "ol_platform_handle_t";
let desc = "Handle of a platform instance";
More information about the llvm-commits
mailing list