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
16namespace {
17
18llvm::cl::list<std::string>
19 EntrypointNamesOption("e", llvm::cl::desc("<list of entrypoints>"),
20 llvm::cl::OneOrMore);
21
22} // anonymous namespace
23
24bool 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> headerFileSet;
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 &header : 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
102int main(int argc, char *argv[]) {
103 llvm::cl::ParseCommandLineOptions(argc, argv);
104 return TableGenMain(argv[0], TestGeneratorMain);
105}
106

source code of libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp