1//===- offload-tblgen/APIGen.cpp - Tablegen backend for Offload printing --===//
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 print functions for the Offload API
10// entry point functions.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/FormatVariadic.h"
15#include "llvm/TableGen/Record.h"
16
17#include "GenCommon.hpp"
18#include "RecordTypes.hpp"
19
20using namespace llvm;
21using namespace offload::tblgen;
22
23constexpr auto PrintTypeHeader =
24 R"(///////////////////////////////////////////////////////////////////////////////
25/// @brief Print operator for the {0} type
26/// @returns llvm::raw_ostream &
27)";
28
29constexpr auto PrintTaggedEnumHeader =
30 R"(///////////////////////////////////////////////////////////////////////////////
31/// @brief Print type-tagged {0} enum value
32/// @returns llvm::raw_ostream &
33)";
34
35static void ProcessEnum(const EnumRec &Enum, raw_ostream &OS) {
36 OS << formatv(Fmt: PrintTypeHeader, Vals: Enum.getName());
37 OS << formatv(Fmt: "inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, "
38 "enum {0} value) "
39 "{{\n" TAB_1 "switch (value) {{\n",
40 Vals: Enum.getName());
41
42 for (const auto &Val : Enum.getValues()) {
43 auto Name = Enum.getEnumValNamePrefix() + "_" + Val.getName();
44 OS << formatv(TAB_1 "case {0}:\n", Vals&: Name);
45 OS << formatv(TAB_2 "os << \"{0}\";\n", Vals&: Name);
46 OS << formatv(TAB_2 "break;\n");
47 }
48
49 OS << TAB_1 "default:\n" TAB_2 "os << \"unknown enumerator\";\n" TAB_2
50 "break;\n" TAB_1 "}\n" TAB_1 "return os;\n}\n\n";
51
52 if (!Enum.isTyped()) {
53 return;
54 }
55
56 OS << formatv(Fmt: PrintTaggedEnumHeader, Vals: Enum.getName());
57
58 OS << formatv(Fmt: R"""(template <>
59inline void printTagged(llvm::raw_ostream &os, const void *ptr, {0} value, size_t size) {{
60 if (ptr == NULL) {{
61 printPtr(os, ptr);
62 return;
63 }
64
65 switch (value) {{
66)""",
67 Vals: Enum.getName());
68
69 for (const auto &Val : Enum.getValues()) {
70 auto Name = Enum.getEnumValNamePrefix() + "_" + Val.getName();
71 auto Type = Val.getTaggedType();
72 OS << formatv(TAB_1 "case {0}: {{\n", Vals&: Name);
73 // Special case for strings
74 if (Type == "char[]") {
75 OS << formatv(TAB_2 "printPtr(os, (const char*) ptr);\n");
76 } else {
77 if (Type == "void *")
78 OS << formatv(TAB_2 "void * const * const tptr = (void * "
79 "const * const)ptr;\n");
80 else
81 OS << formatv(
82 TAB_2 "const {0} * const tptr = (const {0} * const)ptr;\n", Vals&: Type);
83 // TODO: Handle other cases here
84 OS << TAB_2 "os << (const void *)tptr << \" (\";\n";
85 if (Type.ends_with(Suffix: "*")) {
86 OS << TAB_2 "os << printPtr(os, tptr);\n";
87 } else {
88 OS << TAB_2 "os << *tptr;\n";
89 }
90 OS << TAB_2 "os << \")\";\n";
91 }
92 OS << formatv(TAB_2 "break;\n" TAB_1 "}\n");
93 }
94
95 OS << TAB_1 "default:\n" TAB_2 "os << \"unknown enumerator\";\n" TAB_2
96 "break;\n" TAB_1 "}\n";
97
98 OS << "}\n";
99}
100
101static void EmitResultPrint(raw_ostream &OS) {
102 OS << R""(
103inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
104 const ol_error_struct_t *Err) {
105 if (Err == nullptr) {
106 os << "OL_SUCCESS";
107 } else {
108 os << Err->Code;
109 }
110 return os;
111}
112)"";
113}
114
115static void EmitFunctionParamStructPrint(const FunctionRec &Func,
116 raw_ostream &OS) {
117 if (Func.getParams().size() == 0) {
118 return;
119 }
120
121 OS << formatv(Fmt: R"(
122inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct {0} *params) {{
123)",
124 Vals: Func.getParamStructName());
125
126 for (const auto &Param : Func.getParams()) {
127 OS << formatv(TAB_1 "os << \".{0} = \";\n", Vals: Param.getName());
128 if (auto Range = Param.getRange()) {
129 OS << formatv(TAB_1 "os << \"{{\";\n");
130 OS << formatv(TAB_1 "for (size_t i = {0}; i < *params->p{1}; i++) {{\n",
131 Vals&: Range->first, Vals&: Range->second);
132 OS << TAB_2 "if (i > 0) {\n";
133 OS << TAB_3 " os << \", \";\n";
134 OS << TAB_2 "}\n";
135 OS << formatv(TAB_2 "printPtr(os, (*params->p{0})[i]);\n",
136 Vals: Param.getName());
137 OS << formatv(TAB_1 "}\n");
138 OS << formatv(TAB_1 "os << \"}\";\n");
139 } else if (auto TypeInfo = Param.getTypeInfo()) {
140 OS << formatv(
141 TAB_1
142 "printTagged(os, *params->p{0}, *params->p{1}, *params->p{2});\n",
143 Vals: Param.getName(), Vals&: TypeInfo->first, Vals&: TypeInfo->second);
144 } else if (Param.isPointerType() || Param.isHandleType()) {
145 OS << formatv(TAB_1 "printPtr(os, *params->p{0});\n", Vals: Param.getName());
146 } else if (Param.isFptrType()) {
147 OS << formatv(TAB_1 "os << reinterpret_cast<void*>(*params->p{0});\n",
148 Vals: Param.getName());
149 } else {
150 OS << formatv(TAB_1 "os << *params->p{0};\n", Vals: Param.getName());
151 }
152 if (Param != Func.getParams().back()) {
153 OS << TAB_1 "os << \", \";\n";
154 }
155 }
156
157 OS << TAB_1 "return os;\n}\n";
158}
159
160void ProcessStruct(const StructRec &Struct, raw_ostream &OS) {
161 if (Struct.getName() == "ol_error_struct_t") {
162 return;
163 }
164 OS << formatv(Fmt: PrintTypeHeader, Vals: Struct.getName());
165 OS << formatv(Fmt: R"(
166inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct {0} params) {{
167)",
168 Vals: Struct.getName());
169 OS << formatv(TAB_1 "os << \"(struct {0}){{\";\n", Vals: Struct.getName());
170 for (const auto &Member : Struct.getMembers()) {
171 OS << formatv(TAB_1 "os << \".{0} = \";\n", Vals: Member.getName());
172 if (Member.isPointerType() || Member.isHandleType()) {
173 OS << formatv(TAB_1 "printPtr(os, params.{0});\n", Vals: Member.getName());
174 } else {
175 OS << formatv(TAB_1 "os << params.{0};\n", Vals: Member.getName());
176 }
177 if (Member.getName() != Struct.getMembers().back().getName()) {
178 OS << TAB_1 "os << \", \";\n";
179 }
180 }
181 OS << TAB_1 "os << \"}\";\n";
182 OS << TAB_1 "return os;\n";
183 OS << "}\n";
184}
185
186void EmitOffloadPrintHeader(const RecordKeeper &Records, raw_ostream &OS) {
187 OS << GenericHeader;
188 OS << R"""(
189// Auto-generated file, do not manually edit.
190
191#pragma once
192
193#include <OffloadAPI.h>
194#include <llvm/Support/raw_ostream.h>
195
196
197template <typename T> inline ol_result_t printPtr(llvm::raw_ostream &os, const T *ptr);
198template <typename T> inline void printTagged(llvm::raw_ostream &os, const void *ptr, T value, size_t size);
199)""";
200
201 // ==========
202 OS << "template <typename T> struct is_handle : std::false_type {};\n";
203 for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Handle")) {
204 HandleRec H{R};
205 OS << formatv(Fmt: "template <> struct is_handle<{0}> : std::true_type {{};\n",
206 Vals: H.getName());
207 }
208 OS << "template <typename T> inline constexpr bool is_handle_v = "
209 "is_handle<T>::value;\n";
210 // =========
211
212 // Forward declare the operator<< overloads so their implementations can
213 // use each other.
214 OS << "\n";
215 for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Enum")) {
216 OS << formatv(Fmt: "inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, "
217 "enum {0} value);\n",
218 Vals: EnumRec{R}.getName());
219 }
220 for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Struct")) {
221 OS << formatv(Fmt: "inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, "
222 "const struct {0} param);\n",
223 Vals: StructRec{R}.getName());
224 }
225 OS << "\n";
226
227 // Create definitions
228 for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Enum")) {
229 EnumRec E{R};
230 ProcessEnum(Enum: E, OS);
231 }
232 EmitResultPrint(OS);
233
234 for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Struct")) {
235 StructRec S{R};
236 ProcessStruct(Struct: S, OS);
237 }
238
239 // Emit print functions for the function param structs
240 for (auto *R : Records.getAllDerivedDefinitions(ClassName: "Function")) {
241 EmitFunctionParamStructPrint(Func: FunctionRec{R}, OS);
242 }
243
244 OS << R"""(
245///////////////////////////////////////////////////////////////////////////////
246// @brief Print pointer value
247template <typename T> inline ol_result_t printPtr(llvm::raw_ostream &os, const T *ptr) {
248 if (ptr == nullptr) {
249 os << "nullptr";
250 } else if constexpr (std::is_pointer_v<T>) {
251 os << (const void *)(ptr) << " (";
252 printPtr(os, *ptr);
253 os << ")";
254 } else if constexpr (std::is_void_v<T> || is_handle_v<T *>) {
255 os << (const void *)ptr;
256 } else if constexpr (std::is_same_v<std::remove_cv_t< T >, char>) {
257 os << (const void *)(ptr) << " (";
258 os << ptr;
259 os << ")";
260 } else {
261 os << (const void *)(ptr) << " (";
262 os << *ptr;
263 os << ")";
264 }
265
266 return OL_SUCCESS;
267}
268 )""";
269}
270

source code of offload/tools/offload-tblgen/PrintGen.cpp