200 lines · cpp
1//===- offload-tblgen/DocGen.cpp - Tablegen backend for Offload header ----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This is a Tablegen backend that produces the contents of the Offload API10// specification. The generated reStructuredText is Sphinx compatible, see11// https://www.sphinx-doc.org/en/master/usage/domains/c.html for further12// details on the C language domain.13//14//===----------------------------------------------------------------------===//15 16#include "llvm/ADT/StringExtras.h"17#include "llvm/Support/FormatVariadic.h"18#include "llvm/TableGen/Record.h"19#include "llvm/TableGen/TableGenBackend.h"20 21#include "GenCommon.hpp"22#include "RecordTypes.hpp"23 24using namespace llvm;25using namespace offload::tblgen;26 27namespace {28std::string makeFunctionSignature(StringRef RetTy, StringRef Name,29 ArrayRef<ParamRec> Params) {30 std::string S;31 raw_string_ostream OS{S};32 OS << RetTy << " " << Name << "(";33 for (const ParamRec &Param : Params) {34 OS << Param.getType() << " " << Param.getName();35 if (Param != Params.back()) {36 OS << ", ";37 }38 }39 OS << ")";40 return S;41}42 43std::string makeDoubleBackticks(StringRef R) {44 std::string S;45 for (char C : R) {46 if (C == '`') {47 S.push_back('`');48 }49 S.push_back(C);50 }51 return S;52}53 54void processMacro(const MacroRec &M, raw_ostream &OS) {55 OS << formatv(".. c:macro:: {0}\n\n", M.getNameWithArgs());56 OS << " " << M.getDesc() << "\n\n";57}58 59void processTypedef(const TypedefRec &T, raw_ostream &OS) {60 OS << formatv(".. c:type:: {0} {1}\n\n", T.getValue(), T.getName());61 OS << " " << T.getDesc() << "\n\n";62}63 64void processHandle(const HandleRec &H, raw_ostream &OS) {65 66 OS << formatv(".. c:type:: struct {0} *{1}\n\n", getHandleImplName(H),67 H.getName());68 OS << " " << H.getDesc() << "\n\n";69}70 71void processFptrTypedef(const FptrTypedefRec &F, raw_ostream &OS) {72 OS << ".. c:type:: "73 << makeFunctionSignature(F.getReturn(),74 StringRef{formatv("(*{0})", F.getName())},75 F.getParams())76 << "\n\n";77 for (const ParamRec &P : F.getParams()) {78 OS << formatv(" :param {0}: {1}\n", P.getName(), P.getDesc());79 }80 OS << "\n";81}82 83void processEnum(const EnumRec &E, raw_ostream &OS) {84 OS << formatv(".. c:enum:: {0}\n\n", E.getName());85 OS << " " << E.getDesc() << "\n\n";86 for (const EnumValueRec Etor : E.getValues()) {87 OS << formatv(" .. c:enumerator:: {0}_{1}\n\n", E.getEnumValNamePrefix(),88 Etor.getName());89 OS << " ";90 if (E.isTyped()) {91 OS << ":c:expr:`" << Etor.getTaggedType() << "` — ";92 }93 OS << Etor.getDesc() << "\n\n";94 }95}96 97void processStruct(const StructRec &S, raw_ostream &OS) {98 OS << formatv(".. c:struct:: {0}\n\n", S.getName());99 OS << " " << S.getDesc() << "\n\n";100 for (const StructMemberRec &M : S.getMembers()) {101 OS << formatv(" .. c:member:: {0} {1}\n\n", M.getType(), M.getName());102 OS << " " << M.getDesc() << "\n\n";103 }104}105 106void processFunction(const FunctionRec &F, raw_ostream &OS) {107 OS << ".. c:function:: "108 << makeFunctionSignature({formatv("{0}_result_t", PrefixLower)},109 F.getName(), F.getParams())110 << "\n\n";111 112 OS << " " << F.getDesc() << "\n\n";113 for (StringRef D : F.getDetails()) {114 OS << " " << D << "\n";115 }116 if (!F.getDetails().empty()) {117 OS << "\n";118 }119 120 for (const ParamRec &P : F.getParams()) {121 OS << formatv(" :param {0}: {1}\n", P.getName(), P.getDesc());122 }123 124 for (const ReturnRec &R : F.getReturns()) {125 OS << formatv(" :retval {0}:\n", R.getValue());126 for (StringRef C : R.getConditions()) {127 OS << " * ";128 if (C.starts_with("`") && C.ends_with("`")) {129 OS << ":c:expr:" << C;130 } else {131 OS << makeDoubleBackticks(C);132 }133 OS << "\n";134 }135 }136 OS << "\n";137}138} // namespace139 140void EmitOffloadDoc(const RecordKeeper &Records, raw_ostream &OS) {141 OS << "Offload API\n";142 OS << "===========\n\n";143 144 ArrayRef<const Record *> Macros = Records.getAllDerivedDefinitions("Macro");145 if (!Macros.empty()) {146 OS << "Macros\n";147 OS << "------\n\n";148 for (const Record *M : Macros) {149 processMacro(MacroRec{M}, OS);150 }151 }152 153 ArrayRef<const Record *> Handles = Records.getAllDerivedDefinitions("Handle");154 ArrayRef<const Record *> Typedefs =155 Records.getAllDerivedDefinitions("Typedef");156 ArrayRef<const Record *> FptrTypedefs =157 Records.getAllDerivedDefinitions("FptrTypedef");158 if (!Handles.empty() || !Typedefs.empty() || !FptrTypedefs.empty()) {159 OS << "Type Definitions\n";160 OS << "----------------\n\n";161 for (const Record *H : Handles) {162 processHandle(HandleRec{H}, OS);163 }164 for (const Record *T : Typedefs) {165 processTypedef(TypedefRec{T}, OS);166 }167 for (const Record *F : FptrTypedefs) {168 processFptrTypedef(FptrTypedefRec{F}, OS);169 }170 }171 172 ArrayRef<const Record *> Enums = Records.getAllDerivedDefinitions("Enum");173 OS << "Enums\n";174 OS << "-----\n\n";175 if (!Enums.empty()) {176 for (const Record *E : Enums) {177 processEnum(EnumRec{E}, OS);178 }179 }180 181 ArrayRef<const Record *> Structs = Records.getAllDerivedDefinitions("Struct");182 if (!Structs.empty()) {183 OS << "Structs\n";184 OS << "-------\n\n";185 for (const Record *S : Structs) {186 processStruct(StructRec{S}, OS);187 }188 }189 190 ArrayRef<const Record *> Functions =191 Records.getAllDerivedDefinitions("Function");192 if (!Functions.empty()) {193 OS << "Functions\n";194 OS << "---------\n\n";195 for (const Record *F : Functions) {196 processFunction(FunctionRec{F}, OS);197 }198 }199}200