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