| //===- 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); | |
| } | |
| } | |
| } |