[Offload] Add Offload API Sphinx documentation (#147323)
* 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. * 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.
This commit is contained in:
parent
56a8655f4a
commit
cea33304c0
@ -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)
|
||||
|
3
offload/docs/.gitignore
vendored
Normal file
3
offload/docs/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
_static/
|
||||
_themes/
|
||||
offload-api.rst
|
37
offload/docs/CMakeLists.txt
Normal file
37
offload/docs/CMakeLists.txt
Normal file
@ -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()
|
32
offload/docs/conf.py
Normal file
32
offload/docs/conf.py
Normal file
@ -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"
|
21
offload/docs/index.rst
Normal file
21
offload/docs/index.rst
Normal file
@ -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`
|
@ -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";
|
||||
|
@ -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());
|
||||
|
@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS Support)
|
||||
add_tablegen(offload-tblgen OFFLOAD
|
||||
EXPORT OFFLOAD
|
||||
APIGen.cpp
|
||||
DocGen.cpp
|
||||
EntryPointGen.cpp
|
||||
MiscGen.cpp
|
||||
GenCommon.hpp
|
||||
|
195
offload/tools/offload-tblgen/DocGen.cpp
Normal file
195
offload/tools/offload-tblgen/DocGen.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
//===- offload-tblgen/DocGen.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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user