1 //===-- "main" function of libc-wrappergen --------------------------------===// 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/Error.h" 14 #include "llvm/TableGen/Main.h" 15 16 #include <sstream> 17 #include <string> 18 19 llvm::cl::opt<std::string> 20 FunctionName("name", llvm::cl::desc("Name of the function to be wrapped."), 21 llvm::cl::value_desc("<function name>"), llvm::cl::Required); 22 23 static bool WrapperGenMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { 24 llvm_libc::APIIndexer Indexer(Records); 25 auto Iter = Indexer.FunctionSpecMap.find(FunctionName); 26 if (Iter == Indexer.FunctionSpecMap.end()) { 27 llvm::PrintFatalError("Function '" + FunctionName + 28 "' not found in any standard spec."); 29 } 30 31 // To avoid all confusion, we include the implementation header using the 32 // full path (relative the libc directory.) 33 std::string Header = Indexer.FunctionToHeaderMap[FunctionName]; 34 auto RelPath = llvm::StringRef(Header).drop_back(2); // Drop the ".h" suffix. 35 OS << "#include \"src/" << RelPath << "/" << FunctionName << ".h\"\n"; 36 37 auto &NameSpecPair = *Iter; 38 llvm::Record *FunctionSpec = NameSpecPair.second; 39 llvm::Record *RetValSpec = FunctionSpec->getValueAsDef("Return"); 40 llvm::Record *ReturnType = RetValSpec->getValueAsDef("ReturnType"); 41 std::string ReturnTypeString = Indexer.getTypeAsString(ReturnType); 42 bool ShouldReturn = true; 43 // We are generating C wrappers in C++ code. So, we should convert the C 44 // _Noreturn to the C++ [[noreturn]]. 45 llvm::StringRef NR("_Noreturn "); // Note the space after _Noreturn 46 llvm::StringRef RT(ReturnTypeString); 47 if (RT.startswith(NR)) { 48 RT = RT.drop_front(NR.size() - 1); // - 1 because of the space. 49 ReturnTypeString = std::string("[[noreturn]]") + std::string(RT); 50 ShouldReturn = false; 51 } 52 OS << "extern \"C\" " << ReturnTypeString << " " << FunctionName << "("; 53 54 auto ArgsList = FunctionSpec->getValueAsListOfDefs("Args"); 55 std::stringstream CallArgs; 56 std::string ArgPrefix("__arg"); 57 for (size_t i = 0; i < ArgsList.size(); ++i) { 58 llvm::Record *ArgType = ArgsList[i]->getValueAsDef("ArgType"); 59 auto TypeName = Indexer.getTypeAsString(ArgType); 60 61 if (TypeName.compare("void") == 0) { 62 if (ArgsList.size() == 1) { 63 break; 64 } else { 65 // the reason this is a fatal error is that a void argument means this 66 // function has no arguments; multiple copies of no arguments is an 67 // error. 68 llvm::PrintFatalError( 69 "The specification for function " + FunctionName + 70 " lists other arguments along with a void argument."); 71 } 72 } 73 74 OS << TypeName << " " << ArgPrefix << i; 75 CallArgs << ArgPrefix << i; 76 if (i < ArgsList.size() - 1) { 77 OS << ", "; 78 CallArgs << ", "; 79 } 80 } 81 82 // TODO: Arg types of the C++ implementation functions need not 83 // match the standard types. Either handle such differences here, or 84 // avoid such a thing in the implementations. 85 OS << ") {\n" 86 << " " << (ShouldReturn ? "return " : "") 87 << "__llvm_libc::" << FunctionName << "(" << CallArgs.str() << ");\n" 88 << "}\n"; 89 90 return false; 91 } 92 93 int main(int argc, char *argv[]) { 94 llvm::cl::ParseCommandLineOptions(argc, argv); 95 return TableGenMain(argv[0], WrapperGenMain); 96 } 97