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 @@ -147,24 +147,67 @@ message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.") endif() + set(wrapper_cpp "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_wrapper.cpp") + set(wrappergen_target "${fq_target_name}__wrapper_gen") + add_custom_command( + OUTPUT ${wrapper_cpp} + COMMAND $ -I ${LIBC_SOURCE_DIR} -name ${entrypoint_name} ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td -o ${wrapper_cpp} + DEPENDS libc-wrappergen + ) + add_custom_target( + "${wrappergen_target}" + DEPENDS ${wrapper_cpp} + ) + set(wrapper_target "${fq_target_name}_wrapper_object") + add_library( + ${wrapper_target} + OBJECT + ${wrapper_cpp} + ) + target_include_directories( + ${wrapper_target} + PRIVATE + ${LIBC_BUILD_DIR}/include + ${LIBC_SOURCE_DIR} + ${LIBC_BUILD_DIR} + ) + set(mangled_name_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_mangled_name.txt") + add_custom_command( + OUTPUT ${mangled_name_file} + COMMAND $ --undefined-only --just-symbol-name $ > ${mangled_name_file} + VERBATIM + DEPENDS ${wrapper_target} + ) + set(mangled_name_target "${fq_target_name}__mangled_name_gen") + add_custom_target( + ${mangled_name_target} + DEPENDS ${mangled_name_file} + ) + set(source_with_alias "${CMAKE_CURRENT_BINARY_DIR}/__${target_name}_with_alias.cpp") + add_custom_command( + OUTPUT ${source_with_alias} + COMMAND $ -I ${LIBC_SOURCE_DIR} -name ${entrypoint_name} -alias-file ${mangled_name_file} ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td -add-alias-to ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_ENTRYPOINT_OBJ_SRCS} -o ${source_with_alias} + DEPENDS libc-wrappergen + ) + set(objects_target_name "${fq_target_name}_objects") add_library( - ${objects_target_name} + ${fq_target_name} # We want an object library as the objects will eventually get packaged into # an archive (like libc.a). OBJECT - ${ADD_ENTRYPOINT_OBJ_SRCS} + ${source_with_alias} ${ADD_ENTRYPOINT_OBJ_HDRS} ) target_compile_options( - ${objects_target_name} + ${fq_target_name} BEFORE PRIVATE -fpie ${LLVM_CXX_STD_default} -ffreestanding ) target_include_directories( - ${objects_target_name} + ${fq_target_name} PRIVATE ${LIBC_BUILD_DIR}/include ${LIBC_SOURCE_DIR} @@ -172,47 +215,50 @@ ) get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS}) add_dependencies( - ${objects_target_name} + ${fq_target_name} libc.src.__support.common ${fq_deps_list} + ${mangled_name_target} ) if(ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS) target_compile_options( - ${objects_target_name} + ${fq_target_name} PRIVATE ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS} ) endif() - set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o") - set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o") - - set(input_objects $) - add_custom_command( - OUTPUT ${object_file_raw} - DEPENDS ${input_objects} - COMMAND ${CMAKE_LINKER} -r ${input_objects} -o ${object_file_raw} - ) - - set(alias_attributes "0,function,global") - if(ADD_ENTRYPOINT_OBJ_REDIRECTED) - set(alias_attributes "${alias_attributes},hidden") - endif() - - add_custom_command( - OUTPUT ${object_file} - # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag. - DEPENDS ${object_file_raw} ${llvm-objcopy} - COMMAND $ --add-symbol - "${entrypoint_name}=.llvm.libc.entrypoint.${entrypoint_name}:${alias_attributes}" - ${object_file_raw} ${object_file} - ) + set(object_file_raw $) + set(object_file $) - add_custom_target( - ${fq_target_name} - ALL - DEPENDS ${object_file} - ) +# set(input_objects $) +# add_custom_command( +# OUTPUT ${object_file_raw} +# DEPENDS ${input_objects} +# COMMAND ${CMAKE_LINKER} -r ${input_objects} -o ${object_file_raw} +# ) +# +# set(alias_attributes "0,function,global") +# if(ADD_ENTRYPOINT_OBJ_REDIRECTED) +# set(alias_attributes "${alias_attributes},hidden") +# else() +# set(alias_attributes "${alias_attributes},weak") +# endif() +# +# add_custom_command( +# OUTPUT ${object_file} +# # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag. +# DEPENDS ${object_file_raw} ${llvm-objcopy} +# COMMAND $ --add-symbol +# "${entrypoint_name}=.llvm.libc.entrypoint.${entrypoint_name}:${alias_attributes}" +# ${object_file_raw} ${object_file} +# ) +# +# add_custom_target( +# ${fq_target_name} +# ALL +# DEPENDS ${object_file} +# ) set_target_properties( ${fq_target_name} PROPERTIES @@ -273,14 +319,14 @@ # 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 ${fq_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) add_custom_target(${fq_target_name}.__lint__ DEPENDS ${lint_timestamp}) add_dependencies(lint-libc ${fq_target_name}.__lint__) - add_dependencies(${fq_target_name} ${fq_target_name}.__lint__) + #add_dependencies(${fq_target_name} ${fq_target_name}.__lint__) endif() endfunction(add_entrypoint_object) diff --git a/libc/config/linux/platform_defs.h.inc b/libc/config/linux/platform_defs.h.inc --- a/libc/config/linux/platform_defs.h.inc +++ b/libc/config/linux/platform_defs.h.inc @@ -10,4 +10,4 @@ #define ENTRYPOINT_SECTION_ATTRIBUTE(name) \ __attribute__((section(".llvm.libc.entrypoint."#name))) -#define LLVM_LIBC_ENTRYPOINT(name) ENTRYPOINT_SECTION_ATTRIBUTE(name) name +#define LLVM_LIBC_ENTRYPOINT(name) name // ENTRYPOINT_SECTION_ATTRIBUTE(name) name diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -209,7 +209,7 @@ DEPENDS libc.utils.FPUtil.fputil COMPILE_OPTIONS - -O2 + -O3 ) add_entrypoint_object( 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,6 +10,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Main.h" @@ -19,8 +20,37 @@ 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 + 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; + + auto ErrorOrBuf = llvm::MemoryBuffer::getFile(AliaseeFile); + if (!ErrorOrBuf) + llvm::PrintFatalError("Unable to read the aliasee file " + AliaseeFile); + return std::string(ErrorOrBuf.get()->getBuffer().trim()); +} 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."); + } + llvm_libc::APIIndexer Indexer(Records); auto Iter = Indexer.FunctionSpecMap.find(FunctionName); if (Iter == Indexer.FunctionSpecMap.end()) { @@ -28,11 +58,27 @@ "' not found in any standard spec."); } - // To avoid all confusion, we include the implementation header using the - // full path (relative 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"; + 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 implementtion 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; @@ -79,14 +125,17 @@ } } - // 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"; - + if (EmitAlias) { + OS << ") [[gnu::alias(\"" << GetAliaseeName() << "\")]];\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"; + } return false; }