diff --git a/libc/cmake/modules/LLVMLibCObjectRules.cmake b/libc/cmake/modules/LLVMLibCObjectRules.cmake --- a/libc/cmake/modules/LLVMLibCObjectRules.cmake +++ b/libc/cmake/modules/LLVMLibCObjectRules.cmake @@ -81,6 +81,10 @@ ) get_fq_target_name(${target_name} fq_target_name) + set(entrypoint_name ${target_name}) + if(ADD_ENTRYPOINT_OBJ_NAME) + set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME}) + endif() if(ADD_ENTRYPOINT_OBJ_ALIAS) # Alias targets help one add aliases to other entrypoint object targets. @@ -109,6 +113,7 @@ set_target_properties( ${fq_target_name} PROPERTIES + "ENTRYPOINT_NAME" ${entrypoint_name} "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} "IS_ALIAS" "YES" "OBJECT_FILE" "" @@ -125,11 +130,6 @@ message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.") endif() - set(entrypoint_name ${target_name}) - if(ADD_ENTRYPOINT_OBJ_NAME) - set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME}) - endif() - set(objects_target_name "${fq_target_name}_objects") add_library( @@ -199,6 +199,7 @@ set_target_properties( ${fq_target_name} PROPERTIES + "ENTRYPOINT_NAME" ${entrypoint_name} "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} "OBJECT_FILE" "${object_file}" "OBJECT_FILE_RAW" "${object_file_raw}" @@ -255,7 +256,7 @@ # crossplatform touch. COMMAND "${CMAKE_COMMAND}" -E touch ${lint_timestamp} COMMENT "Linting... ${target_name}" - DEPENDS ${clang-tidy} ${objects_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS} + DEPENDS clang-tidy ${objects_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/libc/lib/CMakeLists.txt b/libc/config/linux/x86_64/entrypoints.txt copy from libc/lib/CMakeLists.txt copy to libc/config/linux/x86_64/entrypoints.txt --- a/libc/lib/CMakeLists.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -1,7 +1,4 @@ - -add_entrypoint_library( - llvmlibc - DEPENDS +set(LIBC_ENTRYPOINTS # assert.h entrypoints libc.src.assert.__assert_fail @@ -23,11 +20,9 @@ libc.src.stdlib.abort # string.h entrypoints - libc.src.string.bzero libc.src.string.memcpy - libc.src.string.memset - libc.src.string.strcat libc.src.string.strcpy + libc.src.string.strcat libc.src.string.strlen # sys/mman.h entrypoints @@ -45,22 +40,10 @@ libc.src.unistd.write ) -add_entrypoint_library( - llvmlibm - DEPENDS +set(LIBM_ENTRYPOINTS # math.h entrypoints libc.src.math.cosf - libc.src.math.fabs - libc.src.math.fabsf - libc.src.math.expf - libc.src.math.exp2f libc.src.math.round libc.src.math.sincosf libc.src.math.sinf -) - -add_redirector_library( - llvmlibc_redirectors - DEPENDS - round_redirector -) +) \ No newline at end of file diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt new file mode 100644 --- /dev/null +++ b/libc/config/linux/x86_64/headers.txt @@ -0,0 +1,12 @@ +set(PUBLIC_HEADERS + libc.include.assert_h + libc.include.errno + libc.include.math + libc.include.signal + libc.include.stdio + libc.include.stdlib + libc.include.sys_mman + libc.include.sys_syscall + libc.include.threads + libc.include.unistd +) diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt --- a/libc/lib/CMakeLists.txt +++ b/libc/lib/CMakeLists.txt @@ -1,62 +1,16 @@ +include("${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/${LIBC_TARGET_MACHINE}/entrypoints.txt") +include("${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/${LIBC_TARGET_MACHINE}/headers.txt") add_entrypoint_library( llvmlibc DEPENDS - # assert.h entrypoints - libc.src.assert.__assert_fail - - # errno.h entrypoints - libc.src.errno.__errno_location - - # signal.h entrypoints - libc.src.signal.raise - libc.src.signal.sigaction - libc.src.signal.sigdelset - libc.src.signal.sigaddset - libc.src.signal.sigemptyset - libc.src.signal.sigprocmask - libc.src.signal.sigfillset - libc.src.signal.signal - - # stdlib.h entrypoints - libc.src.stdlib._Exit - libc.src.stdlib.abort - - # string.h entrypoints - libc.src.string.bzero - libc.src.string.memcpy - libc.src.string.memset - libc.src.string.strcat - libc.src.string.strcpy - libc.src.string.strlen - - # sys/mman.h entrypoints - libc.src.sys.mman.mmap - libc.src.sys.mman.munmap - - # threads.h entrypoints - libc.src.threads.mtx_init - libc.src.threads.mtx_lock - libc.src.threads.mtx_unlock - libc.src.threads.thrd_create - libc.src.threads.thrd_join - - # unistd.h entrypoints - libc.src.unistd.write + ${LIBC_ENTRYPOINTS} ) add_entrypoint_library( llvmlibm DEPENDS - # math.h entrypoints - libc.src.math.cosf - libc.src.math.fabs - libc.src.math.fabsf - libc.src.math.expf - libc.src.math.exp2f - libc.src.math.round - libc.src.math.sincosf - libc.src.math.sinf + ${LIBM_ENTRYPOINTS} ) add_redirector_library( diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt --- a/libc/test/src/CMakeLists.txt +++ b/libc/test/src/CMakeLists.txt @@ -8,3 +8,91 @@ add_subdirectory(sys) add_subdirectory(threads) add_subdirectory(unistd) + +include("${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/${LIBC_TARGET_MACHINE}/entrypoints.txt") +include("${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/${LIBC_TARGET_MACHINE}/headers.txt") + +set(public_test ${CMAKE_CURRENT_BINARY_DIR}/public_integration_test.cpp) + +set(entrypoints_name_list "") +foreach(entry IN LISTS LIBC_ENTRYPOINTS LIBM_ENTRYPOINTS) + get_target_property(entry_name ${entry} "ENTRYPOINT_NAME") + list(APPEND entrypoints_name_list ${entry_name}) +endforeach() + +# TODO: Remove these when they are added to the TableGen. +list(REMOVE_ITEM entrypoints_name_list "__assert_fail" "__errno_location") +list(TRANSFORM entrypoints_name_list PREPEND "-e=") + +# Generate integration test souce code. +add_custom_command( + OUTPUT ${public_test} + COMMAND $ -o ${public_test} + ${entrypoints_name_list} + -I ${LIBC_SOURCE_DIR} + ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td + + DEPENDS ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td + libc-prototype-testgen ${PUBLIC_HEADERS} + llvmlibc llvmlibm +) + +add_executable( + public_integration_test + EXCLUDE_FROM_ALL + ${public_test} +) +# Blank out default include directories to prevent accidentally including +# system headers or our own internal headers. +set_target_properties( + public_integration_test + PROPERTIES + INCLUDE_DIRECTORIES "" +) +# Only include we need is the include for cpp::IsSame and our generated +# public headers. +target_include_directories( + public_integration_test BEFORE + PRIVATE + "${LIBC_SOURCE_DIR}/utils/CPP" + "${LIBC_BUILD_DIR}/include" +) +target_compile_options( + public_integration_test + PRIVATE + -ffreestanding +) +target_link_options( + public_integration_test + PRIVATE "-nostdlib" +) +set(library_files) +foreach(library_name IN LISTS "llvmlibc;llvmlibm") + get_target_property(library_file ${library_name} "LIBRARY_FILE") + list(APPEND library_files ${library_file}) +endforeach() + +if(COMPILER_RESOURCE_DIR AND LLVM_LIBC_ENABLE_LINTING) + add_custom_target( + public_integration_test-tidy + VERBATIM + COMMAND $ --system-headers + --checks=-*,llvmlibc-restrict-system-libc-headers + "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}" + --header-filter=.* + --warnings-as-errors=llvmlibc-* + "-config={CheckOptions: [{key: llvmlibc-restrict-system-libc-headers.Includes, value: '-*, linux/*, asm/*.h, asm-generic/*.h'}]}" + --quiet + -p ${PROJECT_BINARY_DIR} + ${public_test} + DEPENDS + clang-tidy ${public_test} + ) + add_dependencies(check-libc public_integration_test-tidy) +endif() + +target_link_libraries(public_integration_test + PRIVATE + ${library_files} +) +add_dependencies(check-libc public_integration_test) diff --git a/libc/utils/HdrGen/CMakeLists.txt b/libc/utils/HdrGen/CMakeLists.txt --- a/libc/utils/HdrGen/CMakeLists.txt +++ b/libc/utils/HdrGen/CMakeLists.txt @@ -11,3 +11,5 @@ PublicAPICommand.cpp PublicAPICommand.h ) + +add_subdirectory(PrototypeTestGen) diff --git a/libc/utils/HdrGen/PrototypeTestGen/.clang-tidy b/libc/utils/HdrGen/PrototypeTestGen/.clang-tidy new file mode 100644 --- /dev/null +++ b/libc/utils/HdrGen/PrototypeTestGen/.clang-tidy @@ -0,0 +1,3 @@ +CheckOptions: + - key: readability-identifier-naming.VariableCase + value: camelBack diff --git a/libc/utils/HdrGen/PrototypeTestGen/CMakeLists.txt b/libc/utils/HdrGen/PrototypeTestGen/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/utils/HdrGen/PrototypeTestGen/CMakeLists.txt @@ -0,0 +1,5 @@ +add_tablegen(libc-prototype-testgen llvm-libc + PrototypeTestGen.cpp + ../PublicAPICommand.cpp + ../Command.cpp +) diff --git a/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp b/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp new file mode 100644 --- /dev/null +++ b/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp @@ -0,0 +1,71 @@ +//===-- PrototypeTestGen.cpp ----------------------------------------------===// +// +// 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/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/TableGen/Main.h" +#include "llvm/TableGen/Record.h" + +namespace { + +llvm::cl::list + EntrypointNamesOption("e", llvm::cl::desc(""), + llvm::cl::OneOrMore); + +} // anonymous namespace + +bool TestGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &records) { + OS << "#include \"TypeTraits.h\"\n"; + llvm_libc::APIGenerator G(records); + for (const auto &header : G.PublicHeaders) + OS << "#include <" << header << ">\n"; + OS << '\n'; + OS << "int main() {\n"; + for (const auto &entrypoint : EntrypointNamesOption) { + auto match = G.FunctionSpecMap.find(entrypoint); + if (match == G.FunctionSpecMap.end()) { + llvm::errs() << "ERROR: entrypoint '" << entrypoint + << "' could not be found in spec in any public header\n"; + return true; + } + llvm::Record *functionSpec = match->second; + llvm::Record *retValSpec = functionSpec->getValueAsDef("Return"); + std::string returnType = + G.getTypeAsString(retValSpec->getValueAsDef("ReturnType")); + // _Noreturn is an indication for the compiler that a function + // doesn't return, and isn't a type understood by c++ templates. + if (llvm::StringRef(returnType).contains("_Noreturn")) + returnType = "void"; + + OS << " static_assert(__llvm_libc::cpp::IsSame<" << returnType << '('; + auto args = functionSpec->getValueAsListOfDefs("Args"); + for (size_t i = 0, size = args.size(); i < size; ++i) { + llvm::Record *argType = args[i]->getValueAsDef("ArgType"); + OS << G.getTypeAsString(argType); + if (i < size - 1) + OS << ", "; + } + OS << "), decltype(" << entrypoint << ")>::Value, "; + OS << '"' << entrypoint + << " prototype in TableGen does not match public header" << '"'; + OS << ");\n"; + } + + OS << '\n'; + OS << " return 0;\n"; + OS << "}\n\n"; + + return false; +} + +int main(int argc, char *argv[]) { + llvm::cl::ParseCommandLineOptions(argc, argv); + return TableGenMain(argv[0], TestGeneratorMain); +} diff --git a/libc/utils/HdrGen/PublicAPICommand.h b/libc/utils/HdrGen/PublicAPICommand.h --- a/libc/utils/HdrGen/PublicAPICommand.h +++ b/libc/utils/HdrGen/PublicAPICommand.h @@ -25,6 +25,9 @@ } // namespace llvm +using NameToRecordMapping = std::unordered_map; +using NameSet = std::unordered_set; + namespace llvm_libc { class PublicAPICommand : public Command { @@ -36,6 +39,58 @@ const Command::ErrorReporter &Reporter) const override; }; +class APIGenerator { +private: + llvm::Optional 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; + + bool isaNamedType(llvm::Record *Def); + bool isaStructType(llvm::Record *Def); + bool isaPtrType(llvm::Record *Def); + bool isaConstType(llvm::Record *Def); + bool isaRestrictedPtrType(llvm::Record *Def); + bool isaStandardSpec(llvm::Record *Def); + bool isaPublicAPI(llvm::Record *Def); + + void indexStandardSpecDef(llvm::Record *StandardSpec); + void indexPublicAPIDef(llvm::Record *PublicAPI); + void index(llvm::RecordKeeper &Records); + +public: + explicit APIGenerator(llvm::RecordKeeper &Records) : StdHeader(llvm::None) { + index(Records); + } + APIGenerator(llvm::StringRef Header, llvm::RecordKeeper &Records) + : StdHeader(Header) { + index(Records); + } + + // Mapping from names to records defining them. + NameToRecordMapping MacroSpecMap; + NameToRecordMapping TypeSpecMap; + NameToRecordMapping EnumerationSpecMap; + NameToRecordMapping FunctionSpecMap; + NameToRecordMapping MacroDefsMap; + NameToRecordMapping TypeDeclsMap; + + NameSet Structs; + NameSet Enumerations; + NameSet Functions; + NameSet PublicHeaders; + + std::string getTypeAsString(llvm::Record *TypeRecord); + + void write(llvm::raw_ostream &OS); +}; + } // namespace llvm_libc #endif // LLVM_LIBC_UTILS_HDRGEN_PUBLICAPICOMMAND_H diff --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp --- a/libc/utils/HdrGen/PublicAPICommand.cpp +++ b/libc/utils/HdrGen/PublicAPICommand.cpp @@ -57,218 +57,196 @@ } } -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; - using NameSet = std::unordered_set; +namespace llvm_libc { - // Mapping from names to records defining them. - NameToRecordMapping MacroSpecMap; - NameToRecordMapping TypeSpecMap; - NameToRecordMapping EnumerationSpecMap; - NameToRecordMapping FunctionSpecMap; - NameToRecordMapping MacroDefsMap; - NameToRecordMapping TypeDeclsMap; +bool APIGenerator::isaNamedType(llvm::Record *Def) { + return isa(Def, NamedTypeClass); +} - NameSet Structs; - NameSet Enumerations; - NameSet Functions; +bool APIGenerator::isaStructType(llvm::Record *Def) { + return isa(Def, StructClass); +} - bool isaNamedType(llvm::Record *Def) { return isa(Def, NamedTypeClass); } +bool APIGenerator::isaPtrType(llvm::Record *Def) { + return isa(Def, PtrTypeClass); +} - bool isaStructType(llvm::Record *Def) { return isa(Def, StructClass); } +bool APIGenerator::isaConstType(llvm::Record *Def) { + return isa(Def, ConstTypeClass); +} - bool isaPtrType(llvm::Record *Def) { return isa(Def, PtrTypeClass); } +bool APIGenerator::isaRestrictedPtrType(llvm::Record *Def) { + return isa(Def, RestrictedPtrTypeClass); +} - bool isaConstType(llvm::Record *Def) { return isa(Def, ConstTypeClass); } +bool APIGenerator::isaStandardSpec(llvm::Record *Def) { + return isa(Def, StandardSpecClass); +} - bool isaRestrictedPtrType(llvm::Record *Def) { - return isa(Def, RestrictedPtrTypeClass); - } +bool APIGenerator::isaPublicAPI(llvm::Record *Def) { + return isa(Def, PublicAPIClass); +} - bool isaStandardSpec(llvm::Record *Def) { - return isa(Def, StandardSpecClass); +std::string APIGenerator::getTypeAsString(llvm::Record *TypeRecord) { + if (isaNamedType(TypeRecord) || isaStructType(TypeRecord)) { + return std::string(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"); } +} - bool isaPublicAPI(llvm::Record *Def) { return isa(Def, PublicAPIClass); } - - std::string getTypeAsString(llvm::Record *TypeRecord) { - if (isaNamedType(TypeRecord) || isaStructType(TypeRecord)) { - return std::string(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 APIGenerator::indexStandardSpecDef(llvm::Record *StandardSpec) { + auto HeaderSpecList = StandardSpec->getValueAsListOfDefs("Headers"); + for (llvm::Record *HeaderSpec : HeaderSpecList) { + llvm::StringRef Header = HeaderSpec->getValueAsString("Name"); + if (!StdHeader.hasValue() || Header == StdHeader) { + PublicHeaders.emplace(Header); + auto MacroSpecList = HeaderSpec->getValueAsListOfDefs("Macros"); + // TODO: Trigger a fatal error on duplicate specs. + for (llvm::Record *MacroSpec : MacroSpecList) + MacroSpecMap[std::string(MacroSpec->getValueAsString("Name"))] = + MacroSpec; + + auto TypeSpecList = HeaderSpec->getValueAsListOfDefs("Types"); + for (llvm::Record *TypeSpec : TypeSpecList) + TypeSpecMap[std::string(TypeSpec->getValueAsString("Name"))] = TypeSpec; + + auto FunctionSpecList = HeaderSpec->getValueAsListOfDefs("Functions"); + for (llvm::Record *FunctionSpec : FunctionSpecList) { + FunctionSpecMap[std::string(FunctionSpec->getValueAsString("Name"))] = + FunctionSpec; + } - 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[std::string(MacroSpec->getValueAsString("Name"))] = - MacroSpec; - - auto TypeSpecList = HeaderSpec->getValueAsListOfDefs("Types"); - for (llvm::Record *TypeSpec : TypeSpecList) - TypeSpecMap[std::string(TypeSpec->getValueAsString("Name"))] = - TypeSpec; - - auto FunctionSpecList = HeaderSpec->getValueAsListOfDefs("Functions"); - for (llvm::Record *FunctionSpec : FunctionSpecList) { - FunctionSpecMap[std::string(FunctionSpec->getValueAsString("Name"))] = - FunctionSpec; - } - - auto EnumerationSpecList = - HeaderSpec->getValueAsListOfDefs("Enumerations"); - for (llvm::Record *EnumerationSpec : EnumerationSpecList) { - EnumerationSpecMap[std::string( - EnumerationSpec->getValueAsString("Name"))] = EnumerationSpec; - } + auto EnumerationSpecList = + HeaderSpec->getValueAsListOfDefs("Enumerations"); + for (llvm::Record *EnumerationSpec : EnumerationSpecList) { + EnumerationSpecMap[std::string( + EnumerationSpec->getValueAsString("Name"))] = EnumerationSpec; } } } +} - 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[std::string(MacroDef->getValueAsString("Name"))] = MacroDef; - - auto TypeDeclList = PublicAPI->getValueAsListOfDefs("TypeDeclarations"); - for (llvm::Record *TypeDecl : TypeDeclList) - TypeDeclsMap[std::string(TypeDecl->getValueAsString("Name"))] = TypeDecl; - - auto StructList = PublicAPI->getValueAsListOfStrings("Structs"); - for (llvm::StringRef StructName : StructList) - Structs.insert(std::string(StructName)); - - auto FunctionList = PublicAPI->getValueAsListOfStrings("Functions"); - for (llvm::StringRef FunctionName : FunctionList) - Functions.insert(std::string(FunctionName)); - - auto EnumerationList = PublicAPI->getValueAsListOfStrings("Enumerations"); - for (llvm::StringRef EnumerationName : EnumerationList) - Enumerations.insert(std::string(EnumerationName)); - } +void APIGenerator::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[std::string(MacroDef->getValueAsString("Name"))] = MacroDef; + + auto TypeDeclList = PublicAPI->getValueAsListOfDefs("TypeDeclarations"); + for (llvm::Record *TypeDecl : TypeDeclList) + TypeDeclsMap[std::string(TypeDecl->getValueAsString("Name"))] = TypeDecl; + + auto StructList = PublicAPI->getValueAsListOfStrings("Structs"); + for (llvm::StringRef StructName : StructList) + Structs.insert(std::string(StructName)); + + auto FunctionList = PublicAPI->getValueAsListOfStrings("Functions"); + for (llvm::StringRef FunctionName : FunctionList) + Functions.insert(std::string(FunctionName)); + + auto EnumerationList = PublicAPI->getValueAsListOfStrings("Enumerations"); + for (llvm::StringRef EnumerationName : EnumerationList) + Enumerations.insert(std::string(EnumerationName)); +} - 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); - } +void APIGenerator::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 (!StdHeader.hasValue() || + Def->getValueAsString("HeaderName") == StdHeader) + indexPublicAPIDef(Def); } } +} -public: - APIGenerator(llvm::StringRef Header, llvm::RecordKeeper &Records) - : StdHeader(Header) { - index(Records); - } +void APIGenerator::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"); - 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); - llvm::Record *MacroDef = Pair.second; - dedentAndWrite(MacroDef->getValueAsString("Defn"), OS); + OS << '\n'; + } - 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"); - 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); - llvm::Record *TypeDecl = Pair.second; - dedentAndWrite(TypeDecl->getValueAsString("Decl"), OS); + OS << '\n'; + } - OS << '\n'; + if (Enumerations.size() != 0) + OS << "enum {" << '\n'; + for (const auto &Name : Enumerations) { + if (EnumerationSpecMap.find(Name) == EnumerationSpecMap.end()) + llvm::PrintFatalError( + Name + " is not listed as an enumeration in any standard spec.\n"); + + llvm::Record *EnumerationSpec = EnumerationSpecMap[Name]; + OS << " " << EnumerationSpec->getValueAsString("Name"); + auto Value = EnumerationSpec->getValueAsString("Value"); + if (Value == "__default__") { + OS << ",\n"; + } else { + OS << " = " << Value << ",\n"; } - - if (Enumerations.size() != 0) - OS << "enum {" << '\n'; - for (const auto &Name : Enumerations) { - if (EnumerationSpecMap.find(Name) == EnumerationSpecMap.end()) - llvm::PrintFatalError( - Name + " is not listed as an enumeration in any standard spec.\n"); - - llvm::Record *EnumerationSpec = EnumerationSpecMap[Name]; - OS << " " << EnumerationSpec->getValueAsString("Name"); - auto Value = EnumerationSpec->getValueAsString("Value"); - if (Value == "__default__") { - OS << ",\n"; - } else { - OS << " = " << Value << ",\n"; - } + } + if (Enumerations.size() != 0) + OS << "};\n\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 << ", "; } - if (Enumerations.size() != 0) - OS << "};\n\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"; + OS << ");\n\n"; } -}; - -namespace llvm_libc { + OS << "__END_C_DECLS\n"; +} void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {}