diff --git a/libc/test/utils/tools/WrapperGen/wrappergen_test.cpp b/libc/test/utils/tools/WrapperGen/wrappergen_test.cpp --- a/libc/test/utils/tools/WrapperGen/wrappergen_test.cpp +++ b/libc/test/utils/tools/WrapperGen/wrappergen_test.cpp @@ -72,8 +72,12 @@ llvm::None, llvm::StringRef(STDOutFile.get().TmpName), llvm::StringRef(STDErrFile.get().TmpName)}; - llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg), - llvm::StringRef(APIArg), "--name", "strlen"}; + llvm::StringRef ArgV[] = {ProgPath, + llvm::StringRef(IncludeArg), + llvm::StringRef(APIArg), + "--gen-wrapper", + "--name", + "strlen"}; int ExitCode = llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects); @@ -90,8 +94,12 @@ llvm::None, llvm::StringRef(STDOutFile.get().TmpName), llvm::StringRef(STDErrFile.get().TmpName)}; - llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg), - llvm::StringRef(APIArg), "--name", "strlen"}; + llvm::StringRef ArgV[] = {ProgPath, + llvm::StringRef(IncludeArg), + llvm::StringRef(APIArg), + "--gen-wrapper", + "--name", + "strlen"}; int ExitCode = llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects); @@ -116,7 +124,7 @@ // would break this test. } -TEST_F(WrapperGenTest, RunWrapperGenOnStrlenWithAliasee) { +TEST_F(WrapperGenTest, GenAliasForStrlen) { llvm::Optional Redirects[] = { llvm::None, llvm::StringRef(STDOutFile.get().TmpName), llvm::StringRef(STDErrFile.get().TmpName)}; @@ -124,8 +132,9 @@ llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg), llvm::StringRef(APIArg), - "--aliasee", - "STRLEN_ALIAS", + "--gen-alias", + "--mangled-name", + "__llvm_libc_strlen_mangled_name", "--name", "strlen"}; @@ -142,35 +151,38 @@ auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName); std::string STDOutOutput = STDOutOrError.get()->getBuffer().str(); - ASSERT_EQ(STDOutOutput, "extern \"C\" size_t strlen(const char * __arg0) " - "__attribute__((alias(\"STRLEN_ALIAS\")));\n"); + ASSERT_EQ(STDOutOutput, + "extern \"C\" size_t strlen(const char * __arg0) " + "__attribute__((alias(\"__llvm_libc_strlen_mangled_name\")));\n"); // TODO:(michaelrj) Figure out how to make this output comparison // less brittle. Currently it's just comparing the output of the program // to an exact string, this means that even a small formatting change // would break this test. } -TEST_F(WrapperGenTest, DeclStrlenAliasUsingAliaseeFile) { +TEST_F(WrapperGenTest, DeclStrlenAliasUsingMangledNameFile) { llvm::Optional Redirects[] = { llvm::None, llvm::StringRef(STDOutFile.get().TmpName), llvm::StringRef(STDErrFile.get().TmpName)}; - const char *AliaseeFileContent = "abc\nxyz__llvm_libcSTRLEN_ALIAS\nijk\n"; - llvm::SmallVector AliaseeFilePath; - auto AliaseeFileCreateError = llvm::sys::fs::createUniqueFile( - "libc-wrappergen-test-aliasee-file-%%-%%-%%-%%.txt", AliaseeFilePath); - ASSERT_FALSE(AliaseeFileCreateError); - auto AliaseeFileWriteError = llvm::writeFileAtomically( + const char *MangledNameFileContent = + "abc\nxyz__llvm_libc_strlen_mangled_name\nijk\n"; + llvm::SmallVector MangledNameFilePath; + auto MangledNameFileCreateError = llvm::sys::fs::createUniqueFile( + "libc-wrappergen-test-aliasee-file-%%-%%-%%-%%.txt", MangledNameFilePath); + ASSERT_FALSE(MangledNameFileCreateError); + auto MangledNameFileWriteError = llvm::writeFileAtomically( "libc-wrappergen-temp-test-aliasee-file-%%-%%-%%-%%.txt", - llvm::StringRef(AliaseeFilePath.data()), - llvm::StringRef(AliaseeFileContent)); - ASSERT_FALSE(AliaseeFileWriteError); + llvm::StringRef(MangledNameFilePath.data()), + llvm::StringRef(MangledNameFileContent)); + ASSERT_FALSE(MangledNameFileWriteError); llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg), llvm::StringRef(APIArg), - "--aliasee-file", - llvm::StringRef(AliaseeFilePath.data()), + "--gen-alias", + "--mangled-name-file", + llvm::StringRef(MangledNameFilePath.data()), "--name", "strlen"}; @@ -187,9 +199,10 @@ auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName); std::string STDOutOutput = STDOutOrError.get()->getBuffer().str(); - ASSERT_EQ(STDOutOutput, - "extern \"C\" size_t strlen(const char * __arg0) " - "__attribute__((alias(\"xyz__llvm_libcSTRLEN_ALIAS\")));\n"); + ASSERT_EQ( + STDOutOutput, + "extern \"C\" size_t strlen(const char * __arg0) " + "__attribute__((alias(\"xyz__llvm_libc_strlen_mangled_name\")));\n"); } ///////////////////////////////////////////////////////////////////// @@ -199,8 +212,7 @@ // return errors ///////////////////////////////////////////////////////////////////// -TEST_F(WrapperGenTest, - RunWrapperGenOnStrlenWithAliaseeAndAliaseeFileWhichIsError) { +TEST_F(WrapperGenTest, RunWrapperGenOnStrlenWithMangledNameAndMangledNameFile) { llvm::Optional Redirects[] = { llvm::None, llvm::StringRef(STDOutFile.get().TmpName), llvm::StringRef(STDErrFile.get().TmpName)}; @@ -208,10 +220,11 @@ llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg), llvm::StringRef(APIArg), - "--aliasee", - "STRLEN_ALIAS", - "--aliasee-file", - "STRLEN_ALIAS_FILE", + "--gen-alias", + "--mangled-name", + "__llvm_libc_strlen_mangled_name", + "--mangled-name-file", + "non-existant-mangled-name-file.txt", "--name", "strlen"}; @@ -223,8 +236,9 @@ auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName); std::string STDErrOutput = STDErrOrError.get()->getBuffer().str(); - ASSERT_EQ(STDErrOutput, "error: The options 'aliasee' and 'aliasee-file' " - "cannot be specified simultaniously.\n"); + ASSERT_EQ(STDErrOutput, + "error: The options 'mangled-name' and 'mangled-name-file' " + "cannot be specified simultaniously.\n"); auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName); std::string STDOutOutput = STDOutOrError.get()->getBuffer().str(); @@ -239,8 +253,12 @@ llvm::StringRef BadFuncName = "FAKE_TEST_FUNC"; - llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg), - llvm::StringRef(APIArg), "--name", BadFuncName}; + llvm::StringRef ArgV[] = {ProgPath, + llvm::StringRef(IncludeArg), + llvm::StringRef(APIArg), + "--gen-wrapper", + "--name", + BadFuncName}; int ExitCode = llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects); @@ -260,17 +278,21 @@ ASSERT_EQ(STDOutOutput, ""); } -TEST_F(WrapperGenTest, RunWrapperGenOnStrlenWithBadAliaseeFile) { +TEST_F(WrapperGenTest, RunWrapperGenOnStrlenWithBadMangledNameFile) { llvm::Optional Redirects[] = { llvm::None, llvm::StringRef(STDOutFile.get().TmpName), llvm::StringRef(STDErrFile.get().TmpName)}; - llvm::StringRef BadAliaseeFileName = "FILE_THAT_DOESNT_EXIST.txt"; + llvm::StringRef BadMangledNameFileName = "FILE_THAT_DOESNT_EXIST.txt"; - llvm::StringRef ArgV[] = { - ProgPath, llvm::StringRef(IncludeArg), llvm::StringRef(APIArg), - "--aliasee-file", BadAliaseeFileName, "--name", - "strlen"}; + llvm::StringRef ArgV[] = {ProgPath, + llvm::StringRef(IncludeArg), + llvm::StringRef(APIArg), + "--gen-alias", + "--mangled-name-file", + BadMangledNameFileName, + "--name", + "strlen"}; int ExitCode = llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects); @@ -280,8 +302,8 @@ auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName); std::string STDErrOutput = STDErrOrError.get()->getBuffer().str(); - ASSERT_EQ(STDErrOutput, ("error: Unable to read the aliasee file " + - BadAliaseeFileName + "\n") + ASSERT_EQ(STDErrOutput, ("error: Unable to read the mangled name file " + + BadMangledNameFileName + "\n") .str()); auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName); @@ -290,21 +312,23 @@ ASSERT_EQ(STDOutOutput, ""); } -TEST_F(WrapperGenTest, RunWithAliaseeFileMissingLLVMLibcName) { +TEST_F(WrapperGenTest, RunWithMangledNameFileMissingLLVMLibcName) { llvm::Optional Redirects[] = { llvm::None, llvm::StringRef(STDOutFile.get().TmpName), llvm::StringRef(STDErrFile.get().TmpName)}; - llvm::SmallVector AliaseeFilePath; - auto AliaseeFileCreateError = llvm::sys::fs::createUniqueFile( - "libc-wrappergen-test-aliasee-file-%%-%%-%%-%%.txt", AliaseeFilePath); - ASSERT_FALSE(AliaseeFileCreateError); + llvm::SmallVector MangledNameFilePath; + auto MangledNameFileCreateError = llvm::sys::fs::createUniqueFile( + "libc-wrappergen-test-mangled-name-file-%%-%%-%%-%%.txt", + MangledNameFilePath); + ASSERT_FALSE(MangledNameFileCreateError); llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg), llvm::StringRef(APIArg), - "--aliasee-file", - llvm::StringRef(AliaseeFilePath.data()), + "--gen-alias", + "--mangled-name-file", + llvm::StringRef(MangledNameFilePath.data()), "--name", "strlen"}; @@ -317,6 +341,6 @@ std::string STDErrOutput = STDErrOrError.get()->getBuffer().str(); ASSERT_EQ(STDErrOutput, ("error: Did not find an LLVM libc mangled name in " + - AliaseeFilePath + "\n") + MangledNameFilePath + "\n") .str()); } diff --git a/libc/utils/tools/WrapperGen/Main.cpp b/libc/utils/tools/WrapperGen/Main.cpp --- a/libc/utils/tools/WrapperGen/Main.cpp +++ b/libc/utils/tools/WrapperGen/Main.cpp @@ -10,38 +10,68 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Main.h" +#include +#include #include #include +llvm::cl::opt + GenWrapper("gen-wrapper", + llvm::cl::desc("Generate a C wrapper for .")); +llvm::cl::opt GenAlias("gen-alias", + llvm::cl::desc("Generate a C alias for .")); + llvm::cl::opt FunctionName("name", llvm::cl::desc("Name of the function to be wrapped."), llvm::cl::value_desc(""), llvm::cl::Required); -llvm::cl::opt - AliaseeString("aliasee", - llvm::cl::desc("Declare as an alias to this C name."), - llvm::cl::value_desc("")); -llvm::cl::opt - AliaseeFile("aliasee-file", - llvm::cl::desc("Declare as an alias to the C name read from " - "this file."), - llvm::cl::value_desc("")); +llvm::cl::opt MangledNameString( + "mangled-name", llvm::cl::desc("Declare as an alias to this mangled name."), + llvm::cl::value_desc("")); +llvm::cl::opt MangledNameFile( + "mangled-name-file", + llvm::cl::desc("Declare as an alias to the C name read from " + "this file."), + llvm::cl::value_desc("")); llvm::cl::opt AppendToFile("append-to-file", llvm::cl::desc("Append the generated content at the end of " "the contents of this file."), llvm::cl::value_desc("")); -static std::string GetAliaseeName() { - if (AliaseeString.size() > 0) - return AliaseeString; +void validateOpts() { + int ActionCount = 0; + if (GenWrapper) + ++ActionCount; + if (GenAlias) + ++ActionCount; + if (ActionCount != 1) { + llvm::PrintFatalError("Exactly one of {--gen-wrapper, --gen-alias} " + "should be specified"); + } + if (!MangledNameString.empty() && !MangledNameFile.empty()) { + llvm::PrintFatalError("The options 'mangled-name' and 'mangled-name-file' " + "cannot be specified simultaneously."); + } +} + +static std::string getMangledName() { + if (!MangledNameString.empty()) + return MangledNameString; - auto ErrorOrBuf = llvm::MemoryBuffer::getFile(AliaseeFile); + if (MangledNameFile.empty()) + llvm::PrintFatalError("At least one of --mangled-name or " + "--mangled-name-file should be specified."); + + auto ErrorOrBuf = llvm::MemoryBuffer::getFile(MangledNameFile); if (!ErrorOrBuf) - llvm::PrintFatalError("Unable to read the aliasee file " + AliaseeFile); + llvm::PrintFatalError("Unable to read the mangled name file " + + MangledNameFile); llvm::StringRef FileContent = ErrorOrBuf.get()->getBuffer().trim(); llvm::SmallVector Lines; FileContent.split(Lines, '\n'); @@ -50,47 +80,32 @@ return std::string(L); } llvm::PrintFatalError("Did not find an LLVM libc mangled name in " + - AliaseeFile); + MangledNameFile); return std::string(); } -static bool WrapperGenMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { - if (!AliaseeString.empty() && !AliaseeFile.empty()) { - llvm::PrintFatalError("The options 'aliasee' and 'aliasee-file' cannot " - "be specified simultaniously."); +void writeAppendToFile(llvm::raw_ostream &OS) { + auto ErrorOrBuf = llvm::MemoryBuffer::getFile(AppendToFile); + if (!ErrorOrBuf) { + llvm::PrintFatalError("Unable to read the file '" + AppendToFile + + "' to append to."); } + OS << ErrorOrBuf.get()->getBuffer().trim() << '\n'; +} - llvm_libc::APIIndexer Indexer(Records); +llvm::Record *getFunctionSpec(const llvm_libc::APIIndexer &Indexer) { auto Iter = Indexer.FunctionSpecMap.find(FunctionName); if (Iter == Indexer.FunctionSpecMap.end()) { llvm::PrintFatalError("Function '" + FunctionName + "' not found in any standard spec."); } - - bool EmitAlias = !(AliaseeString.empty() && AliaseeFile.empty()); - - if (!EmitAlias && AppendToFile.empty()) { - // If not emitting an alias, and not appending to another file, - // we should include the implementation header to ensure the wrapper - // compiles. - // To avoid all confusion, we include the implementation header using the - // full path (relative to the libc directory.) - std::string Header = Indexer.FunctionToHeaderMap[FunctionName]; - auto RelPath = - llvm::StringRef(Header).drop_back(2); // Drop the ".h" suffix. - OS << "#include \"src/" << RelPath << "/" << FunctionName << ".h\"\n"; - } - if (!AppendToFile.empty()) { - auto ErrorOrBuf = llvm::MemoryBuffer::getFile(AppendToFile); - if (!ErrorOrBuf) { - llvm::PrintFatalError("Unable to read the file '" + AppendToFile + - "' to append to."); - } - OS << ErrorOrBuf.get()->getBuffer().trim() << '\n'; - } - auto &NameSpecPair = *Iter; - llvm::Record *FunctionSpec = NameSpecPair.second; + return NameSpecPair.second; +} + +std::pair writeFunctionHeader(llvm_libc::APIIndexer &Indexer, + llvm::Record *FunctionSpec, + llvm::raw_ostream &OS) { llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return"); llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType"); std::string ReturnTypeString = Indexer.getTypeAsString(ReturnType); @@ -133,22 +148,51 @@ CallArgs << ", "; } } + return make_pair(CallArgs.str(), ShouldReturn); +} - if (EmitAlias) { - OS << ") __attribute__((alias(\"" << GetAliaseeName() << "\")));\n"; +static bool generateWrapper(llvm::raw_ostream &OS, + llvm::RecordKeeper &Records) { + llvm_libc::APIIndexer Indexer(Records); + llvm::Record *FunctionSpec = getFunctionSpec(Indexer); + if (AppendToFile.empty()) { + std::string Header = Indexer.FunctionToHeaderMap[FunctionName]; + auto RelPath = + llvm::StringRef(Header).drop_back(2); // Drop the ".h" suffix. + OS << "#include \"src/" << RelPath << "/" << FunctionName << ".h\"\n"; } else { - // TODO: Arg types of the C++ implementation functions need not - // match the standard types. Either handle such differences here, or - // avoid such a thing in the implementations. - OS << ") {\n" - << " " << (ShouldReturn ? "return " : "") - << "__llvm_libc::" << FunctionName << "(" << CallArgs.str() << ");\n" - << "}\n"; + writeAppendToFile(OS); } + auto Pair = writeFunctionHeader(Indexer, FunctionSpec, OS); + OS << ") {\n" + << " " << (Pair.second ? "return " : "") + << "__llvm_libc::" << FunctionName << "(" << Pair.first << ");\n" + << "}\n"; + return false; +} + +static bool generateAlias(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { + if (!AppendToFile.empty()) + writeAppendToFile(OS); + llvm_libc::APIIndexer Indexer(Records); + llvm::Record *FunctionSpec = getFunctionSpec(Indexer); + auto Pair = writeFunctionHeader(Indexer, FunctionSpec, OS); + OS << ") __attribute__((alias(\"" << getMangledName() << "\")));\n"; return false; } +static bool wrapperGenMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { + validateOpts(); + + if (GenWrapper) + return generateWrapper(OS, Records); + if (GenAlias) + return generateAlias(OS, Records); + + __builtin_unreachable(); +} + int main(int argc, char *argv[]) { llvm::cl::ParseCommandLineOptions(argc, argv); - return TableGenMain(argv[0], WrapperGenMain); + return TableGenMain(argv[0], wrapperGenMain); }