
* 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.
196 lines
5.7 KiB
C++
196 lines
5.7 KiB
C++
//===- 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);
|
|
}
|
|
}
|
|
}
|