Kenneth Benzie (Benie) b520d21c02
[Offload] Add tagged type to enumerator docs (#147998)
When `EnumRec::isTyped()` is true, include the
`EnumValueRec::getTaggedType()` to the documentation.
2025-07-14 13:35:36 +01:00

200 lines
5.8 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 << " ";
if (E.isTyped()) {
OS << ":c:expr:`" << Etor.getTaggedType() << "` — ";
}
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);
}
}
}