| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| def StdC : StandardSpec<"stdc"> { | ||
| PtrType VoidPtr = PtrType<VoidType>; | ||
| ConstType ConstVoidPtr = ConstType<VoidPtr>; | ||
| RestrictedPtrType VoidRestrictedPtr = RestrictedPtrType<VoidType>; | ||
| ConstType ConstVoidRestrictedPtr = ConstType<VoidRestrictedPtr>; | ||
|
|
||
| PtrType CharPtr = PtrType<CharType>; | ||
| ConstType ConstCharPtr = ConstType<CharPtr>; | ||
| RestrictedPtrType CharRestrictedPtr = RestrictedPtrType<CharType>; | ||
| ConstType ConstCharRestrictedPtr = ConstType<CharRestrictedPtr>; | ||
|
|
||
| NamedType SizeTType = NamedType<"size_t">; | ||
|
|
||
| HeaderSpec String = HeaderSpec< | ||
| "string.h", | ||
| [ | ||
| Macro<"NULL">, | ||
| ], | ||
| [ | ||
| SizeTType, | ||
| ], | ||
| [ | ||
| FunctionSpec< | ||
| "memcpy", | ||
| RetValSpec<VoidPtr>, | ||
| [ArgSpec<VoidRestrictedPtr>, | ||
| ArgSpec<ConstVoidRestrictedPtr>, | ||
| ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "memmove", | ||
| RetValSpec<VoidPtr>, | ||
| [ArgSpec<VoidPtr>, ArgSpec<ConstVoidPtr>, ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "memcmp", | ||
| RetValSpec<IntType>, | ||
| [ArgSpec<ConstVoidPtr>, ArgSpec<ConstVoidPtr>, ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "memchr", | ||
| RetValSpec<VoidPtr>, | ||
| [ArgSpec<ConstVoidPtr>, ArgSpec<IntType>, ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "memset", | ||
| RetValSpec<VoidPtr>, | ||
| [ArgSpec<VoidPtr>, ArgSpec<IntType>, ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strcpy", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<CharRestrictedPtr>, ArgSpec<ConstCharRestrictedPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strncpy", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<CharRestrictedPtr>, | ||
| ArgSpec<ConstCharRestrictedPtr>, | ||
| ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strcat", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<CharRestrictedPtr>, ArgSpec<ConstCharRestrictedPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strncat", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<CharPtr>, ArgSpec<ConstCharPtr>, ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strcmp", | ||
| RetValSpec<IntType>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strcoll", | ||
| RetValSpec<IntType>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strncmp", | ||
| RetValSpec<IntType>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>, ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strxfrm", | ||
| RetValSpec<SizeTType>, | ||
| [ArgSpec<CharRestrictedPtr>, | ||
| ArgSpec<ConstCharRestrictedPtr>, | ||
| ArgSpec<SizeTType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strchr", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<IntType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strcspn", | ||
| RetValSpec<SizeTType>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strpbrk", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strrchr", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<IntType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strspn", | ||
| RetValSpec<SizeTType>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strstr", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strtok", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<CharRestrictedPtr>, ArgSpec<ConstCharRestrictedPtr>] | ||
| >, | ||
| FunctionSpec< | ||
| "strerror", | ||
| RetValSpec<CharPtr>, | ||
| [ArgSpec<IntType>] | ||
| >, | ||
| FunctionSpec< | ||
| "strlen", | ||
| RetValSpec<SizeTType>, | ||
| [ArgSpec<ConstCharPtr>] | ||
| >, | ||
| ] | ||
| >; | ||
|
|
||
| HeaderSpec Math = HeaderSpec< | ||
| "math.h", | ||
| [], // Macros | ||
| [ | ||
| NamedType<"float_t">, | ||
| NamedType<"double_t">, | ||
| ], | ||
| [ | ||
| FunctionSpec<"acos", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>, | ||
| FunctionSpec<"acosl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>, | ||
| ] | ||
| >; | ||
|
|
||
| HeaderSpec StdIO = HeaderSpec< | ||
| "stdio.h", | ||
| [], // Macros | ||
| [ // Types | ||
| SizeTType, | ||
| ], | ||
| [ | ||
| FunctionSpec< | ||
| "snprintf", | ||
| RetValSpec<IntType>, | ||
| [ArgSpec<CharPtr>, | ||
| ArgSpec<SizeTType>, | ||
| ArgSpec<ConstCharRestrictedPtr>, | ||
| ArgSpec<VarArgType>] | ||
| >, | ||
| ] | ||
| >; | ||
|
|
||
| let Headers = [ | ||
| Math, | ||
| String, | ||
| StdIO, | ||
| ]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| add_subdirectory(HdrGen) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| add_tablegen(libc-hdrgen llvm-libc | ||
| Command.h | ||
| Generator.cpp | ||
| Generator.h | ||
| IncludeFileCommand.cpp | ||
| IncludeFileCommand.h | ||
| Main.cpp | ||
| PublicAPICommand.cpp | ||
| PublicAPICommand.h | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| //===-------- Base class for header generation commands ---------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_UTILS_HDRGEN_COMMAND_H | ||
| #define LLVM_LIBC_UTILS_HDRGEN_COMMAND_H | ||
|
|
||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/ADT/Twine.h" | ||
| #include "llvm/Support/SourceMgr.h" | ||
|
|
||
| #include <cstdlib> | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class raw_ostream; | ||
| class RecordKeeper; | ||
|
|
||
| } // namespace llvm | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| typedef llvm::SmallVector<llvm::StringRef, 4> ArgVector; | ||
|
|
||
| class Command { | ||
| public: | ||
| class ErrorReporter { | ||
| llvm::SMLoc Loc; | ||
| const llvm::SourceMgr &SrcMgr; | ||
|
|
||
| public: | ||
| ErrorReporter(llvm::SMLoc L, llvm::SourceMgr &SM) : Loc(L), SrcMgr(SM) {} | ||
|
|
||
| void printFatalError(llvm::Twine Msg) const { | ||
| SrcMgr.PrintMessage(Loc, llvm::SourceMgr::DK_Error, Msg); | ||
| std::exit(1); | ||
| } | ||
| }; | ||
|
|
||
| virtual void run(llvm::raw_ostream &OS, const ArgVector &Args, | ||
| llvm::StringRef StdHeader, llvm::RecordKeeper &Records, | ||
| const ErrorReporter &Reporter) const = 0; | ||
| }; | ||
|
|
||
| } // namespace llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_UTILS_HDRGEN_COMMAND_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| //===---- Implementation of the main header generation class -----*- C++ -*===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Generator.h" | ||
|
|
||
| #include "IncludeFileCommand.h" | ||
| #include "PublicAPICommand.h" | ||
|
|
||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/Support/MemoryBuffer.h" | ||
| #include "llvm/Support/SourceMgr.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| #include <cstdlib> | ||
| #include <memory> | ||
|
|
||
| static const char CommandPrefix[] = "%%"; | ||
| static const size_t CommandPrefixSize = llvm::StringRef(CommandPrefix).size(); | ||
|
|
||
| static const char CommentPrefix[] = "<!>"; | ||
|
|
||
| static const char ParamNamePrefix[] = "${"; | ||
| static const size_t ParamNamePrefixSize = | ||
| llvm::StringRef(ParamNamePrefix).size(); | ||
| static const char ParamNameSuffix[] = "}"; | ||
| static const size_t ParamNameSuffixSize = | ||
| llvm::StringRef(ParamNameSuffix).size(); | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| Command *Generator::getCommandHandler(llvm::StringRef CommandName) { | ||
| if (CommandName == IncludeFileCommand::Name) { | ||
| if (!IncludeFileCmd) | ||
| IncludeFileCmd = std::make_unique<IncludeFileCommand>(); | ||
| return IncludeFileCmd.get(); | ||
| } else if (CommandName == PublicAPICommand::Name) { | ||
| if (!PublicAPICmd) | ||
| PublicAPICmd = std::make_unique<PublicAPICommand>(); | ||
| return PublicAPICmd.get(); | ||
| } else { | ||
| return nullptr; | ||
| } | ||
| } | ||
|
|
||
| void Generator::parseCommandArgs(llvm::StringRef ArgStr, ArgVector &Args) { | ||
| if (!ArgStr.contains(',') && ArgStr.trim(' ').trim('\t').size() == 0) { | ||
| // If it is just space between the parenthesis | ||
| return; | ||
| } | ||
|
|
||
| ArgStr.split(Args, ","); | ||
| for (llvm::StringRef &A : Args) { | ||
| A = A.trim(' '); | ||
| if (A.startswith(ParamNamePrefix) && A.endswith(ParamNameSuffix)) { | ||
| A = A.drop_front(ParamNamePrefixSize).drop_back(ParamNameSuffixSize); | ||
| A = ArgMap[A]; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void Generator::generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { | ||
| auto DefFileBuffer = llvm::MemoryBuffer::getFile(HeaderDefFile); | ||
| if (!DefFileBuffer) { | ||
| llvm::errs() << "Unable to open " << HeaderDefFile << ".\n"; | ||
| std::exit(1); | ||
| } | ||
| llvm::SourceMgr SrcMgr; | ||
| unsigned DefFileID = SrcMgr.AddNewSourceBuffer( | ||
| std::move(DefFileBuffer.get()), llvm::SMLoc::getFromPointer(nullptr)); | ||
|
|
||
| llvm::StringRef Content = SrcMgr.getMemoryBuffer(DefFileID)->getBuffer(); | ||
| while (true) { | ||
| std::pair<llvm::StringRef, llvm::StringRef> P = Content.split('\n'); | ||
| Content = P.second; | ||
|
|
||
| llvm::StringRef Line = P.first.trim(' '); | ||
| if (Line.startswith(CommandPrefix)) { | ||
| Line = Line.drop_front(CommandPrefixSize); | ||
|
|
||
| P = Line.split("("); | ||
| if (P.second.empty() || P.second[P.second.size() - 1] != ')') { | ||
| SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(P.second.data()), | ||
| llvm::SourceMgr::DK_Error, | ||
| "Command argument list should begin with '(' " | ||
| "and end with ')'."); | ||
| std::exit(1); | ||
| } | ||
| llvm::StringRef CommandName = P.first; | ||
| Command *Cmd = getCommandHandler(CommandName); | ||
| if (Cmd == nullptr) { | ||
| SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(CommandName.data()), | ||
| llvm::SourceMgr::DK_Error, | ||
| "Unknown command '%%" + CommandName + "'."); | ||
| std::exit(1); | ||
| } | ||
|
|
||
| llvm::StringRef ArgStr = P.second.drop_back(1); | ||
| ArgVector Args; | ||
| parseCommandArgs(ArgStr, Args); | ||
|
|
||
| Command::ErrorReporter Reporter( | ||
| llvm::SMLoc::getFromPointer(CommandName.data()), SrcMgr); | ||
| Cmd->run(OS, Args, StdHeader, Records, Reporter); | ||
| } else if (!Line.startswith(CommentPrefix)) { | ||
| // There is no comment or command on this line so we just write it as is. | ||
| OS << P.first << "\n"; | ||
| } | ||
|
|
||
| if (P.second.empty()) | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| } // namespace llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| //===------------- - The main header generation class -----------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_UTILS_HDRGEN_GENERATOR_H | ||
| #define LLVM_LIBC_UTILS_HDRGEN_GENERATOR_H | ||
|
|
||
| #include "Command.h" | ||
|
|
||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
|
|
||
| #include <memory> | ||
| #include <string> | ||
| #include <unordered_map> | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class raw_ostream; | ||
| class RecordKeeper; | ||
|
|
||
| } // namespace llvm | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| class Command; | ||
|
|
||
| class Generator { | ||
| llvm::StringRef HeaderDefFile; | ||
| llvm::StringRef StdHeader; | ||
| std::unordered_map<std::string, std::string> &ArgMap; | ||
|
|
||
| std::unique_ptr<Command> IncludeFileCmd; | ||
| std::unique_ptr<Command> PublicAPICmd; | ||
|
|
||
| Command *getCommandHandler(llvm::StringRef CommandName); | ||
|
|
||
| void parseCommandArgs(llvm::StringRef ArgStr, ArgVector &Args); | ||
|
|
||
| void printError(llvm::StringRef Msg); | ||
|
|
||
| public: | ||
| Generator(const std::string &DefFile, const std::string &Header, | ||
| std::unordered_map<std::string, std::string> &Map) | ||
| : HeaderDefFile(DefFile), StdHeader(Header), ArgMap(Map) {} | ||
|
|
||
| void generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records); | ||
| }; | ||
|
|
||
| } // namespace llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_UTILS_HDRGEN_GENERATOR_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| //===----------- Implementation of IncludeFileCommand -----------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "IncludeFileCommand.h" | ||
|
|
||
| #include "llvm/Support/MemoryBuffer.h" | ||
| #include "llvm/Support/SourceMgr.h" | ||
|
|
||
| #include <cstdlib> | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| const char IncludeFileCommand::Name[] = "include_file"; | ||
|
|
||
| void IncludeFileCommand::run(llvm::raw_ostream &OS, const ArgVector &Args, | ||
| llvm::StringRef StdHeader, | ||
| llvm::RecordKeeper &Records, | ||
| const Command::ErrorReporter &Reporter) const { | ||
| if (Args.size() != 1) { | ||
| Reporter.printFatalError( | ||
| "%%include_file command takes exactly 1 argument."); | ||
| } | ||
|
|
||
| llvm::StringRef IncludeFile = Args[0]; | ||
| auto Buffer = llvm::MemoryBuffer::getFileAsStream(IncludeFile); | ||
| if (!Buffer) | ||
| Reporter.printFatalError(llvm::StringRef("Unable to open ") + IncludeFile); | ||
|
|
||
| llvm::StringRef Content = Buffer.get()->getBuffer(); | ||
|
|
||
| // If the included file has %%begin() command listed, then we want to write | ||
| // only the content after the begin command. | ||
| // TODO: The way the content is split below does not allow space within the | ||
| // the parentheses and, before and after the command. This probably is too | ||
| // strict and should be relaxed. | ||
| auto P = Content.split("\n%%begin()\n"); | ||
| if (P.second.empty()) { | ||
| // There was no %%begin in the content. | ||
| OS << P.first; | ||
| } else { | ||
| OS << P.second; | ||
| } | ||
| } | ||
|
|
||
| } // namespace llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| //===-------- Class which implements the %%include_file command -*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_UTILS_HDRGEN_INCLUDE_COMMAND_H | ||
| #define LLVM_LIBC_UTILS_HDRGEN_INCLUDE_COMMAND_H | ||
|
|
||
| #include "Command.h" | ||
|
|
||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
|
|
||
| #include <string> | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| class IncludeFileCommand : public Command { | ||
| public: | ||
| static const char Name[]; | ||
|
|
||
| void run(llvm::raw_ostream &OS, const ArgVector &Args, | ||
| llvm::StringRef StdHeader, llvm::RecordKeeper &Records, | ||
| const Command::ErrorReporter &Reporter) const override; | ||
| }; | ||
|
|
||
| } // namespace llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_UTILS_HDRGEN_INCLUDE_COMMAND_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| //===---------------- "main" function of libc-hdrgen ------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Generator.h" | ||
|
|
||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/Support/CommandLine.h" | ||
| #include "llvm/TableGen/Main.h" | ||
|
|
||
| #include <string> | ||
| #include <unordered_map> | ||
|
|
||
| namespace { | ||
|
|
||
| llvm::cl::opt<std::string> | ||
| HeaderDefFile("def", llvm::cl::desc("Path to the .h.def file."), | ||
| llvm::cl::value_desc("<filename>"), llvm::cl::Required); | ||
| llvm::cl::opt<std::string> StandardHeader( | ||
| "header", | ||
| llvm::cl::desc("The standard header file which is to be generated."), | ||
| llvm::cl::value_desc("<header file>")); | ||
| llvm::cl::list<std::string> ReplacementValues( | ||
| "args", llvm::cl::desc("Command seperated <argument name>=<value> pairs."), | ||
| llvm::cl::value_desc("<name=value>[,name=value]")); | ||
|
|
||
| void ParseArgValuePairs(std::unordered_map<std::string, std::string> &Map) { | ||
| for (std::string &R : ReplacementValues) { | ||
| auto Pair = llvm::StringRef(R).split('='); | ||
| Map[Pair.first] = Pair.second; | ||
| } | ||
| } | ||
|
|
||
| } // anonymous namespace | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| bool HeaderGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { | ||
| std::unordered_map<std::string, std::string> ArgMap; | ||
| ParseArgValuePairs(ArgMap); | ||
| Generator G(HeaderDefFile, StandardHeader, ArgMap); | ||
| G.generate(OS, Records); | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| } // namespace llvm_libc | ||
|
|
||
| int main(int argc, char *argv[]) { | ||
| llvm::cl::ParseCommandLineOptions(argc, argv); | ||
| return TableGenMain(argv[0], &llvm_libc::HeaderGeneratorMain); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,255 @@ | ||
| //===--------------- Implementation of PublicAPICommand ----------*-C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "PublicAPICommand.h" | ||
|
|
||
| #include "llvm/ADT/StringExtras.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/Support/SourceMgr.h" | ||
| #include "llvm/TableGen/Error.h" | ||
| #include "llvm/TableGen/Record.h" | ||
|
|
||
| static const char NamedTypeClassName[] = "NamedType"; | ||
| static const char PtrTypeClassName[] = "PtrType"; | ||
| static const char RestrictedPtrTypeClassName[] = "RestrictedPtrType"; | ||
| static const char ConstTypeClassName[] = "ConstType"; | ||
| static const char StructTypeClassName[] = "Struct"; | ||
|
|
||
| static const char StandardSpecClassName[] = "StandardSpec"; | ||
| static const char PublicAPIClassName[] = "PublicAPI"; | ||
|
|
||
| static bool isa(llvm::Record *Def, llvm::Record *TypeClass) { | ||
| llvm::RecordRecTy *RecordType = Def->getType(); | ||
| llvm::ArrayRef<llvm::Record *> Classes = RecordType->getClasses(); | ||
| // We want exact types. That is, we don't want the classes listed in | ||
| // spec.td to be subclassed. Hence, we do not want the record |Def| | ||
| // to be of more than one class type.. | ||
| if (Classes.size() != 1) | ||
| return false; | ||
| return Classes[0] == TypeClass; | ||
| } | ||
|
|
||
| // Text blocks for macro definitions and type decls can be indented to | ||
| // suit the surrounding tablegen listing. We need to dedent such blocks | ||
| // before writing them out. | ||
| static void dedentAndWrite(llvm::StringRef Text, llvm::raw_ostream &OS) { | ||
| llvm::SmallVector<llvm::StringRef, 10> Lines; | ||
| llvm::SplitString(Text, Lines, "\n"); | ||
| size_t shortest_indent = 1024; | ||
| for (llvm::StringRef L : Lines) { | ||
| llvm::StringRef Indent = L.take_while([](char c) { return c == ' '; }); | ||
| size_t IndentSize = Indent.size(); | ||
| if (Indent.size() == L.size()) { | ||
| // Line is all spaces so no point noting the indent. | ||
| continue; | ||
| } | ||
| if (IndentSize < shortest_indent) | ||
| shortest_indent = IndentSize; | ||
| } | ||
| for (llvm::StringRef L : Lines) { | ||
| if (L.size() >= shortest_indent) | ||
| OS << L.drop_front(shortest_indent) << '\n'; | ||
| } | ||
| } | ||
|
|
||
| class APIGenerator { | ||
| llvm::StringRef StdHeader; | ||
|
|
||
| // TableGen classes in spec.td. | ||
| llvm::Record *NamedTypeClass; | ||
| llvm::Record *PtrTypeClass; | ||
| llvm::Record *RestrictedPtrTypeClass; | ||
| llvm::Record *ConstTypeClass; | ||
| llvm::Record *StructClass; | ||
| llvm::Record *StandardSpecClass; | ||
| llvm::Record *PublicAPIClass; | ||
|
|
||
| using NameToRecordMapping = std::unordered_map<std::string, llvm::Record *>; | ||
| using NameSet = std::unordered_set<std::string>; | ||
|
|
||
| // Mapping from names to records defining them. | ||
| NameToRecordMapping MacroSpecMap; | ||
| NameToRecordMapping TypeSpecMap; | ||
| NameToRecordMapping FunctionSpecMap; | ||
| NameToRecordMapping MacroDefsMap; | ||
| NameToRecordMapping TypeDeclsMap; | ||
|
|
||
| NameSet Structs; | ||
| NameSet Functions; | ||
|
|
||
| bool isaNamedType(llvm::Record *Def) { return isa(Def, NamedTypeClass); } | ||
|
|
||
| bool isaStructType(llvm::Record *Def) { return isa(Def, StructClass); } | ||
|
|
||
| bool isaPtrType(llvm::Record *Def) { return isa(Def, PtrTypeClass); } | ||
|
|
||
| bool isaConstType(llvm::Record *Def) { return isa(Def, ConstTypeClass); } | ||
|
|
||
| bool isaRestrictedPtrType(llvm::Record *Def) { | ||
| return isa(Def, RestrictedPtrTypeClass); | ||
| } | ||
|
|
||
| bool isaStandardSpec(llvm::Record *Def) { | ||
| return isa(Def, StandardSpecClass); | ||
| } | ||
|
|
||
| bool isaPublicAPI(llvm::Record *Def) { return isa(Def, PublicAPIClass); } | ||
|
|
||
| std::string getTypeAsString(llvm::Record *TypeRecord) { | ||
| if (isaNamedType(TypeRecord) || isaStructType(TypeRecord)) { | ||
| return TypeRecord->getValueAsString("Name"); | ||
| } else if (isaPtrType(TypeRecord)) { | ||
| return getTypeAsString(TypeRecord->getValueAsDef("PointeeType")) + " *"; | ||
| } else if (isaConstType(TypeRecord)) { | ||
| return std::string("const ") + | ||
| getTypeAsString(TypeRecord->getValueAsDef("UnqualifiedType")); | ||
| } else if (isaRestrictedPtrType(TypeRecord)) { | ||
| return getTypeAsString(TypeRecord->getValueAsDef("PointeeType")) + | ||
| " *__restrict"; | ||
| } else { | ||
| llvm::PrintFatalError(TypeRecord->getLoc(), "Invalid type.\n"); | ||
| } | ||
| } | ||
|
|
||
| void indexStandardSpecDef(llvm::Record *StandardSpec) { | ||
| auto HeaderSpecList = StandardSpec->getValueAsListOfDefs("Headers"); | ||
| for (llvm::Record *HeaderSpec : HeaderSpecList) { | ||
| if (HeaderSpec->getValueAsString("Name") == StdHeader) { | ||
| auto MacroSpecList = HeaderSpec->getValueAsListOfDefs("Macros"); | ||
| // TODO: Trigger a fatal error on duplicate specs. | ||
| for (llvm::Record *MacroSpec : MacroSpecList) | ||
| MacroSpecMap[MacroSpec->getValueAsString("Name")] = MacroSpec; | ||
|
|
||
| auto TypeSpecList = HeaderSpec->getValueAsListOfDefs("Types"); | ||
| for (llvm::Record *TypeSpec : TypeSpecList) | ||
| TypeSpecMap[TypeSpec->getValueAsString("Name")] = TypeSpec; | ||
|
|
||
| auto FunctionSpecList = HeaderSpec->getValueAsListOfDefs("Functions"); | ||
| for (llvm::Record *FunctionSpec : FunctionSpecList) { | ||
| FunctionSpecMap[FunctionSpec->getValueAsString("Name")] = | ||
| FunctionSpec; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void indexPublicAPIDef(llvm::Record *PublicAPI) { | ||
| // While indexing the public API, we do not check if any of the entities | ||
| // requested is from an included standard. Such a check is done while | ||
| // generating the API. | ||
| auto MacroDefList = PublicAPI->getValueAsListOfDefs("Macros"); | ||
| for (llvm::Record *MacroDef : MacroDefList) | ||
| MacroDefsMap[MacroDef->getValueAsString("Name")] = MacroDef; | ||
|
|
||
| auto TypeDeclList = PublicAPI->getValueAsListOfDefs("TypeDeclarations"); | ||
| for (llvm::Record *TypeDecl : TypeDeclList) | ||
| TypeDeclsMap[TypeDecl->getValueAsString("Name")] = TypeDecl; | ||
|
|
||
| auto StructList = PublicAPI->getValueAsListOfStrings("Structs"); | ||
| for (llvm::StringRef StructName : StructList) | ||
| Structs.insert(StructName); | ||
|
|
||
| auto FunctionList = PublicAPI->getValueAsListOfStrings("Functions"); | ||
| for (llvm::StringRef FunctionName : FunctionList) | ||
| Functions.insert(FunctionName); | ||
| } | ||
|
|
||
| void index(llvm::RecordKeeper &Records) { | ||
| NamedTypeClass = Records.getClass(NamedTypeClassName); | ||
| PtrTypeClass = Records.getClass(PtrTypeClassName); | ||
| RestrictedPtrTypeClass = Records.getClass(RestrictedPtrTypeClassName); | ||
| StructClass = Records.getClass(StructTypeClassName); | ||
| ConstTypeClass = Records.getClass(ConstTypeClassName); | ||
| StandardSpecClass = Records.getClass(StandardSpecClassName); | ||
| PublicAPIClass = Records.getClass(PublicAPIClassName); | ||
|
|
||
| const auto &DefsMap = Records.getDefs(); | ||
| for (auto &Pair : DefsMap) { | ||
| llvm::Record *Def = Pair.second.get(); | ||
| if (isaStandardSpec(Def)) | ||
| indexStandardSpecDef(Def); | ||
| if (isaPublicAPI(Def)) { | ||
| if (Def->getValueAsString("HeaderName") == StdHeader) | ||
| indexPublicAPIDef(Def); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public: | ||
| APIGenerator(llvm::StringRef Header, llvm::RecordKeeper &Records) | ||
| : StdHeader(Header) { | ||
| index(Records); | ||
| } | ||
|
|
||
| void write(llvm::raw_ostream &OS) { | ||
| for (auto &Pair : MacroDefsMap) { | ||
| const std::string &Name = Pair.first; | ||
| if (MacroSpecMap.find(Name) == MacroSpecMap.end()) | ||
| llvm::PrintFatalError(Name + " not found in any standard spec.\n"); | ||
|
|
||
| llvm::Record *MacroDef = Pair.second; | ||
| dedentAndWrite(MacroDef->getValueAsString("Defn"), OS); | ||
|
|
||
| OS << '\n'; | ||
| } | ||
|
|
||
| for (auto &Pair : TypeDeclsMap) { | ||
| const std::string &Name = Pair.first; | ||
| if (TypeSpecMap.find(Name) == TypeSpecMap.end()) | ||
| llvm::PrintFatalError(Name + " not found in any standard spec.\n"); | ||
|
|
||
| llvm::Record *TypeDecl = Pair.second; | ||
| dedentAndWrite(TypeDecl->getValueAsString("Decl"), OS); | ||
|
|
||
| OS << '\n'; | ||
| } | ||
|
|
||
| OS << "__BEGIN_C_DECLS\n\n"; | ||
| for (auto &Name : Functions) { | ||
| if (FunctionSpecMap.find(Name) == FunctionSpecMap.end()) | ||
| llvm::PrintFatalError(Name + " not found in any standard spec.\n"); | ||
|
|
||
| llvm::Record *FunctionSpec = FunctionSpecMap[Name]; | ||
| llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return"); | ||
| llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType"); | ||
|
|
||
| OS << getTypeAsString(ReturnType) << " " << Name << "("; | ||
|
|
||
| auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args"); | ||
| for (size_t i = 0; i < ArgsList.size(); ++i) { | ||
| llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType"); | ||
| OS << getTypeAsString(ArgType); | ||
| if (i < ArgsList.size() - 1) | ||
| OS << ", "; | ||
| } | ||
|
|
||
| OS << ");\n\n"; | ||
| } | ||
| OS << "__END_C_DECLS\n"; | ||
| } | ||
| }; | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {} | ||
|
|
||
| const char PublicAPICommand::Name[] = "public_api"; | ||
|
|
||
| void PublicAPICommand::run(llvm::raw_ostream &OS, const ArgVector &Args, | ||
| llvm::StringRef StdHeader, | ||
| llvm::RecordKeeper &Records, | ||
| const Command::ErrorReporter &Reporter) const { | ||
| if (Args.size() != 0) { | ||
| Reporter.printFatalError("public_api command does not take any arguments."); | ||
| } | ||
|
|
||
| APIGenerator G(StdHeader, Records); | ||
| G.write(OS); | ||
| } | ||
|
|
||
| } // namespace llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| //===---------- Implementation of PublicAPICommand --------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Command.h" | ||
|
|
||
| #include "llvm/ADT/StringRef.h" | ||
|
|
||
| #include <string> | ||
| #include <unordered_map> | ||
| #include <unordered_set> | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class raw_ostream; | ||
| class Record; | ||
| class RecordKeeper; | ||
|
|
||
| } // namespace llvm | ||
|
|
||
| namespace llvm_libc { | ||
|
|
||
| class PublicAPICommand : public Command { | ||
| public: | ||
| static const char Name[]; | ||
|
|
||
| void run(llvm::raw_ostream &OS, const ArgVector &Args, | ||
| llvm::StringRef StdHeader, llvm::RecordKeeper &Records, | ||
| const Command::ErrorReporter &Reporter) const override; | ||
| }; | ||
|
|
||
| } // namespace llvm_libc |