[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()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(OFFLOAD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
if(OPENMP_STANDALONE_BUILD)
|
if(OPENMP_STANDALONE_BUILD)
|
||||||
set(OFFLOAD_LIBDIR_SUFFIX "" CACHE STRING
|
set(OFFLOAD_LIBDIR_SUFFIX "" CACHE STRING
|
||||||
"Suffix of lib installation directory, e.g. 64 => lib64")
|
"Suffix of lib installation directory, e.g. 64 => lib64")
|
||||||
@ -371,6 +373,7 @@ add_subdirectory(tools/offload-tblgen)
|
|||||||
add_subdirectory(plugins-nextgen)
|
add_subdirectory(plugins-nextgen)
|
||||||
add_subdirectory(DeviceRTL)
|
add_subdirectory(DeviceRTL)
|
||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
|
add_subdirectory(docs)
|
||||||
|
|
||||||
# Build target agnostic offloading library.
|
# Build target agnostic offloading library.
|
||||||
add_subdirectory(libomptarget)
|
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 = "";
|
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 {
|
def : Handle {
|
||||||
let name = "ol_platform_handle_t";
|
let name = "ol_platform_handle_t";
|
||||||
let desc = "Handle of a platform instance";
|
let desc = "Handle of a platform instance";
|
||||||
|
@ -48,7 +48,7 @@ static void ProcessHandle(const HandleRec &H, raw_ostream &OS) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ImplName = H.getName().substr(0, H.getName().size() - 9) + "_impl_t";
|
auto ImplName = getHandleImplName(H);
|
||||||
OS << CommentsHeader;
|
OS << CommentsHeader;
|
||||||
OS << formatv("/// @brief {0}\n", H.getDesc());
|
OS << formatv("/// @brief {0}\n", H.getDesc());
|
||||||
OS << formatv("typedef struct {0} *{1};\n", ImplName, H.getName());
|
OS << formatv("typedef struct {0} *{1};\n", ImplName, H.getName());
|
||||||
|
@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS Support)
|
|||||||
add_tablegen(offload-tblgen OFFLOAD
|
add_tablegen(offload-tblgen OFFLOAD
|
||||||
EXPORT OFFLOAD
|
EXPORT OFFLOAD
|
||||||
APIGen.cpp
|
APIGen.cpp
|
||||||
|
DocGen.cpp
|
||||||
EntryPointGen.cpp
|
EntryPointGen.cpp
|
||||||
MiscGen.cpp
|
MiscGen.cpp
|
||||||
GenCommon.hpp
|
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.isOut() ? "[out]" : ""),
|
||||||
(Param.isOpt() ? "[optional]" : ""), Param.getDesc());
|
(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"
|
#include "llvm/TableGen/Record.h"
|
||||||
|
|
||||||
void EmitOffloadAPI(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
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,
|
void EmitOffloadFuncNames(const llvm::RecordKeeper &Records,
|
||||||
llvm::raw_ostream &OS);
|
llvm::raw_ostream &OS);
|
||||||
void EmitOffloadImplFuncDecls(const llvm::RecordKeeper &Records,
|
void EmitOffloadImplFuncDecls(const llvm::RecordKeeper &Records,
|
||||||
|
@ -26,6 +26,7 @@ enum ActionType {
|
|||||||
PrintRecords,
|
PrintRecords,
|
||||||
DumpJSON,
|
DumpJSON,
|
||||||
GenAPI,
|
GenAPI,
|
||||||
|
GenDoc,
|
||||||
GenFuncNames,
|
GenFuncNames,
|
||||||
GenImplFuncDecls,
|
GenImplFuncDecls,
|
||||||
GenEntryPoints,
|
GenEntryPoints,
|
||||||
@ -44,6 +45,8 @@ cl::opt<ActionType> Action(
|
|||||||
clEnumValN(DumpJSON, "dump-json",
|
clEnumValN(DumpJSON, "dump-json",
|
||||||
"Dump all records as machine-readable JSON"),
|
"Dump all records as machine-readable JSON"),
|
||||||
clEnumValN(GenAPI, "gen-api", "Generate Offload API header contents"),
|
clEnumValN(GenAPI, "gen-api", "Generate Offload API header contents"),
|
||||||
|
clEnumValN(GenDoc, "gen-doc",
|
||||||
|
"Generate Offload API documentation contents"),
|
||||||
clEnumValN(GenFuncNames, "gen-func-names",
|
clEnumValN(GenFuncNames, "gen-func-names",
|
||||||
"Generate a list of all Offload API function names"),
|
"Generate a list of all Offload API function names"),
|
||||||
clEnumValN(
|
clEnumValN(
|
||||||
@ -71,6 +74,9 @@ static bool OffloadTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
|
|||||||
case GenAPI:
|
case GenAPI:
|
||||||
EmitOffloadAPI(Records, OS);
|
EmitOffloadAPI(Records, OS);
|
||||||
break;
|
break;
|
||||||
|
case GenDoc:
|
||||||
|
EmitOffloadDoc(Records, OS);
|
||||||
|
break;
|
||||||
case GenFuncNames:
|
case GenFuncNames:
|
||||||
EmitOffloadFuncNames(Records, OS);
|
EmitOffloadFuncNames(Records, OS);
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user