Skip to content

[Offload] Add Offload API Sphinx documentation #147323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions offload/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions offload/docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
_static/
_themes/
offload-api.rst
37 changes: 37 additions & 0 deletions offload/docs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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 changes: 32 additions & 0 deletions offload/docs/conf.py
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions offload/docs/index.rst
Original file line number Diff line number Diff line change
@@ -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`
15 changes: 0 additions & 15 deletions offload/liboffload/API/Common.td
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
2 changes: 1 addition & 1 deletion offload/tools/offload-tblgen/APIGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions offload/tools/offload-tblgen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
195 changes: 195 additions & 0 deletions offload/tools/offload-tblgen/DocGen.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
5 changes: 5 additions & 0 deletions offload/tools/offload-tblgen/GenCommon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
1 change: 1 addition & 0 deletions offload/tools/offload-tblgen/Generators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions offload/tools/offload-tblgen/offload-tblgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum ActionType {
PrintRecords,
DumpJSON,
GenAPI,
GenDoc,
GenFuncNames,
GenImplFuncDecls,
GenEntryPoints,
Expand All @@ -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(
Expand Down Expand Up @@ -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;
Expand Down
Loading