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