270 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This is a Tablegen backend that produces print functions for the Offload API10// 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} type26/// @returns llvm::raw_ostream &27)";28 29constexpr auto PrintTaggedEnumHeader =30 R"(///////////////////////////////////////////////////////////////////////////////31/// @brief Print type-tagged {0} enum value32/// @returns llvm::raw_ostream &33)";34 35static void ProcessEnum(const EnumRec &Enum, raw_ostream &OS) {36 OS << formatv(PrintTypeHeader, Enum.getName());37 OS << formatv("inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, "38 "enum {0} value) "39 "{{\n" TAB_1 "switch (value) {{\n",40 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", Name);45 OS << formatv(TAB_2 "os << \"{0}\";\n", Name);46 OS << formatv(TAB_2 "break;\n");47 }48 49 OS << TAB_1 "default:\n" TAB_2 "os << \"unknown enumerator\";\n" TAB_250 "break;\n" TAB_1 "}\n" TAB_1 "return os;\n}\n\n";51 52 if (!Enum.isTyped()) {53 return;54 }55 56 OS << formatv(PrintTaggedEnumHeader, Enum.getName());57 58 OS << formatv(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 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", Name);73 // Special case for strings74 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 else81 OS << formatv(82 TAB_2 "const {0} * const tptr = (const {0} * const)ptr;\n", Type);83 // TODO: Handle other cases here84 OS << TAB_2 "os << (const void *)tptr << \" (\";\n";85 if (Type.ends_with("*")) {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_296 "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(R"(122inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct {0} *params) {{123)",124 Func.getParamStructName());125 126 for (const auto &Param : Func.getParams()) {127 OS << formatv(TAB_1 "os << \".{0} = \";\n", 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 Range->first, 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 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_1142 "printTagged(os, *params->p{0}, *params->p{1}, *params->p{2});\n",143 Param.getName(), TypeInfo->first, TypeInfo->second);144 } else if (Param.isPointerType() || Param.isHandleType()) {145 OS << formatv(TAB_1 "printPtr(os, *params->p{0});\n", Param.getName());146 } else if (Param.isFptrType()) {147 OS << formatv(TAB_1 "os << reinterpret_cast<void*>(*params->p{0});\n",148 Param.getName());149 } else {150 OS << formatv(TAB_1 "os << *params->p{0};\n", 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(PrintTypeHeader, Struct.getName());165 OS << formatv(R"(166inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const struct {0} params) {{167)",168 Struct.getName());169 OS << formatv(TAB_1 "os << \"(struct {0}){{\";\n", Struct.getName());170 for (const auto &Member : Struct.getMembers()) {171 OS << formatv(TAB_1 "os << \".{0} = \";\n", Member.getName());172 if (Member.isPointerType() || Member.isHandleType()) {173 OS << formatv(TAB_1 "printPtr(os, params.{0});\n", Member.getName());174 } else {175 OS << formatv(TAB_1 "os << params.{0};\n", 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 once192 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("Handle")) {204 HandleRec H{R};205 OS << formatv("template <> struct is_handle<{0}> : std::true_type {{};\n",206 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 can213 // use each other.214 OS << "\n";215 for (auto *R : Records.getAllDerivedDefinitions("Enum")) {216 OS << formatv("inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, "217 "enum {0} value);\n",218 EnumRec{R}.getName());219 }220 for (auto *R : Records.getAllDerivedDefinitions("Struct")) {221 OS << formatv("inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, "222 "const struct {0} param);\n",223 StructRec{R}.getName());224 }225 OS << "\n";226 227 // Create definitions228 for (auto *R : Records.getAllDerivedDefinitions("Enum")) {229 EnumRec E{R};230 ProcessEnum(E, OS);231 }232 EmitResultPrint(OS);233 234 for (auto *R : Records.getAllDerivedDefinitions("Struct")) {235 StructRec S{R};236 ProcessStruct(S, OS);237 }238 239 // Emit print functions for the function param structs240 for (auto *R : Records.getAllDerivedDefinitions("Function")) {241 EmitFunctionParamStructPrint(FunctionRec{R}, OS);242 }243 244 OS << R"""(245///////////////////////////////////////////////////////////////////////////////246// @brief Print pointer value247template <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