1 //===-- PrototypeTestGen.cpp ----------------------------------------------===//
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 #include "utils/LibcTableGenUtil/APIIndexer.h"
10
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Support/CommandLine.h"
13 #include "llvm/TableGen/Main.h"
14 #include "llvm/TableGen/Record.h"
15
16 namespace {
17
18 llvm::cl::list<std::string>
19 EntrypointNamesOption("e", llvm::cl::desc("<list of entrypoints>"),
20 llvm::cl::OneOrMore);
21
22 } // anonymous namespace
23
TestGeneratorMain(llvm::raw_ostream & OS,llvm::RecordKeeper & records)24 bool TestGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &records) {
25 OS << "#include \"TypeTraits.h\"\n";
26 llvm_libc::APIIndexer G(records);
27 std::unordered_set<std::string> headerFileSet;
28 for (const auto &entrypoint : EntrypointNamesOption) {
29 auto match = G.FunctionToHeaderMap.find(entrypoint);
30 if (match == G.FunctionToHeaderMap.end()) {
31 auto objectMatch = G.ObjectToHeaderMap.find(entrypoint);
32 if (objectMatch != G.ObjectToHeaderMap.end()) {
33 headerFileSet.insert(objectMatch->second);
34 continue;
35 }
36
37 llvm::errs() << "ERROR: entrypoint '" << entrypoint
38 << "' could not be found in spec in any public header\n";
39 return true;
40 }
41 headerFileSet.insert(match->second);
42 }
43 for (const auto &header : headerFileSet)
44 OS << "#include <" << header << ">\n";
45
46 OS << '\n';
47
48 OS << "int main() {\n";
49 for (const auto &entrypoint : EntrypointNamesOption) {
50 auto match = G.FunctionSpecMap.find(entrypoint);
51 if (match == G.FunctionSpecMap.end()) {
52 auto objectMatch = G.ObjectSpecMap.find(entrypoint);
53 if (objectMatch != G.ObjectSpecMap.end()) {
54 auto entrypointPtr = entrypoint + "_ptr";
55 llvm::Record *objectSpec = G.ObjectSpecMap[entrypoint];
56 auto objectType = objectSpec->getValueAsString("Type");
57 // We just make sure that the global object is present.
58 OS << " " << objectType << " *" << entrypointPtr << " = &"
59 << entrypoint << ";\n";
60 OS << " ++" << entrypointPtr << ";\n"; // To avoid unused var warning.
61 continue;
62 }
63 llvm::errs() << "ERROR: entrypoint '" << entrypoint
64 << "' could not be found in spec in any public header\n";
65 return true;
66 }
67 llvm::Record *functionSpec = match->second;
68 llvm::Record *retValSpec = functionSpec->getValueAsDef("Return");
69 std::string returnType =
70 G.getTypeAsString(retValSpec->getValueAsDef("ReturnType"));
71 // _Noreturn is an indication for the compiler that a function
72 // doesn't return, and isn't a type understood by c++ templates.
73 if (llvm::StringRef(returnType).contains("_Noreturn"))
74 returnType = "void";
75
76 OS << " static_assert(__llvm_libc::cpp::IsSame<" << returnType << '(';
77 auto args = functionSpec->getValueAsListOfDefs("Args");
78 for (size_t i = 0, size = args.size(); i < size; ++i) {
79 llvm::Record *argType = args[i]->getValueAsDef("ArgType");
80 OS << G.getTypeAsString(argType);
81 if (i < size - 1)
82 OS << ", ";
83 }
84 OS << "), decltype(" << entrypoint << ")>::Value, ";
85 OS << '"' << entrypoint
86 << " prototype in TableGen does not match public header" << '"';
87 OS << ");\n";
88 }
89
90 OS << '\n';
91 OS << " return 0;\n";
92 OS << "}\n\n";
93
94 // We provide dummy malloc and free implementations to support the case
95 // when LLVM libc does to include them.
96 OS << "void *malloc(size_t) { return nullptr; }\n";
97 OS << "void free(void *) {}\n";
98
99 return false;
100 }
101
main(int argc,char * argv[])102 int main(int argc, char *argv[]) {
103 llvm::cl::ParseCommandLineOptions(argc, argv);
104 return TableGenMain(argv[0], TestGeneratorMain);
105 }
106