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