diff --git a/libc/cmake/modules/LLVMLibCHeaderRules.cmake b/libc/cmake/modules/LLVMLibCHeaderRules.cmake --- a/libc/cmake/modules/LLVMLibCHeaderRules.cmake +++ b/libc/cmake/modules/LLVMLibCHeaderRules.cmake @@ -118,11 +118,17 @@ set(hdrgen_exe ${LIBC_TABLEGEN_EXE}) set(hdrgen_deps "${LIBC_TABLEGEN_EXE};${LIBC_TABLEGEN_TARGET}") endif() + option(LIBC_GPU_OFFLOAD_HEADERS "Create offloading headers for the GPU" ON) + if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND LIBC_GPU_OFFLOAD_HEADERS) + set(offloading "--offloading") + else() + set(offloading "") + endif() add_custom_command( OUTPUT ${out_file} COMMAND ${hdrgen_exe} -o ${out_file} --header ${ADD_GEN_HDR_GEN_HDR} --def ${in_file} ${replacement_params} -I ${LIBC_SOURCE_DIR} - ${ENTRYPOINT_NAME_LIST_ARG} + ${ENTRYPOINT_NAME_LIST_ARG} ${offloading} ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/libc/config/gpu/api.td b/libc/config/gpu/api.td --- a/libc/config/gpu/api.td +++ b/libc/config/gpu/api.td @@ -12,6 +12,11 @@ "size_t", "__atexithandler_t", ]; + + // The offloading wrapper headers need this type defined. + let ExtraDefn = [{ + #include + }]; } def FenvAPI: PublicAPI<"fenv.h"> { diff --git a/libc/config/public_api.td b/libc/config/public_api.td --- a/libc/config/public_api.td +++ b/libc/config/public_api.td @@ -23,4 +23,5 @@ list Structs = []; list Functions = []; list Objects = []; + string ExtraDefn = ""; } diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -500,6 +500,7 @@ DEPENDS .llvm_libc_common_h .llvm-libc-types.rpc_opcodes_t + .llvm-libc-macros.gpu_macros ) endif() diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -172,3 +172,9 @@ HDR wchar-macros.h ) + +add_header( + gpu_macros + HDR + gpu-macros.h +) diff --git a/libc/include/llvm-libc-macros/gpu-macros.h b/libc/include/llvm-libc-macros/gpu-macros.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-macros/gpu-macros.h @@ -0,0 +1,61 @@ +//===-- GPU definitions for LLVM-libc public offloading header files ------===// +// +// 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_MACROS_GPU_MACROS_H +#define LLVM_LIBC_MACROS_GPU_MACROS_H + +#undef __OFFLOADING +#if defined(_OPENMP) || defined(__HIP__) || defined(__CUDA__) +#define __OFFLOADING +#endif + +#undef __BEGIN_OPENMP_DECLS +#ifdef _OPENMP +#define __BEGIN_OPENMP_DECLS _Pragma("omp begin declare target"); +#else +#define __BEGIN_OPENMP_DECLS +#endif + +#undef __END_OPENMP_DECLS +#ifdef _OPENMP +#define __END_OPENMP_DECLS _Pragma("omp end declare target"); +#else +#define __END_OPENMP_DECLS +#endif + +#undef __DEVICE +#if defined(__HIP__) || defined(__CUDA__) +#define __DEVICE __attribute__((device)) +#else +#define __DEVICE +#endif + +#ifdef __OFFLOADING +#undef __NOEXCEPT +#define __NOEXCEPT +#endif + +#ifdef __cplusplus + +#undef __BEGIN_C_DECLS +#define __BEGIN_C_DECLS extern "C" { + +#undef __END_C_DECLS +#define __END_C_DECLS } + +#else + +#undef __BEGIN_C_DECLS +#define __BEGIN_C_DECLS + +#undef __END_C_DECLS +#define __END_C_DECLS + +#endif + +#endif // LLVM_LIBC_MACROS_GPU_MACROS_H diff --git a/libc/utils/HdrGen/BeginCommand.h b/libc/utils/HdrGen/BeginCommand.h --- a/libc/utils/HdrGen/BeginCommand.h +++ b/libc/utils/HdrGen/BeginCommand.h @@ -19,9 +19,13 @@ namespace llvm_libc { class BeginCommand : public Command { + const bool Offloading; + public: static const char Name[]; + BeginCommand(bool Offloading) : Offloading(Offloading) {} + void run(llvm::raw_ostream &OS, const ArgVector &Args, llvm::StringRef StdHeader, llvm::RecordKeeper &Records, const Command::ErrorReporter &Reporter) const override; diff --git a/libc/utils/HdrGen/BeginCommand.cpp b/libc/utils/HdrGen/BeginCommand.cpp --- a/libc/utils/HdrGen/BeginCommand.cpp +++ b/libc/utils/HdrGen/BeginCommand.cpp @@ -22,6 +22,17 @@ const Command::ErrorReporter &Reporter) const { if (Args.size() != 0) Reporter.printFatalError("%%begin command does not take any arguments."); + + if (!Offloading) + return; + + // Offloading languages must have the same headers included from both the host + // and device compilations. For this reason, if the user has an offloading + // language enabled we need to defer to the system header. + OS << "#include \n\n" + << "#ifdef __OFFLOADING\n" + << "#include_next <" << StdHeader << ">\n" + << "#else\n"; } } // namespace llvm_libc diff --git a/libc/utils/HdrGen/EndCommand.h b/libc/utils/HdrGen/EndCommand.h --- a/libc/utils/HdrGen/EndCommand.h +++ b/libc/utils/HdrGen/EndCommand.h @@ -19,9 +19,13 @@ namespace llvm_libc { class EndCommand : public Command { + const bool Offloading; + public: static const char Name[]; + EndCommand(bool Offloading) : Offloading(Offloading) {} + void run(llvm::raw_ostream &OS, const ArgVector &Args, llvm::StringRef StdHeader, llvm::RecordKeeper &Records, const Command::ErrorReporter &Reporter) const override; diff --git a/libc/utils/HdrGen/EndCommand.cpp b/libc/utils/HdrGen/EndCommand.cpp --- a/libc/utils/HdrGen/EndCommand.cpp +++ b/libc/utils/HdrGen/EndCommand.cpp @@ -22,6 +22,11 @@ const Command::ErrorReporter &Reporter) const { if (Args.size() != 0) Reporter.printFatalError("%%end command does not take any arguments."); + + if (!Offloading) + return; + + OS << "#endif\n"; } } // namespace llvm_libc diff --git a/libc/utils/HdrGen/Generator.h b/libc/utils/HdrGen/Generator.h --- a/libc/utils/HdrGen/Generator.h +++ b/libc/utils/HdrGen/Generator.h @@ -33,6 +33,7 @@ llvm::StringRef HeaderDefFile; const std::vector &EntrypointNameList; llvm::StringRef StdHeader; + const bool Offloading; std::unordered_map &ArgMap; std::unique_ptr BeginCmd; @@ -48,10 +49,10 @@ public: Generator(const std::string &DefFile, const std::vector &EN, - const std::string &Header, + const std::string &Header, const bool Offloading, std::unordered_map &Map) : HeaderDefFile(DefFile), EntrypointNameList(EN), StdHeader(Header), - ArgMap(Map) {} + Offloading(Offloading), ArgMap(Map) {} void generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records); }; diff --git a/libc/utils/HdrGen/Generator.cpp b/libc/utils/HdrGen/Generator.cpp --- a/libc/utils/HdrGen/Generator.cpp +++ b/libc/utils/HdrGen/Generator.cpp @@ -38,11 +38,11 @@ Command *Generator::getCommandHandler(llvm::StringRef CommandName) { if (CommandName == BeginCommand::Name) { if (!BeginCmd) - BeginCmd = std::make_unique(); + BeginCmd = std::make_unique(Offloading); return BeginCmd.get(); } else if (CommandName == EndCommand::Name) { if (!EndCmd) - EndCmd = std::make_unique(); + EndCmd = std::make_unique(Offloading); return EndCmd.get(); } else if (CommandName == IncludeFileCommand::Name) { if (!IncludeFileCmd) @@ -50,7 +50,8 @@ return IncludeFileCmd.get(); } else if (CommandName == PublicAPICommand::Name) { if (!PublicAPICmd) - PublicAPICmd = std::make_unique(EntrypointNameList); + PublicAPICmd = + std::make_unique(EntrypointNameList, Offloading); return PublicAPICmd.get(); } else { return nullptr; diff --git a/libc/utils/HdrGen/Main.cpp b/libc/utils/HdrGen/Main.cpp --- a/libc/utils/HdrGen/Main.cpp +++ b/libc/utils/HdrGen/Main.cpp @@ -32,6 +32,9 @@ llvm::cl::list ReplacementValues( "args", llvm::cl::desc("Command separated = pairs."), llvm::cl::value_desc("[,name=value]")); +llvm::cl::opt Offloading( + "offloading", + llvm::cl::desc("Create headers suitable for offloading languages")); void ParseArgValuePairs(std::unordered_map &Map) { for (std::string &R : ReplacementValues) { @@ -47,7 +50,8 @@ bool HeaderGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { std::unordered_map ArgMap; ParseArgValuePairs(ArgMap); - Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, ArgMap); + Generator G(HeaderDefFile, EntrypointNamesOption, StandardHeader, Offloading, + ArgMap); G.generate(OS, Records); return false; 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 @@ -29,11 +29,14 @@ private: const std::vector &EntrypointNameList; + const bool Offloading; + public: static const char Name[]; - PublicAPICommand(const std::vector &EntrypointNames) - : EntrypointNameList(EntrypointNames) {} + PublicAPICommand(const std::vector &EntrypointNames, + const bool Offloading) + : EntrypointNameList(EntrypointNames), Offloading(Offloading) {} void run(llvm::raw_ostream &OS, const ArgVector &Args, llvm::StringRef StdHeader, llvm::RecordKeeper &Records, 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 @@ -48,8 +48,11 @@ namespace llvm_libc { void writeAPIFromIndex(APIIndexer &G, - std::vector EntrypointNameList, - llvm::raw_ostream &OS) { + const std::vector &EntrypointNameList, + const bool Offloading, llvm::raw_ostream &OS) { + if (Offloading) + OS << "#ifndef __OFFLOADING\n"; + for (auto &Pair : G.MacroDefsMap) { const std::string &Name = Pair.first; if (G.MacroSpecMap.find(Name) == G.MacroSpecMap.end()) @@ -87,6 +90,16 @@ if (G.Enumerations.size() != 0) OS << "};\n\n"; + if (Offloading) { + if (!G.ExtraDefn.empty()) { + OS << "#else\n"; + dedentAndWrite(G.ExtraDefn, OS); + } + OS << "#endif\n\n"; + } + + if (Offloading) + OS << "__BEGIN_OPENMP_DECLS\n"; OS << "__BEGIN_C_DECLS\n\n"; for (auto &Name : EntrypointNameList) { if (G.FunctionSpecMap.find(Name) == G.FunctionSpecMap.end()) { @@ -112,7 +125,10 @@ OS << ", "; } - OS << ") __NOEXCEPT;\n\n"; + if (Offloading) + OS << ") __NOEXCEPT __DEVICE;\n\n"; + else + OS << ") __NOEXCEPT;\n\n"; } // Make another pass over entrypoints to emit object declarations. @@ -121,9 +137,14 @@ continue; llvm::Record *ObjectSpec = G.ObjectSpecMap[Name]; auto Type = ObjectSpec->getValueAsString("Type"); - OS << "extern " << Type << " " << Name << ";\n"; + if (Offloading) + OS << "extern " << Type << " " << Name << " __DEVICE;\n"; + else + OS << "extern " << Type << " " << Name << ";\n"; } OS << "__END_C_DECLS\n"; + if (Offloading) + OS << "__END_OPENMP_DECLS\n"; } void writePublicAPI(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) {} @@ -139,7 +160,7 @@ } APIIndexer G(StdHeader, Records); - writeAPIFromIndex(G, EntrypointNameList, OS); + writeAPIFromIndex(G, EntrypointNameList, Offloading, OS); } } // namespace llvm_libc diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.h b/libc/utils/LibcTableGenUtil/APIIndexer.h --- a/libc/utils/LibcTableGenUtil/APIIndexer.h +++ b/libc/utils/LibcTableGenUtil/APIIndexer.h @@ -75,6 +75,7 @@ NameSet Functions; NameSet Objects; NameSet PublicHeaders; + llvm::StringRef ExtraDefn; std::string getTypeAsString(llvm::Record *TypeRecord); }; diff --git a/libc/utils/LibcTableGenUtil/APIIndexer.cpp b/libc/utils/LibcTableGenUtil/APIIndexer.cpp --- a/libc/utils/LibcTableGenUtil/APIIndexer.cpp +++ b/libc/utils/LibcTableGenUtil/APIIndexer.cpp @@ -146,6 +146,8 @@ auto ObjectList = PublicAPI->getValueAsListOfStrings("Objects"); for (llvm::StringRef ObjectName : ObjectList) Objects.insert(std::string(ObjectName)); + + ExtraDefn = PublicAPI->getValueAsString("ExtraDefn"); } void APIIndexer::index(llvm::RecordKeeper &Records) {