xref: /llvm-project/offload/tools/offload-tblgen/APIGen.cpp (revision fd3907ccb583df99e9c19d2fe84e4e7c52d75de9)
1*fd3907ccSCallum Fare //===- offload-tblgen/APIGen.cpp - Tablegen backend for Offload header ----===//
2*fd3907ccSCallum Fare //
3*fd3907ccSCallum Fare // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fd3907ccSCallum Fare // See https://llvm.org/LICENSE.txt for license information.
5*fd3907ccSCallum Fare // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fd3907ccSCallum Fare //
7*fd3907ccSCallum Fare //===----------------------------------------------------------------------===//
8*fd3907ccSCallum Fare //
9*fd3907ccSCallum Fare // This is a Tablegen backend that produces the contents of the Offload API
10*fd3907ccSCallum Fare // header. The generated comments are Doxygen compatible.
11*fd3907ccSCallum Fare //
12*fd3907ccSCallum Fare //===----------------------------------------------------------------------===//
13*fd3907ccSCallum Fare 
14*fd3907ccSCallum Fare #include "llvm/ADT/StringExtras.h"
15*fd3907ccSCallum Fare #include "llvm/Support/FormatVariadic.h"
16*fd3907ccSCallum Fare #include "llvm/TableGen/Record.h"
17*fd3907ccSCallum Fare #include "llvm/TableGen/TableGenBackend.h"
18*fd3907ccSCallum Fare 
19*fd3907ccSCallum Fare #include "GenCommon.hpp"
20*fd3907ccSCallum Fare #include "RecordTypes.hpp"
21*fd3907ccSCallum Fare 
22*fd3907ccSCallum Fare using namespace llvm;
23*fd3907ccSCallum Fare using namespace offload::tblgen;
24*fd3907ccSCallum Fare 
25*fd3907ccSCallum Fare // Produce a possibly multi-line comment from the input string
26*fd3907ccSCallum Fare static std::string MakeComment(StringRef in) {
27*fd3907ccSCallum Fare   std::string out = "";
28*fd3907ccSCallum Fare   size_t LineStart = 0;
29*fd3907ccSCallum Fare   size_t LineBreak = 0;
30*fd3907ccSCallum Fare   while (LineBreak < in.size()) {
31*fd3907ccSCallum Fare     LineBreak = in.find_first_of("\n", LineStart);
32*fd3907ccSCallum Fare     if (LineBreak - LineStart <= 1) {
33*fd3907ccSCallum Fare       break;
34*fd3907ccSCallum Fare     }
35*fd3907ccSCallum Fare     out += std::string("/// ") +
36*fd3907ccSCallum Fare            in.substr(LineStart, LineBreak - LineStart).str() + "\n";
37*fd3907ccSCallum Fare     LineStart = LineBreak + 1;
38*fd3907ccSCallum Fare   }
39*fd3907ccSCallum Fare 
40*fd3907ccSCallum Fare   return out;
41*fd3907ccSCallum Fare }
42*fd3907ccSCallum Fare 
43*fd3907ccSCallum Fare static void ProcessHandle(const HandleRec &H, raw_ostream &OS) {
44*fd3907ccSCallum Fare   OS << CommentsHeader;
45*fd3907ccSCallum Fare   OS << formatv("/// @brief {0}\n", H.getDesc());
46*fd3907ccSCallum Fare   OS << formatv("typedef struct {0}_ *{0};\n", H.getName());
47*fd3907ccSCallum Fare }
48*fd3907ccSCallum Fare 
49*fd3907ccSCallum Fare static void ProcessTypedef(const TypedefRec &T, raw_ostream &OS) {
50*fd3907ccSCallum Fare   OS << CommentsHeader;
51*fd3907ccSCallum Fare   OS << formatv("/// @brief {0}\n", T.getDesc());
52*fd3907ccSCallum Fare   OS << formatv("typedef {0} {1};\n", T.getValue(), T.getName());
53*fd3907ccSCallum Fare }
54*fd3907ccSCallum Fare 
55*fd3907ccSCallum Fare static void ProcessMacro(const MacroRec &M, raw_ostream &OS) {
56*fd3907ccSCallum Fare   OS << CommentsHeader;
57*fd3907ccSCallum Fare   OS << formatv("#ifndef {0}\n", M.getName());
58*fd3907ccSCallum Fare   if (auto Condition = M.getCondition()) {
59*fd3907ccSCallum Fare     OS << formatv("#if {0}\n", *Condition);
60*fd3907ccSCallum Fare   }
61*fd3907ccSCallum Fare   OS << "/// @brief " << M.getDesc() << "\n";
62*fd3907ccSCallum Fare   OS << formatv("#define {0} {1}\n", M.getNameWithArgs(), M.getValue());
63*fd3907ccSCallum Fare   if (auto AltValue = M.getAltValue()) {
64*fd3907ccSCallum Fare     OS << "#else\n";
65*fd3907ccSCallum Fare     OS << formatv("#define {0} {1}\n", M.getNameWithArgs(), *AltValue);
66*fd3907ccSCallum Fare   }
67*fd3907ccSCallum Fare   if (auto Condition = M.getCondition()) {
68*fd3907ccSCallum Fare     OS << formatv("#endif // {0}\n", *Condition);
69*fd3907ccSCallum Fare   }
70*fd3907ccSCallum Fare   OS << formatv("#endif // {0}\n", M.getName());
71*fd3907ccSCallum Fare }
72*fd3907ccSCallum Fare 
73*fd3907ccSCallum Fare static void ProcessFunction(const FunctionRec &F, raw_ostream &OS) {
74*fd3907ccSCallum Fare   OS << CommentsHeader;
75*fd3907ccSCallum Fare   OS << formatv("/// @brief {0}\n", F.getDesc());
76*fd3907ccSCallum Fare   OS << CommentsBreak;
77*fd3907ccSCallum Fare 
78*fd3907ccSCallum Fare   OS << "/// @details\n";
79*fd3907ccSCallum Fare   for (auto &Detail : F.getDetails()) {
80*fd3907ccSCallum Fare     OS << formatv("///    - {0}\n", Detail);
81*fd3907ccSCallum Fare   }
82*fd3907ccSCallum Fare   OS << CommentsBreak;
83*fd3907ccSCallum Fare 
84*fd3907ccSCallum Fare   // Emit analogue remarks
85*fd3907ccSCallum Fare   auto Analogues = F.getAnalogues();
86*fd3907ccSCallum Fare   if (!Analogues.empty()) {
87*fd3907ccSCallum Fare     OS << "/// @remarks\n///  _Analogues_\n";
88*fd3907ccSCallum Fare     for (auto &Analogue : Analogues) {
89*fd3907ccSCallum Fare       OS << formatv("///    - **{0}**\n", Analogue);
90*fd3907ccSCallum Fare     }
91*fd3907ccSCallum Fare     OS << CommentsBreak;
92*fd3907ccSCallum Fare   }
93*fd3907ccSCallum Fare 
94*fd3907ccSCallum Fare   OS << "/// @returns\n";
95*fd3907ccSCallum Fare   auto Returns = F.getReturns();
96*fd3907ccSCallum Fare   for (auto &Ret : Returns) {
97*fd3907ccSCallum Fare     OS << formatv("///     - ::{0}\n", Ret.getValue());
98*fd3907ccSCallum Fare     auto RetConditions = Ret.getConditions();
99*fd3907ccSCallum Fare     for (auto &RetCondition : RetConditions) {
100*fd3907ccSCallum Fare       OS << formatv("///         + {0}\n", RetCondition);
101*fd3907ccSCallum Fare     }
102*fd3907ccSCallum Fare   }
103*fd3907ccSCallum Fare 
104*fd3907ccSCallum Fare   OS << formatv("{0}_APIEXPORT {1}_result_t {0}_APICALL ", PrefixUpper,
105*fd3907ccSCallum Fare                 PrefixLower);
106*fd3907ccSCallum Fare   OS << F.getName();
107*fd3907ccSCallum Fare   OS << "(\n";
108*fd3907ccSCallum Fare   auto Params = F.getParams();
109*fd3907ccSCallum Fare   for (auto &Param : Params) {
110*fd3907ccSCallum Fare     OS << MakeParamComment(Param) << "\n";
111*fd3907ccSCallum Fare     OS << "  " << Param.getType() << " " << Param.getName();
112*fd3907ccSCallum Fare     if (Param != Params.back()) {
113*fd3907ccSCallum Fare       OS << ",\n";
114*fd3907ccSCallum Fare     } else {
115*fd3907ccSCallum Fare       OS << "\n";
116*fd3907ccSCallum Fare     }
117*fd3907ccSCallum Fare   }
118*fd3907ccSCallum Fare   OS << ");\n\n";
119*fd3907ccSCallum Fare }
120*fd3907ccSCallum Fare 
121*fd3907ccSCallum Fare static void ProcessEnum(const EnumRec &Enum, raw_ostream &OS) {
122*fd3907ccSCallum Fare   OS << CommentsHeader;
123*fd3907ccSCallum Fare   OS << formatv("/// @brief {0}\n", Enum.getDesc());
124*fd3907ccSCallum Fare   OS << formatv("typedef enum {0} {{\n", Enum.getName());
125*fd3907ccSCallum Fare 
126*fd3907ccSCallum Fare   uint32_t EtorVal = 0;
127*fd3907ccSCallum Fare   for (const auto &EnumVal : Enum.getValues()) {
128*fd3907ccSCallum Fare     if (Enum.isTyped()) {
129*fd3907ccSCallum Fare       OS << MakeComment(
130*fd3907ccSCallum Fare           formatv("[{0}] {1}", EnumVal.getTaggedType(), EnumVal.getDesc())
131*fd3907ccSCallum Fare               .str());
132*fd3907ccSCallum Fare     } else {
133*fd3907ccSCallum Fare       OS << MakeComment(EnumVal.getDesc());
134*fd3907ccSCallum Fare     }
135*fd3907ccSCallum Fare     OS << formatv(TAB_1 "{0}_{1} = {2},\n", Enum.getEnumValNamePrefix(),
136*fd3907ccSCallum Fare                   EnumVal.getName(), EtorVal++);
137*fd3907ccSCallum Fare   }
138*fd3907ccSCallum Fare 
139*fd3907ccSCallum Fare   // Add force uint32 val
140*fd3907ccSCallum Fare   OS << formatv(TAB_1 "/// @cond\n" TAB_1
141*fd3907ccSCallum Fare                       "{0}_FORCE_UINT32 = 0x7fffffff\n" TAB_1
142*fd3907ccSCallum Fare                       "/// @endcond\n\n",
143*fd3907ccSCallum Fare                 Enum.getEnumValNamePrefix());
144*fd3907ccSCallum Fare 
145*fd3907ccSCallum Fare   OS << formatv("} {0};\n", Enum.getName());
146*fd3907ccSCallum Fare }
147*fd3907ccSCallum Fare 
148*fd3907ccSCallum Fare static void ProcessStruct(const StructRec &Struct, raw_ostream &OS) {
149*fd3907ccSCallum Fare   OS << CommentsHeader;
150*fd3907ccSCallum Fare   OS << formatv("/// @brief {0}\n", Struct.getDesc());
151*fd3907ccSCallum Fare   OS << formatv("typedef struct {0} {{\n", Struct.getName());
152*fd3907ccSCallum Fare 
153*fd3907ccSCallum Fare   for (const auto &Member : Struct.getMembers()) {
154*fd3907ccSCallum Fare     OS << formatv(TAB_1 "{0} {1}; {2}", Member.getType(), Member.getName(),
155*fd3907ccSCallum Fare                   MakeComment(Member.getDesc()));
156*fd3907ccSCallum Fare   }
157*fd3907ccSCallum Fare 
158*fd3907ccSCallum Fare   OS << formatv("} {0};\n\n", Struct.getName());
159*fd3907ccSCallum Fare }
160*fd3907ccSCallum Fare 
161*fd3907ccSCallum Fare static void ProcessFuncParamStruct(const FunctionRec &Func, raw_ostream &OS) {
162*fd3907ccSCallum Fare   if (Func.getParams().size() == 0) {
163*fd3907ccSCallum Fare     return;
164*fd3907ccSCallum Fare   }
165*fd3907ccSCallum Fare 
166*fd3907ccSCallum Fare   auto FuncParamStructBegin = R"(
167*fd3907ccSCallum Fare ///////////////////////////////////////////////////////////////////////////////
168*fd3907ccSCallum Fare /// @brief Function parameters for {0}
169*fd3907ccSCallum Fare /// @details Each entry is a pointer to the parameter passed to the function;
170*fd3907ccSCallum Fare typedef struct {1} {{
171*fd3907ccSCallum Fare )";
172*fd3907ccSCallum Fare 
173*fd3907ccSCallum Fare   OS << formatv(FuncParamStructBegin, Func.getName(),
174*fd3907ccSCallum Fare                 Func.getParamStructName());
175*fd3907ccSCallum Fare   for (const auto &Param : Func.getParams()) {
176*fd3907ccSCallum Fare     OS << TAB_1 << Param.getType() << "* p" << Param.getName() << ";\n";
177*fd3907ccSCallum Fare   }
178*fd3907ccSCallum Fare   OS << formatv("} {0};\n", Func.getParamStructName());
179*fd3907ccSCallum Fare }
180*fd3907ccSCallum Fare 
181*fd3907ccSCallum Fare static void ProcessFuncWithCodeLocVariant(const FunctionRec &Func,
182*fd3907ccSCallum Fare                                           raw_ostream &OS) {
183*fd3907ccSCallum Fare 
184*fd3907ccSCallum Fare   auto FuncWithCodeLocBegin = R"(
185*fd3907ccSCallum Fare ///////////////////////////////////////////////////////////////////////////////
186*fd3907ccSCallum Fare /// @brief Variant of {0} that also sets source code location information
187*fd3907ccSCallum Fare /// @details See also ::{0}
188*fd3907ccSCallum Fare OL_APIEXPORT ol_result_t OL_APICALL {0}WithCodeLoc(
189*fd3907ccSCallum Fare )";
190*fd3907ccSCallum Fare   OS << formatv(FuncWithCodeLocBegin, Func.getName());
191*fd3907ccSCallum Fare   auto Params = Func.getParams();
192*fd3907ccSCallum Fare   for (auto &Param : Params) {
193*fd3907ccSCallum Fare     OS << "  " << Param.getType() << " " << Param.getName();
194*fd3907ccSCallum Fare     OS << ",\n";
195*fd3907ccSCallum Fare   }
196*fd3907ccSCallum Fare   OS << "ol_code_location_t *CodeLocation);\n\n";
197*fd3907ccSCallum Fare }
198*fd3907ccSCallum Fare 
199*fd3907ccSCallum Fare void EmitOffloadAPI(const RecordKeeper &Records, raw_ostream &OS) {
200*fd3907ccSCallum Fare   OS << GenericHeader;
201*fd3907ccSCallum Fare   OS << FileHeader;
202*fd3907ccSCallum Fare   // Generate main API definitions
203*fd3907ccSCallum Fare   for (auto *R : Records.getAllDerivedDefinitions("APIObject")) {
204*fd3907ccSCallum Fare     if (R->isSubClassOf("Macro")) {
205*fd3907ccSCallum Fare       ProcessMacro(MacroRec{R}, OS);
206*fd3907ccSCallum Fare     } else if (R->isSubClassOf("Typedef")) {
207*fd3907ccSCallum Fare       ProcessTypedef(TypedefRec{R}, OS);
208*fd3907ccSCallum Fare     } else if (R->isSubClassOf("Handle")) {
209*fd3907ccSCallum Fare       ProcessHandle(HandleRec{R}, OS);
210*fd3907ccSCallum Fare     } else if (R->isSubClassOf("Function")) {
211*fd3907ccSCallum Fare       ProcessFunction(FunctionRec{R}, OS);
212*fd3907ccSCallum Fare     } else if (R->isSubClassOf("Enum")) {
213*fd3907ccSCallum Fare       ProcessEnum(EnumRec{R}, OS);
214*fd3907ccSCallum Fare     } else if (R->isSubClassOf("Struct")) {
215*fd3907ccSCallum Fare       ProcessStruct(StructRec{R}, OS);
216*fd3907ccSCallum Fare     }
217*fd3907ccSCallum Fare   }
218*fd3907ccSCallum Fare 
219*fd3907ccSCallum Fare   // Generate auxiliary definitions (func param structs etc)
220*fd3907ccSCallum Fare   for (auto *R : Records.getAllDerivedDefinitions("Function")) {
221*fd3907ccSCallum Fare     ProcessFuncParamStruct(FunctionRec{R}, OS);
222*fd3907ccSCallum Fare   }
223*fd3907ccSCallum Fare 
224*fd3907ccSCallum Fare   for (auto *R : Records.getAllDerivedDefinitions("Function")) {
225*fd3907ccSCallum Fare     ProcessFuncWithCodeLocVariant(FunctionRec{R}, OS);
226*fd3907ccSCallum Fare   }
227*fd3907ccSCallum Fare 
228*fd3907ccSCallum Fare   OS << FileFooter;
229*fd3907ccSCallum Fare }
230