|
37 | 37 | #include "llvm/Object/IRObjectFile.h"
|
38 | 38 | #include "llvm/Object/ObjectFile.h"
|
39 | 39 | #include "llvm/Object/OffloadBinary.h"
|
| 40 | +#include "llvm/Object/SYCLBIN.h" |
40 | 41 | #include "llvm/Option/ArgList.h"
|
41 | 42 | #include "llvm/Option/OptTable.h"
|
42 | 43 | #include "llvm/Option/Option.h"
|
@@ -151,6 +152,8 @@ static std::optional<llvm::module_split::IRSplitMode> SYCLModuleSplitMode;
|
151 | 152 |
|
152 | 153 | static bool UseSYCLPostLinkTool;
|
153 | 154 |
|
| 155 | +static bool OutputSYCLBIN; |
| 156 | + |
154 | 157 | static SmallString<128> OffloadImageDumpDir;
|
155 | 158 |
|
156 | 159 | using OffloadingImage = OffloadBinary::OffloadingImage;
|
@@ -1182,6 +1185,62 @@ static Expected<StringRef> runCompile(StringRef &InputFile,
|
1182 | 1185 | return *OutputFileOrErr;
|
1183 | 1186 | }
|
1184 | 1187 |
|
| 1188 | +/// Write an OffloadBinary containing the serialized SYCLBIN resulting from |
| 1189 | +/// \p ModuleDescs to the ExecutableName file with the .syclbin extension. |
| 1190 | +static Expected<StringRef> |
| 1191 | +packageSYCLBIN(SYCLBIN::BundleState State, |
| 1192 | + const ArrayRef<SYCLBIN::SYCLBINModuleDesc> Modules) { |
| 1193 | + SYCLBIN::SYCLBINDesc SYCLBIND{State, Modules}; |
| 1194 | + size_t SYCLBINByteSize = 0; |
| 1195 | + if (Error E = SYCLBIND.getSYCLBINByteSite().moveInto(SYCLBINByteSize)) |
| 1196 | + return std::move(E); |
| 1197 | + |
| 1198 | + SmallString<0> SYCLBINImage; |
| 1199 | + SYCLBINImage.reserve(SYCLBINByteSize); |
| 1200 | + raw_svector_ostream SYCLBINImageOS{SYCLBINImage}; |
| 1201 | + if (Error E = SYCLBIN::write(SYCLBIND, SYCLBINImageOS)) |
| 1202 | + return std::move(E); |
| 1203 | + |
| 1204 | + OffloadingImage Image{}; |
| 1205 | + Image.TheImageKind = IMG_SYCLBIN; |
| 1206 | + Image.TheOffloadKind = OFK_SYCL; |
| 1207 | + Image.Image = MemoryBuffer::getMemBuffer(SYCLBINImage, /*BufferName=*/"", |
| 1208 | + /*RequiresNullTerminator=*/false); |
| 1209 | + |
| 1210 | + std::unique_ptr<MemoryBuffer> Binary = MemoryBuffer::getMemBufferCopy( |
| 1211 | + OffloadBinary::write(Image), Image.Image->getBufferIdentifier()); |
| 1212 | + |
| 1213 | + auto OutFileOrErr = |
| 1214 | + createOutputFile(sys::path::filename(ExecutableName), "syclbin"); |
| 1215 | + if (!OutFileOrErr) |
| 1216 | + return OutFileOrErr.takeError(); |
| 1217 | + |
| 1218 | + Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr = |
| 1219 | + FileOutputBuffer::create(*OutFileOrErr, Binary->getBufferSize()); |
| 1220 | + if (!OutputOrErr) |
| 1221 | + return OutputOrErr.takeError(); |
| 1222 | + std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr); |
| 1223 | + llvm::copy(Binary->getBuffer(), Output->getBufferStart()); |
| 1224 | + if (Error E = Output->commit()) |
| 1225 | + return std::move(E); |
| 1226 | + |
| 1227 | + return *OutFileOrErr; |
| 1228 | +} |
| 1229 | + |
| 1230 | +Error mergeSYCLBIN(ArrayRef<StringRef> Files, const ArgList &Args) { |
| 1231 | + // Fast path for the general case where there's only one file. In this case we |
| 1232 | + // do not need to parse it and can instead simply copy it. |
| 1233 | + if (Files.size() == 1) { |
| 1234 | + if (std::error_code EC = sys::fs::copy_file(Files[0], ExecutableName)) |
| 1235 | + return createFileError(ExecutableName, EC); |
| 1236 | + return Error::success(); |
| 1237 | + } |
| 1238 | + // TODO: Merge SYCLBIN files here and write to ExecutableName output. |
| 1239 | + // Use the first file as the base and modify. |
| 1240 | + assert(Files.size() == 1); |
| 1241 | + return Error::success(); |
| 1242 | +} |
| 1243 | + |
1185 | 1244 | // Run wrapping library and clang
|
1186 | 1245 | static Expected<StringRef>
|
1187 | 1246 | runWrapperAndCompile(std::vector<module_split::SplitModule> &SplitModules,
|
@@ -1962,6 +2021,12 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
|
1962 | 2021 | // object file.
|
1963 | 2022 | SmallVector<StringRef> WrappedOutput;
|
1964 | 2023 |
|
| 2024 | + // When creating SYCLBIN files, we need to store the compiled modules for |
| 2025 | + // combined packaging. |
| 2026 | + std::mutex SYCLBINModulesMtx; |
| 2027 | + SYCLBIN::BundleState SYCLBINState = SYCLBIN::BundleState::Input; |
| 2028 | + SmallVector<SYCLBIN::SYCLBINModuleDesc> SYCLBINModules; |
| 2029 | + |
1965 | 2030 | // Initialize the images with any overriding inputs.
|
1966 | 2031 | if (Args.hasArg(OPT_override_image))
|
1967 | 2032 | if (Error Err = handleOverrideImages(Args, Images))
|
@@ -2067,18 +2132,26 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
|
2067 | 2132 | }
|
2068 | 2133 | }
|
2069 | 2134 |
|
2070 |
| - // TODO(NOM7): Remove this call and use community flow for bundle/wrap |
2071 |
| - auto OutputFile = sycl::runWrapperAndCompile(SplitModules, LinkerArgs); |
2072 |
| - if (!OutputFile) |
2073 |
| - return OutputFile.takeError(); |
2074 |
| - |
2075 |
| - // SYCL offload kind images are all ready to be sent to host linker. |
2076 |
| - // TODO: Currently, device code wrapping for SYCL offload happens in a |
2077 |
| - // separate path inside 'linkDevice' call seen above. |
2078 |
| - // This will eventually be refactored to use the 'common' wrapping logic |
2079 |
| - // that is used for other offload kinds. |
2080 |
| - std::scoped_lock Guard(ImageMtx); |
2081 |
| - WrappedOutput.push_back(*OutputFile); |
| 2135 | + if (OutputSYCLBIN) { |
| 2136 | + SYCLBIN::SYCLBINModuleDesc MD; |
| 2137 | + MD.ArchString = LinkerArgs.getLastArgValue(OPT_arch_EQ); |
| 2138 | + MD.SplitModules = std::move(SplitModules); |
| 2139 | + std::scoped_lock Guard(SYCLBINModulesMtx); |
| 2140 | + SYCLBINModules.emplace_back(std::move(MD)); |
| 2141 | + } else { |
| 2142 | + // TODO(NOM7): Remove this call and use community flow for bundle/wrap |
| 2143 | + auto OutputFile = sycl::runWrapperAndCompile(SplitModules, LinkerArgs); |
| 2144 | + if (!OutputFile) |
| 2145 | + return OutputFile.takeError(); |
| 2146 | + |
| 2147 | + // SYCL offload kind images are all ready to be sent to host linker. |
| 2148 | + // TODO: Currently, device code wrapping for SYCL offload happens in a |
| 2149 | + // separate path inside 'linkDevice' call seen above. |
| 2150 | + // This will eventually be refactored to use the 'common' wrapping logic |
| 2151 | + // that is used for other offload kinds. |
| 2152 | + std::scoped_lock Guard(ImageMtx); |
| 2153 | + WrappedOutput.push_back(*OutputFile); |
| 2154 | + } |
2082 | 2155 | }
|
2083 | 2156 | if (HasNonSYCLOffloadKinds) {
|
2084 | 2157 | // Write any remaining device inputs to an output file.
|
@@ -2129,6 +2202,13 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
|
2129 | 2202 | if (Err)
|
2130 | 2203 | return std::move(Err);
|
2131 | 2204 |
|
| 2205 | + if (OutputSYCLBIN) { |
| 2206 | + auto OutputOrErr = sycl::packageSYCLBIN(SYCLBINState, SYCLBINModules); |
| 2207 | + if (!OutputOrErr) |
| 2208 | + return OutputOrErr.takeError(); |
| 2209 | + WrappedOutput.push_back(*OutputOrErr); |
| 2210 | + } |
| 2211 | + |
2132 | 2212 | for (auto &[Kind, Input] : Images) {
|
2133 | 2213 | if (Kind == OFK_SYCL)
|
2134 | 2214 | continue;
|
@@ -2585,6 +2665,11 @@ int main(int Argc, char **Argv) {
|
2585 | 2665 | "-no-use-sycl-post-link-tool options can't "
|
2586 | 2666 | "be used together."));
|
2587 | 2667 |
|
| 2668 | + OutputSYCLBIN = Args.hasArg(OPT_syclbin); |
| 2669 | + if (OutputSYCLBIN && Args.hasArg(OPT_sycl_embed_ir)) |
| 2670 | + reportError(createStringError( |
| 2671 | + "-sycl-embed_ir and -syclbin can't be used together.")); |
| 2672 | + |
2588 | 2673 | if (Args.hasArg(OPT_sycl_module_split_mode_EQ)) {
|
2589 | 2674 | if (UseSYCLPostLinkTool)
|
2590 | 2675 | reportError(createStringError(
|
@@ -2623,9 +2708,14 @@ int main(int Argc, char **Argv) {
|
2623 | 2708 | if (!FilesOrErr)
|
2624 | 2709 | reportError(FilesOrErr.takeError());
|
2625 | 2710 |
|
2626 |
| - // Run the host linking job with the rendered arguments. |
2627 |
| - if (Error Err = runLinker(*FilesOrErr, Args)) |
2628 |
| - reportError(std::move(Err)); |
| 2711 | + if (OutputSYCLBIN) { |
| 2712 | + if (Error Err = sycl::mergeSYCLBIN(*FilesOrErr, Args)) |
| 2713 | + reportError(std::move(Err)); |
| 2714 | + } else { |
| 2715 | + // Run the host linking job with the rendered arguments. |
| 2716 | + if (Error Err = runLinker(*FilesOrErr, Args)) |
| 2717 | + reportError(std::move(Err)); |
| 2718 | + } |
2629 | 2719 | }
|
2630 | 2720 |
|
2631 | 2721 | if (const opt::Arg *Arg = Args.getLastArg(OPT_wrapper_time_trace_eq)) {
|
|
0 commit comments