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