1 //===-- clang-linker-wrapper/ClangLinkerWrapper.cpp - wrapper over linker-===// 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 // This tool works as a wrapper over a linking job. This tool is used to create 10 // linked device images for offloading. It scans the linker's input for embedded 11 // device offloading data stored in sections `.llvm.offloading` and extracts it 12 // as a temporary file. The extracted device files will then be passed to a 13 // device linking job to create a final device image. 14 // 15 //===---------------------------------------------------------------------===// 16 17 #include "OffloadWrapper.h" 18 #include "clang/Basic/Version.h" 19 #include "llvm/BinaryFormat/Magic.h" 20 #include "llvm/Bitcode/BitcodeWriter.h" 21 #include "llvm/CodeGen/CommandFlags.h" 22 #include "llvm/IR/Constants.h" 23 #include "llvm/IR/DiagnosticPrinter.h" 24 #include "llvm/IR/Module.h" 25 #include "llvm/IRReader/IRReader.h" 26 #include "llvm/LTO/LTO.h" 27 #include "llvm/MC/TargetRegistry.h" 28 #include "llvm/Object/Archive.h" 29 #include "llvm/Object/ArchiveWriter.h" 30 #include "llvm/Object/Binary.h" 31 #include "llvm/Object/ELFObjectFile.h" 32 #include "llvm/Object/IRObjectFile.h" 33 #include "llvm/Object/ObjectFile.h" 34 #include "llvm/Object/OffloadBinary.h" 35 #include "llvm/Option/ArgList.h" 36 #include "llvm/Option/OptTable.h" 37 #include "llvm/Option/Option.h" 38 #include "llvm/Support/CommandLine.h" 39 #include "llvm/Support/Errc.h" 40 #include "llvm/Support/FileOutputBuffer.h" 41 #include "llvm/Support/FileSystem.h" 42 #include "llvm/Support/Host.h" 43 #include "llvm/Support/InitLLVM.h" 44 #include "llvm/Support/MemoryBuffer.h" 45 #include "llvm/Support/Path.h" 46 #include "llvm/Support/Program.h" 47 #include "llvm/Support/Signals.h" 48 #include "llvm/Support/SourceMgr.h" 49 #include "llvm/Support/StringSaver.h" 50 #include "llvm/Support/TargetSelect.h" 51 #include "llvm/Support/WithColor.h" 52 #include "llvm/Support/raw_ostream.h" 53 #include "llvm/Target/TargetMachine.h" 54 55 using namespace llvm; 56 using namespace llvm::opt; 57 using namespace llvm::object; 58 59 /// Path of the current binary. 60 static const char *LinkerExecutable; 61 62 /// Ssave intermediary results. 63 static bool SaveTemps = false; 64 65 /// Print arguments without executing. 66 static bool DryRun = false; 67 68 /// Print verbose output. 69 static bool Verbose = false; 70 71 /// Filename of the executable being created. 72 static StringRef ExecutableName; 73 74 /// Binary path for the CUDA installation. 75 static std::string CudaBinaryPath; 76 77 /// Temporary files created by the linker wrapper. 78 static std::list<SmallString<128>> TempFiles; 79 80 /// Codegen flags for LTO backend. 81 static codegen::RegisterCodeGenFlags CodeGenFlags; 82 83 /// Global flag to indicate that the LTO pipeline threw an error. 84 static std::atomic<bool> LTOError; 85 86 using OffloadingImage = OffloadBinary::OffloadingImage; 87 88 /// A class to contain the binary information for a single OffloadBinary. 89 class OffloadFile : public OwningBinary<OffloadBinary> { 90 public: 91 using TargetID = std::pair<StringRef, StringRef>; 92 93 OffloadFile(std::unique_ptr<OffloadBinary> Binary, 94 std::unique_ptr<MemoryBuffer> Buffer) 95 : OwningBinary<OffloadBinary>(std::move(Binary), std::move(Buffer)) {} 96 97 /// We use the Triple and Architecture pair to group linker inputs together. 98 /// This conversion function lets us use these files in a hash-map. 99 operator TargetID() const { 100 return std::make_pair(getBinary()->getTriple(), getBinary()->getArch()); 101 } 102 }; 103 104 namespace llvm { 105 // Provide DenseMapInfo so that OffloadKind can be used in a DenseMap. 106 template <> struct DenseMapInfo<OffloadKind> { 107 static inline OffloadKind getEmptyKey() { return OFK_LAST; } 108 static inline OffloadKind getTombstoneKey() { 109 return static_cast<OffloadKind>(OFK_LAST + 1); 110 } 111 static unsigned getHashValue(const OffloadKind &Val) { return Val; } 112 113 static bool isEqual(const OffloadKind &LHS, const OffloadKind &RHS) { 114 return LHS == RHS; 115 } 116 }; 117 } // namespace llvm 118 119 namespace { 120 using std::error_code; 121 122 /// Must not overlap with llvm::opt::DriverFlag. 123 enum WrapperFlags { 124 WrapperOnlyOption = (1 << 4), // Options only used by the linker wrapper. 125 DeviceOnlyOption = (1 << 5), // Options only used for device linking. 126 }; 127 128 enum ID { 129 OPT_INVALID = 0, // This is not an option ID. 130 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 131 HELPTEXT, METAVAR, VALUES) \ 132 OPT_##ID, 133 #include "LinkerWrapperOpts.inc" 134 LastOption 135 #undef OPTION 136 }; 137 138 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 139 #include "LinkerWrapperOpts.inc" 140 #undef PREFIX 141 142 static const OptTable::Info InfoTable[] = { 143 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ 144 HELPTEXT, METAVAR, VALUES) \ 145 {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \ 146 PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES}, 147 #include "LinkerWrapperOpts.inc" 148 #undef OPTION 149 }; 150 151 class WrapperOptTable : public opt::OptTable { 152 public: 153 WrapperOptTable() : OptTable(InfoTable) {} 154 }; 155 156 const OptTable &getOptTable() { 157 static const WrapperOptTable *Table = []() { 158 auto Result = std::make_unique<WrapperOptTable>(); 159 return Result.release(); 160 }(); 161 return *Table; 162 } 163 164 Error extractFromBuffer(std::unique_ptr<MemoryBuffer> Buffer, 165 SmallVectorImpl<OffloadFile> &DeviceFiles); 166 167 void printCommands(ArrayRef<StringRef> CmdArgs) { 168 if (CmdArgs.empty()) 169 return; 170 171 llvm::errs() << " \"" << CmdArgs.front() << "\" "; 172 for (auto IC = std::next(CmdArgs.begin()), IE = CmdArgs.end(); IC != IE; ++IC) 173 llvm::errs() << *IC << (std::next(IC) != IE ? " " : "\n"); 174 } 175 176 [[noreturn]] void reportError(Error E) { 177 outs().flush(); 178 logAllUnhandledErrors(std::move(E), 179 WithColor::error(errs(), LinkerExecutable)); 180 exit(EXIT_FAILURE); 181 } 182 183 /// Create an extra user-specified \p OffloadFile. 184 /// TODO: We should find a way to wrap these as libraries instead. 185 Expected<OffloadFile> getInputBitcodeLibrary(StringRef Input) { 186 auto DeviceAndPath = StringRef(Input).split('='); 187 auto StringAndArch = DeviceAndPath.first.rsplit('-'); 188 auto KindAndTriple = StringAndArch.first.split('-'); 189 190 llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> ImageOrError = 191 llvm::MemoryBuffer::getFileOrSTDIN(DeviceAndPath.second); 192 if (std::error_code EC = ImageOrError.getError()) 193 return createFileError(DeviceAndPath.second, EC); 194 195 OffloadingImage Image{}; 196 Image.TheImageKind = IMG_Bitcode; 197 Image.TheOffloadKind = getOffloadKind(KindAndTriple.first); 198 Image.StringData = {{"triple", KindAndTriple.second}, 199 {"arch", StringAndArch.second}}; 200 Image.Image = std::move(*ImageOrError); 201 202 std::unique_ptr<MemoryBuffer> Binary = OffloadBinary::write(Image); 203 auto NewBinaryOrErr = OffloadBinary::create(*Binary); 204 if (!NewBinaryOrErr) 205 return NewBinaryOrErr.takeError(); 206 return OffloadFile(std::move(*NewBinaryOrErr), std::move(Binary)); 207 } 208 209 std::string getMainExecutable(const char *Name) { 210 void *Ptr = (void *)(intptr_t)&getMainExecutable; 211 auto COWPath = sys::fs::getMainExecutable(Name, Ptr); 212 return sys::path::parent_path(COWPath).str(); 213 } 214 215 /// Get a temporary filename suitable for output. 216 Expected<StringRef> createOutputFile(const Twine &Prefix, StringRef Extension) { 217 SmallString<128> OutputFile; 218 if (SaveTemps) { 219 (Prefix + "." + Extension).toNullTerminatedStringRef(OutputFile); 220 } else { 221 if (std::error_code EC = 222 sys::fs::createTemporaryFile(Prefix, Extension, OutputFile)) 223 return createFileError(OutputFile, EC); 224 } 225 226 TempFiles.emplace_back(std::move(OutputFile)); 227 return TempFiles.back(); 228 } 229 230 /// Execute the command \p ExecutablePath with the arguments \p Args. 231 Error executeCommands(StringRef ExecutablePath, ArrayRef<StringRef> Args) { 232 if (Verbose || DryRun) 233 printCommands(Args); 234 235 if (!DryRun) 236 if (sys::ExecuteAndWait(ExecutablePath, Args)) 237 return createStringError(inconvertibleErrorCode(), 238 "'" + sys::path::filename(ExecutablePath) + "'" + 239 " failed"); 240 return Error::success(); 241 } 242 243 Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) { 244 245 ErrorOr<std::string> Path = sys::findProgramByName(Name, Paths); 246 if (!Path) 247 Path = sys::findProgramByName(Name); 248 if (!Path && DryRun) 249 return Name.str(); 250 if (!Path) 251 return createStringError(Path.getError(), 252 "Unable to find '" + Name + "' in path"); 253 return *Path; 254 } 255 256 /// Runs the wrapped linker job with the newly created input. 257 Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) { 258 llvm::TimeTraceScope TimeScope("Execute host linker"); 259 260 // Render the linker arguments and add the newly created image. We add it 261 // after the output file to ensure it is linked with the correct libraries. 262 StringRef LinkerPath = Args.getLastArgValue(OPT_linker_path_EQ); 263 ArgStringList NewLinkerArgs; 264 for (const opt::Arg *Arg : Args) { 265 // Do not forward arguments only intended for the linker wrapper. 266 if (Arg->getOption().hasFlag(WrapperOnlyOption)) 267 continue; 268 269 Arg->render(Args, NewLinkerArgs); 270 if (Arg->getOption().matches(OPT_o)) 271 llvm::transform(Files, std::back_inserter(NewLinkerArgs), 272 [&](StringRef Arg) { return Args.MakeArgString(Arg); }); 273 } 274 275 SmallVector<StringRef> LinkerArgs({LinkerPath}); 276 for (StringRef Arg : NewLinkerArgs) 277 LinkerArgs.push_back(Arg); 278 if (Error Err = executeCommands(LinkerPath, LinkerArgs)) 279 return Err; 280 return Error::success(); 281 } 282 283 void printVersion(raw_ostream &OS) { 284 OS << clang::getClangToolFullVersion("clang-linker-wrapper") << '\n'; 285 } 286 287 /// Attempts to extract all the embedded device images contained inside the 288 /// buffer \p Contents. The buffer is expected to contain a valid offloading 289 /// binary format. 290 Error extractOffloadFiles(MemoryBufferRef Contents, 291 SmallVectorImpl<OffloadFile> &DeviceFiles) { 292 uint64_t Offset = 0; 293 // There could be multiple offloading binaries stored at this section. 294 while (Offset < Contents.getBuffer().size()) { 295 std::unique_ptr<MemoryBuffer> Buffer = 296 MemoryBuffer::getMemBuffer(Contents.getBuffer().drop_front(Offset), "", 297 /*RequiresNullTerminator*/ false); 298 auto BinaryOrErr = OffloadBinary::create(*Buffer); 299 if (!BinaryOrErr) 300 return BinaryOrErr.takeError(); 301 OffloadBinary &Binary = **BinaryOrErr; 302 303 // Create a new owned binary with a copy of the original memory. 304 std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy( 305 Binary.getData().take_front(Binary.getSize()), 306 Contents.getBufferIdentifier()); 307 auto NewBinaryOrErr = OffloadBinary::create(*BufferCopy); 308 if (!NewBinaryOrErr) 309 return NewBinaryOrErr.takeError(); 310 DeviceFiles.emplace_back(std::move(*NewBinaryOrErr), std::move(BufferCopy)); 311 312 Offset += Binary.getSize(); 313 } 314 315 return Error::success(); 316 } 317 318 // Extract offloading binaries from an Object file \p Obj. 319 Error extractFromBinary(const ObjectFile &Obj, 320 SmallVectorImpl<OffloadFile> &DeviceFiles) { 321 for (ELFSectionRef Sec : Obj.sections()) { 322 if (Sec.getType() != ELF::SHT_LLVM_OFFLOADING) 323 continue; 324 325 Expected<StringRef> Buffer = Sec.getContents(); 326 if (!Buffer) 327 return Buffer.takeError(); 328 329 MemoryBufferRef Contents(*Buffer, Obj.getFileName()); 330 if (Error Err = extractOffloadFiles(Contents, DeviceFiles)) 331 return Err; 332 } 333 334 return Error::success(); 335 } 336 337 Error extractFromBitcode(std::unique_ptr<MemoryBuffer> Buffer, 338 SmallVectorImpl<OffloadFile> &DeviceFiles) { 339 LLVMContext Context; 340 SMDiagnostic Err; 341 std::unique_ptr<Module> M = getLazyIRModule(std::move(Buffer), Err, Context); 342 if (!M) 343 return createStringError(inconvertibleErrorCode(), 344 "Failed to create module"); 345 346 // Extract offloading data from globals referenced by the 347 // `llvm.embedded.object` metadata with the `.llvm.offloading` section. 348 auto *MD = M->getNamedMetadata("llvm.embedded.objects"); 349 if (!MD) 350 return Error::success(); 351 352 for (const MDNode *Op : MD->operands()) { 353 if (Op->getNumOperands() < 2) 354 continue; 355 356 MDString *SectionID = dyn_cast<MDString>(Op->getOperand(1)); 357 if (!SectionID || SectionID->getString() != ".llvm.offloading") 358 continue; 359 360 GlobalVariable *GV = 361 mdconst::dyn_extract_or_null<GlobalVariable>(Op->getOperand(0)); 362 if (!GV) 363 continue; 364 365 auto *CDS = dyn_cast<ConstantDataSequential>(GV->getInitializer()); 366 if (!CDS) 367 continue; 368 369 MemoryBufferRef Contents(CDS->getAsString(), M->getName()); 370 if (Error Err = extractOffloadFiles(Contents, DeviceFiles)) 371 return Err; 372 } 373 374 return Error::success(); 375 } 376 377 Error extractFromArchive(const Archive &Library, 378 SmallVectorImpl<OffloadFile> &DeviceFiles) { 379 // Try to extract device code from each file stored in the static archive. 380 Error Err = Error::success(); 381 for (auto Child : Library.children(Err)) { 382 auto ChildBufferOrErr = Child.getMemoryBufferRef(); 383 if (!ChildBufferOrErr) 384 return ChildBufferOrErr.takeError(); 385 std::unique_ptr<MemoryBuffer> ChildBuffer = 386 MemoryBuffer::getMemBuffer(*ChildBufferOrErr, false); 387 388 // Check if the buffer has the required alignment. 389 if (!isAddrAligned(Align(OffloadBinary::getAlignment()), 390 ChildBuffer->getBufferStart())) 391 ChildBuffer = MemoryBuffer::getMemBufferCopy( 392 ChildBufferOrErr->getBuffer(), 393 ChildBufferOrErr->getBufferIdentifier()); 394 395 if (Error Err = extractFromBuffer(std::move(ChildBuffer), DeviceFiles)) 396 return Err; 397 } 398 399 if (Err) 400 return Err; 401 return Error::success(); 402 } 403 404 /// Extracts embedded device offloading code from a memory \p Buffer to a list 405 /// of \p DeviceFiles. 406 Error extractFromBuffer(std::unique_ptr<MemoryBuffer> Buffer, 407 SmallVectorImpl<OffloadFile> &DeviceFiles) { 408 file_magic Type = identify_magic(Buffer->getBuffer()); 409 switch (Type) { 410 case file_magic::bitcode: 411 return extractFromBitcode(std::move(Buffer), DeviceFiles); 412 case file_magic::elf_relocatable: { 413 Expected<std::unique_ptr<ObjectFile>> ObjFile = 414 ObjectFile::createObjectFile(*Buffer, Type); 415 if (!ObjFile) 416 return ObjFile.takeError(); 417 return extractFromBinary(*ObjFile->get(), DeviceFiles); 418 } 419 case file_magic::archive: { 420 Expected<std::unique_ptr<llvm::object::Archive>> LibFile = 421 object::Archive::create(*Buffer); 422 if (!LibFile) 423 return LibFile.takeError(); 424 return extractFromArchive(*LibFile->get(), DeviceFiles); 425 } 426 default: 427 return Error::success(); 428 } 429 } 430 431 namespace nvptx { 432 Expected<StringRef> assemble(StringRef InputFile, const ArgList &Args, 433 bool RDC = true) { 434 llvm::TimeTraceScope TimeScope("NVPTX Assembler"); 435 // NVPTX uses the ptxas binary to create device object files. 436 Expected<std::string> PtxasPath = findProgram("ptxas", {CudaBinaryPath}); 437 if (!PtxasPath) 438 return PtxasPath.takeError(); 439 440 const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); 441 StringRef Arch = Args.getLastArgValue(OPT_arch_EQ); 442 // Create a new file to write the linked device image to. Assume that the 443 // input filename already has the device and architecture. 444 auto TempFileOrErr = createOutputFile(sys::path::stem(InputFile), "cubin"); 445 if (!TempFileOrErr) 446 return TempFileOrErr.takeError(); 447 448 SmallVector<StringRef, 16> CmdArgs; 449 StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2"); 450 CmdArgs.push_back(*PtxasPath); 451 CmdArgs.push_back(Triple.isArch64Bit() ? "-m64" : "-m32"); 452 if (Verbose) 453 CmdArgs.push_back("-v"); 454 for (StringRef Arg : Args.getAllArgValues(OPT_ptxas_arg)) 455 CmdArgs.push_back(Args.MakeArgString(Arg)); 456 CmdArgs.push_back("-o"); 457 CmdArgs.push_back(*TempFileOrErr); 458 CmdArgs.push_back(Args.MakeArgString("-" + OptLevel)); 459 CmdArgs.push_back("--gpu-name"); 460 CmdArgs.push_back(Arch); 461 if (Args.hasArg(OPT_debug)) 462 CmdArgs.push_back("-g"); 463 if (RDC) 464 CmdArgs.push_back("-c"); 465 466 CmdArgs.push_back(InputFile); 467 468 if (Error Err = executeCommands(*PtxasPath, CmdArgs)) 469 return std::move(Err); 470 471 return *TempFileOrErr; 472 } 473 474 Expected<StringRef> link(ArrayRef<StringRef> InputFiles, const ArgList &Args) { 475 llvm::TimeTraceScope TimeScope("NVPTX linker"); 476 // NVPTX uses the nvlink binary to link device object files. 477 Expected<std::string> NvlinkPath = findProgram("nvlink", {CudaBinaryPath}); 478 if (!NvlinkPath) 479 return NvlinkPath.takeError(); 480 481 const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); 482 StringRef Arch = Args.getLastArgValue(OPT_arch_EQ); 483 484 // Create a new file to write the linked device image to. 485 auto TempFileOrErr = 486 createOutputFile(sys::path::filename(ExecutableName) + "-device-" + 487 Triple.getArchName() + "-" + Arch, 488 "out"); 489 if (!TempFileOrErr) 490 return TempFileOrErr.takeError(); 491 492 SmallVector<StringRef, 16> CmdArgs; 493 CmdArgs.push_back(*NvlinkPath); 494 CmdArgs.push_back(Triple.isArch64Bit() ? "-m64" : "-m32"); 495 if (Args.hasArg(OPT_debug)) 496 CmdArgs.push_back("-g"); 497 if (Verbose) 498 CmdArgs.push_back("-v"); 499 CmdArgs.push_back("-o"); 500 CmdArgs.push_back(*TempFileOrErr); 501 CmdArgs.push_back("-arch"); 502 CmdArgs.push_back(Arch); 503 504 // Add extracted input files. 505 for (StringRef Input : InputFiles) 506 CmdArgs.push_back(Input); 507 508 for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ)) 509 CmdArgs.push_back(Args.MakeArgString(Arg)); 510 if (Error Err = executeCommands(*NvlinkPath, CmdArgs)) 511 return std::move(Err); 512 513 return *TempFileOrErr; 514 } 515 516 Expected<StringRef> 517 fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles, 518 const ArgList &Args) { 519 llvm::TimeTraceScope TimeScope("NVPTX fatbinary"); 520 // NVPTX uses the fatbinary program to bundle the linked images. 521 Expected<std::string> FatBinaryPath = 522 findProgram("fatbinary", {CudaBinaryPath}); 523 if (!FatBinaryPath) 524 return FatBinaryPath.takeError(); 525 526 llvm::Triple Triple( 527 Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple())); 528 529 // Create a new file to write the linked device image to. 530 auto TempFileOrErr = createOutputFile( 531 sys::path::filename(ExecutableName) + "-device", "fatbin"); 532 if (!TempFileOrErr) 533 return TempFileOrErr.takeError(); 534 535 SmallVector<StringRef, 16> CmdArgs; 536 CmdArgs.push_back(*FatBinaryPath); 537 CmdArgs.push_back(Triple.isArch64Bit() ? "-64" : "-32"); 538 CmdArgs.push_back("--create"); 539 CmdArgs.push_back(*TempFileOrErr); 540 for (const auto &FileAndArch : InputFiles) 541 CmdArgs.push_back( 542 Args.MakeArgString("--image=profile=" + std::get<1>(FileAndArch) + 543 ",file=" + std::get<0>(FileAndArch))); 544 545 if (Error Err = executeCommands(*FatBinaryPath, CmdArgs)) 546 return std::move(Err); 547 548 return *TempFileOrErr; 549 } 550 } // namespace nvptx 551 552 namespace amdgcn { 553 Expected<StringRef> link(ArrayRef<StringRef> InputFiles, const ArgList &Args) { 554 llvm::TimeTraceScope TimeScope("AMDGPU linker"); 555 // AMDGPU uses lld to link device object files. 556 Expected<std::string> LLDPath = 557 findProgram("lld", {getMainExecutable("lld")}); 558 if (!LLDPath) 559 return LLDPath.takeError(); 560 561 const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); 562 StringRef Arch = Args.getLastArgValue(OPT_arch_EQ); 563 564 // Create a new file to write the linked device image to. 565 auto TempFileOrErr = 566 createOutputFile(sys::path::filename(ExecutableName) + "-" + 567 Triple.getArchName() + "-" + Arch, 568 "out"); 569 if (!TempFileOrErr) 570 return TempFileOrErr.takeError(); 571 std::string ArchArg = ("-plugin-opt=mcpu=" + Arch).str(); 572 573 SmallVector<StringRef, 16> CmdArgs; 574 CmdArgs.push_back(*LLDPath); 575 CmdArgs.push_back("-flavor"); 576 CmdArgs.push_back("gnu"); 577 CmdArgs.push_back("--no-undefined"); 578 CmdArgs.push_back("-shared"); 579 CmdArgs.push_back("-plugin-opt=-amdgpu-internalize-symbols"); 580 CmdArgs.push_back(ArchArg); 581 CmdArgs.push_back("-o"); 582 CmdArgs.push_back(*TempFileOrErr); 583 584 // Add extracted input files. 585 for (StringRef Input : InputFiles) 586 CmdArgs.push_back(Input); 587 588 for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ)) 589 CmdArgs.push_back(Args.MakeArgString(Arg)); 590 if (Error Err = executeCommands(*LLDPath, CmdArgs)) 591 return std::move(Err); 592 593 return *TempFileOrErr; 594 } 595 596 Expected<StringRef> 597 fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles, 598 const ArgList &Args) { 599 llvm::TimeTraceScope TimeScope("AMDGPU Fatbinary"); 600 601 // AMDGPU uses the clang-offload-bundler to bundle the linked images. 602 Expected<std::string> OffloadBundlerPath = findProgram( 603 "clang-offload-bundler", {getMainExecutable("clang-offload-bundler")}); 604 if (!OffloadBundlerPath) 605 return OffloadBundlerPath.takeError(); 606 607 llvm::Triple Triple( 608 Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple())); 609 610 // Create a new file to write the linked device image to. 611 auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) + 612 "-device-" + Triple.getArchName(), 613 "hipfb"); 614 if (!TempFileOrErr) 615 return TempFileOrErr.takeError(); 616 617 BumpPtrAllocator Alloc; 618 StringSaver Saver(Alloc); 619 620 SmallVector<StringRef, 16> CmdArgs; 621 CmdArgs.push_back(*OffloadBundlerPath); 622 CmdArgs.push_back("-type=o"); 623 CmdArgs.push_back("-bundle-align=4096"); 624 625 SmallVector<StringRef> Targets = {"-targets=host-x86_64-unknown-linux"}; 626 for (const auto &FileAndArch : InputFiles) 627 Targets.push_back( 628 Saver.save("hipv4-amdgcn-amd-amdhsa--" + std::get<1>(FileAndArch))); 629 CmdArgs.push_back(Saver.save(llvm::join(Targets, ","))); 630 631 CmdArgs.push_back("-input=/dev/null"); 632 for (const auto &FileAndArch : InputFiles) 633 CmdArgs.push_back(Saver.save("-input=" + std::get<0>(FileAndArch))); 634 635 CmdArgs.push_back(Saver.save("-output=" + *TempFileOrErr)); 636 637 if (Error Err = executeCommands(*OffloadBundlerPath, CmdArgs)) 638 return std::move(Err); 639 640 return *TempFileOrErr; 641 } 642 } // namespace amdgcn 643 644 namespace generic { 645 646 const char *getLDMOption(const llvm::Triple &T) { 647 switch (T.getArch()) { 648 case llvm::Triple::x86: 649 if (T.isOSIAMCU()) 650 return "elf_iamcu"; 651 return "elf_i386"; 652 case llvm::Triple::aarch64: 653 return "aarch64linux"; 654 case llvm::Triple::aarch64_be: 655 return "aarch64linuxb"; 656 case llvm::Triple::ppc64: 657 return "elf64ppc"; 658 case llvm::Triple::ppc64le: 659 return "elf64lppc"; 660 case llvm::Triple::x86_64: 661 if (T.isX32()) 662 return "elf32_x86_64"; 663 return "elf_x86_64"; 664 case llvm::Triple::ve: 665 return "elf64ve"; 666 default: 667 return nullptr; 668 } 669 } 670 671 Expected<StringRef> link(ArrayRef<StringRef> InputFiles, const ArgList &Args) { 672 llvm::TimeTraceScope TimeScope("Generic linker"); 673 const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); 674 StringRef Arch = Args.getLastArgValue(OPT_arch_EQ); 675 676 // Create a new file to write the linked device image to. 677 auto TempFileOrErr = 678 createOutputFile(sys::path::filename(ExecutableName) + "-" + 679 Triple.getArchName() + "-" + Arch, 680 "out"); 681 if (!TempFileOrErr) 682 return TempFileOrErr.takeError(); 683 684 // Use the host linker to perform generic offloading. Use the same libraries 685 // and paths as the host application does. 686 SmallVector<StringRef, 16> CmdArgs; 687 CmdArgs.push_back(Args.getLastArgValue(OPT_linker_path_EQ)); 688 CmdArgs.push_back("-m"); 689 CmdArgs.push_back(getLDMOption(Triple)); 690 CmdArgs.push_back("-shared"); 691 692 ArgStringList LinkerArgs; 693 for (const opt::Arg *Arg : Args) { 694 auto Op = Arg->getOption(); 695 if (Op.matches(OPT_library) || Op.matches(OPT_library_path) || 696 Op.matches(OPT_as_needed) || Op.matches(OPT_no_as_needed) || 697 Op.matches(OPT_rpath) || Op.matches(OPT_dynamic_linker)) 698 Arg->render(Args, LinkerArgs); 699 } 700 for (StringRef Arg : LinkerArgs) 701 CmdArgs.push_back(Arg); 702 703 CmdArgs.push_back("-Bsymbolic"); 704 CmdArgs.push_back("-o"); 705 CmdArgs.push_back(*TempFileOrErr); 706 707 // Add extracted input files. 708 for (StringRef Input : InputFiles) 709 CmdArgs.push_back(Input); 710 711 for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ)) 712 CmdArgs.push_back(Args.MakeArgString(Arg)); 713 if (Error Err = 714 executeCommands(Args.getLastArgValue(OPT_linker_path_EQ), CmdArgs)) 715 return std::move(Err); 716 717 return *TempFileOrErr; 718 } 719 } // namespace generic 720 721 Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles, 722 const ArgList &Args) { 723 const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); 724 switch (Triple.getArch()) { 725 case Triple::nvptx: 726 case Triple::nvptx64: 727 return nvptx::link(InputFiles, Args); 728 case Triple::amdgcn: 729 return amdgcn::link(InputFiles, Args); 730 case Triple::x86: 731 case Triple::x86_64: 732 case Triple::aarch64: 733 case Triple::aarch64_be: 734 case Triple::ppc64: 735 case Triple::ppc64le: 736 return generic::link(InputFiles, Args); 737 default: 738 return createStringError(inconvertibleErrorCode(), 739 Triple.getArchName() + 740 " linking is not supported"); 741 } 742 } 743 744 void diagnosticHandler(const DiagnosticInfo &DI) { 745 std::string ErrStorage; 746 raw_string_ostream OS(ErrStorage); 747 DiagnosticPrinterRawOStream DP(OS); 748 DI.print(DP); 749 750 switch (DI.getSeverity()) { 751 case DS_Error: 752 WithColor::error(errs(), LinkerExecutable) << ErrStorage << "\n"; 753 LTOError = true; 754 break; 755 case DS_Warning: 756 WithColor::warning(errs(), LinkerExecutable) << ErrStorage << "\n"; 757 break; 758 case DS_Note: 759 WithColor::note(errs(), LinkerExecutable) << ErrStorage << "\n"; 760 break; 761 case DS_Remark: 762 WithColor::remark(errs()) << ErrStorage << "\n"; 763 break; 764 } 765 } 766 767 // Get the list of target features from the input file and unify them such that 768 // if there are multiple +xxx or -xxx features we only keep the last one. 769 std::vector<std::string> getTargetFeatures(ArrayRef<OffloadFile> InputFiles) { 770 SmallVector<StringRef> Features; 771 for (const OffloadFile &File : InputFiles) { 772 for (auto Arg : llvm::split(File.getBinary()->getString("feature"), ",")) 773 Features.emplace_back(Arg); 774 } 775 776 // Only add a feature if it hasn't been seen before starting from the end. 777 std::vector<std::string> UnifiedFeatures; 778 DenseSet<StringRef> UsedFeatures; 779 for (StringRef Feature : llvm::reverse(Features)) { 780 if (UsedFeatures.insert(Feature.drop_front()).second) 781 UnifiedFeatures.push_back(Feature.str()); 782 } 783 784 return UnifiedFeatures; 785 } 786 787 CodeGenOpt::Level getCGOptLevel(unsigned OptLevel) { 788 switch (OptLevel) { 789 case 0: 790 return CodeGenOpt::None; 791 case 1: 792 return CodeGenOpt::Less; 793 case 2: 794 return CodeGenOpt::Default; 795 case 3: 796 return CodeGenOpt::Aggressive; 797 } 798 llvm_unreachable("Invalid optimization level"); 799 } 800 801 template <typename ModuleHook = function_ref<bool(size_t, const Module &)>> 802 std::unique_ptr<lto::LTO> createLTO( 803 const ArgList &Args, const std::vector<std::string> &Features, 804 ModuleHook Hook = [](size_t, const Module &) { return true; }) { 805 const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); 806 StringRef Arch = Args.getLastArgValue(OPT_arch_EQ); 807 lto::Config Conf; 808 lto::ThinBackend Backend; 809 // TODO: Handle index-only thin-LTO 810 Backend = 811 lto::createInProcessThinBackend(llvm::heavyweight_hardware_concurrency()); 812 813 Conf.CPU = Arch.str(); 814 Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple); 815 816 StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2"); 817 Conf.MAttrs = Features; 818 Conf.CGOptLevel = getCGOptLevel(OptLevel[1] - '0'); 819 Conf.OptLevel = OptLevel[1] - '0'; 820 if (Conf.OptLevel > 0) 821 Conf.UseDefaultPipeline = true; 822 Conf.DefaultTriple = Triple.getTriple(); 823 824 LTOError = false; 825 Conf.DiagHandler = diagnosticHandler; 826 827 Conf.PTO.LoopVectorization = Conf.OptLevel > 1; 828 Conf.PTO.SLPVectorization = Conf.OptLevel > 1; 829 830 if (SaveTemps) { 831 std::string TempName = (sys::path::filename(ExecutableName) + "-device-" + 832 Triple.getTriple() + "-" + Arch) 833 .str(); 834 Conf.PostInternalizeModuleHook = [=](size_t Task, const Module &M) { 835 std::string File = !Task ? TempName + ".bc" 836 : TempName + "." + std::to_string(Task) + ".bc"; 837 error_code EC; 838 raw_fd_ostream LinkedBitcode(File, EC, sys::fs::OF_None); 839 if (EC) 840 reportError(errorCodeToError(EC)); 841 WriteBitcodeToFile(M, LinkedBitcode); 842 return true; 843 }; 844 } 845 Conf.PostOptModuleHook = Hook; 846 Conf.CGFileType = Triple.isNVPTX() ? CGFT_AssemblyFile : CGFT_ObjectFile; 847 848 // TODO: Handle remark files 849 Conf.HasWholeProgramVisibility = Args.hasArg(OPT_whole_program); 850 851 return std::make_unique<lto::LTO>(std::move(Conf), Backend); 852 } 853 854 // Returns true if \p S is valid as a C language identifier and will be given 855 // `__start_` and `__stop_` symbols. 856 bool isValidCIdentifier(StringRef S) { 857 return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && 858 std::all_of(S.begin() + 1, S.end(), 859 [](char C) { return C == '_' || isAlnum(C); }); 860 } 861 862 Error linkBitcodeFiles(SmallVectorImpl<OffloadFile> &InputFiles, 863 SmallVectorImpl<StringRef> &OutputFiles, 864 const ArgList &Args) { 865 llvm::TimeTraceScope TimeScope("Link bitcode files"); 866 const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); 867 868 SmallVector<OffloadFile, 4> BitcodeInputFiles; 869 DenseSet<StringRef> UsedInRegularObj; 870 DenseSet<StringRef> UsedInSharedLib; 871 BumpPtrAllocator Alloc; 872 StringSaver Saver(Alloc); 873 874 // Search for bitcode files in the input and create an LTO input file. If it 875 // is not a bitcode file, scan its symbol table for symbols we need to save. 876 for (OffloadFile &File : InputFiles) { 877 MemoryBufferRef Buffer = MemoryBufferRef(File.getBinary()->getImage(), ""); 878 879 file_magic Type = identify_magic(Buffer.getBuffer()); 880 switch (Type) { 881 case file_magic::bitcode: { 882 BitcodeInputFiles.emplace_back(std::move(File)); 883 continue; 884 } 885 case file_magic::elf_relocatable: 886 case file_magic::elf_shared_object: { 887 Expected<std::unique_ptr<ObjectFile>> ObjFile = 888 ObjectFile::createObjectFile(Buffer); 889 if (!ObjFile) 890 continue; 891 892 for (SymbolRef Sym : (*ObjFile)->symbols()) { 893 Expected<StringRef> Name = Sym.getName(); 894 if (!Name) 895 return Name.takeError(); 896 897 // Record if we've seen these symbols in any object or shared libraries. 898 if ((*ObjFile)->isRelocatableObject()) 899 UsedInRegularObj.insert(Saver.save(*Name)); 900 else 901 UsedInSharedLib.insert(Saver.save(*Name)); 902 } 903 continue; 904 } 905 default: 906 continue; 907 } 908 } 909 910 if (BitcodeInputFiles.empty()) 911 return Error::success(); 912 913 // Remove all the bitcode files that we moved from the original input. 914 llvm::erase_if(InputFiles, [](OffloadFile &F) { return !F.getBinary(); }); 915 916 // LTO Module hook to output bitcode without running the backend. 917 SmallVector<StringRef, 4> BitcodeOutput; 918 auto OutputBitcode = [&](size_t, const Module &M) { 919 auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) + 920 "-jit-" + Triple.getTriple(), 921 "bc"); 922 if (!TempFileOrErr) 923 reportError(TempFileOrErr.takeError()); 924 925 std::error_code EC; 926 raw_fd_ostream LinkedBitcode(*TempFileOrErr, EC, sys::fs::OF_None); 927 if (EC) 928 reportError(errorCodeToError(EC)); 929 WriteBitcodeToFile(M, LinkedBitcode); 930 BitcodeOutput.push_back(*TempFileOrErr); 931 return false; 932 }; 933 934 // We assume visibility of the whole program if every input file was bitcode. 935 auto Features = getTargetFeatures(BitcodeInputFiles); 936 auto LTOBackend = Args.hasArg(OPT_embed_bitcode) 937 ? createLTO(Args, Features, OutputBitcode) 938 : createLTO(Args, Features); 939 940 // We need to resolve the symbols so the LTO backend knows which symbols need 941 // to be kept or can be internalized. This is a simplified symbol resolution 942 // scheme to approximate the full resolution a linker would do. 943 uint64_t Idx = 0; 944 DenseSet<StringRef> PrevailingSymbols; 945 for (auto &BitcodeInput : BitcodeInputFiles) { 946 // Get a semi-unique buffer identifier for Thin-LTO. 947 StringRef Identifier = Saver.save( 948 std::to_string(Idx++) + "." + 949 BitcodeInput.getBinary()->getMemoryBufferRef().getBufferIdentifier()); 950 MemoryBufferRef Buffer = 951 MemoryBufferRef(BitcodeInput.getBinary()->getImage(), Identifier); 952 Expected<std::unique_ptr<lto::InputFile>> BitcodeFileOrErr = 953 llvm::lto::InputFile::create(Buffer); 954 if (!BitcodeFileOrErr) 955 return BitcodeFileOrErr.takeError(); 956 957 // Save the input file and the buffer associated with its memory. 958 const auto Symbols = (*BitcodeFileOrErr)->symbols(); 959 SmallVector<lto::SymbolResolution, 16> Resolutions(Symbols.size()); 960 size_t Idx = 0; 961 for (auto &Sym : Symbols) { 962 lto::SymbolResolution &Res = Resolutions[Idx++]; 963 964 // We will use this as the prevailing symbol definition in LTO unless 965 // it is undefined or another definition has already been used. 966 Res.Prevailing = 967 !Sym.isUndefined() && 968 PrevailingSymbols.insert(Saver.save(Sym.getName())).second; 969 970 // We need LTO to preseve the following global symbols: 971 // 1) Symbols used in regular objects. 972 // 2) Sections that will be given a __start/__stop symbol. 973 // 3) Prevailing symbols that are needed visible to external libraries. 974 Res.VisibleToRegularObj = 975 UsedInRegularObj.contains(Sym.getName()) || 976 isValidCIdentifier(Sym.getSectionName()) || 977 (Res.Prevailing && 978 (Sym.getVisibility() != GlobalValue::HiddenVisibility && 979 !Sym.canBeOmittedFromSymbolTable())); 980 981 // Identify symbols that must be exported dynamically and can be 982 // referenced by other files. 983 Res.ExportDynamic = 984 Sym.getVisibility() != GlobalValue::HiddenVisibility && 985 (UsedInSharedLib.contains(Sym.getName()) || 986 !Sym.canBeOmittedFromSymbolTable()); 987 988 // The final definition will reside in this linkage unit if the symbol is 989 // defined and local to the module. This only checks for bitcode files, 990 // full assertion will require complete symbol resolution. 991 Res.FinalDefinitionInLinkageUnit = 992 Sym.getVisibility() != GlobalValue::DefaultVisibility && 993 (!Sym.isUndefined() && !Sym.isCommon()); 994 995 // We do not support linker redefined symbols (e.g. --wrap) for device 996 // image linking, so the symbols will not be changed after LTO. 997 Res.LinkerRedefined = false; 998 } 999 1000 // Add the bitcode file with its resolved symbols to the LTO job. 1001 if (Error Err = LTOBackend->add(std::move(*BitcodeFileOrErr), Resolutions)) 1002 return Err; 1003 } 1004 1005 // Run the LTO job to compile the bitcode. 1006 size_t MaxTasks = LTOBackend->getMaxTasks(); 1007 SmallVector<StringRef> Files(MaxTasks); 1008 auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> { 1009 int FD = -1; 1010 auto &TempFile = Files[Task]; 1011 StringRef Extension = (Triple.isNVPTX()) ? "s" : "o"; 1012 std::string TaskStr = Task ? "." + std::to_string(Task) : ""; 1013 auto TempFileOrErr = 1014 createOutputFile(sys::path::filename(ExecutableName) + "-device-" + 1015 Triple.getTriple() + TaskStr, 1016 Extension); 1017 if (!TempFileOrErr) 1018 reportError(TempFileOrErr.takeError()); 1019 TempFile = *TempFileOrErr; 1020 if (std::error_code EC = sys::fs::openFileForWrite(TempFile, FD)) 1021 reportError(errorCodeToError(EC)); 1022 return std::make_unique<CachedFileStream>( 1023 std::make_unique<llvm::raw_fd_ostream>(FD, true)); 1024 }; 1025 1026 if (Error Err = LTOBackend->run(AddStream)) 1027 return Err; 1028 1029 if (LTOError) 1030 return createStringError(inconvertibleErrorCode(), 1031 "Errors encountered inside the LTO pipeline."); 1032 1033 // If we are embedding bitcode we only need the intermediate output. 1034 bool SingleOutput = Files.size() == 1; 1035 if (Args.hasArg(OPT_embed_bitcode)) { 1036 if (BitcodeOutput.size() != 1 || !SingleOutput) 1037 return createStringError(inconvertibleErrorCode(), 1038 "Cannot embed bitcode with multiple files."); 1039 OutputFiles.push_back(static_cast<std::string>(BitcodeOutput.front())); 1040 return Error::success(); 1041 } 1042 1043 // Is we are compiling for NVPTX we need to run the assembler first. 1044 if (Triple.isNVPTX()) { 1045 for (StringRef &File : Files) { 1046 auto FileOrErr = nvptx::assemble(File, Args, !SingleOutput); 1047 if (!FileOrErr) 1048 return FileOrErr.takeError(); 1049 File = *FileOrErr; 1050 } 1051 } 1052 1053 // Append the new inputs to the device linker input. 1054 for (StringRef File : Files) 1055 OutputFiles.push_back(File); 1056 1057 return Error::success(); 1058 } 1059 1060 Expected<StringRef> writeOffloadFile(const OffloadFile &File) { 1061 const OffloadBinary &Binary = *File.getBinary(); 1062 1063 StringRef Prefix = 1064 sys::path::stem(Binary.getMemoryBufferRef().getBufferIdentifier()); 1065 StringRef Suffix = getImageKindName(Binary.getImageKind()); 1066 1067 auto TempFileOrErr = createOutputFile( 1068 Prefix + "-" + Binary.getTriple() + "-" + Binary.getArch(), Suffix); 1069 if (!TempFileOrErr) 1070 return TempFileOrErr.takeError(); 1071 1072 Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr = 1073 FileOutputBuffer::create(*TempFileOrErr, Binary.getImage().size()); 1074 if (!OutputOrErr) 1075 return OutputOrErr.takeError(); 1076 std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr); 1077 std::copy(Binary.getImage().bytes_begin(), Binary.getImage().bytes_end(), 1078 Output->getBufferStart()); 1079 if (Error E = Output->commit()) 1080 return std::move(E); 1081 1082 return *TempFileOrErr; 1083 } 1084 1085 // Compile the module to an object file using the appropriate target machine for 1086 // the host triple. 1087 Expected<StringRef> compileModule(Module &M) { 1088 llvm::TimeTraceScope TimeScope("Compile module"); 1089 std::string Msg; 1090 const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg); 1091 if (!T) 1092 return createStringError(inconvertibleErrorCode(), Msg); 1093 1094 auto Options = 1095 codegen::InitTargetOptionsFromCodeGenFlags(Triple(M.getTargetTriple())); 1096 StringRef CPU = ""; 1097 StringRef Features = ""; 1098 std::unique_ptr<TargetMachine> TM( 1099 T->createTargetMachine(M.getTargetTriple(), CPU, Features, Options, 1100 Reloc::PIC_, M.getCodeModel())); 1101 1102 if (M.getDataLayout().isDefault()) 1103 M.setDataLayout(TM->createDataLayout()); 1104 1105 int FD = -1; 1106 auto TempFileOrErr = 1107 createOutputFile(sys::path::filename(ExecutableName) + "-wrapper", "o"); 1108 if (!TempFileOrErr) 1109 return TempFileOrErr.takeError(); 1110 if (std::error_code EC = sys::fs::openFileForWrite(*TempFileOrErr, FD)) 1111 return errorCodeToError(EC); 1112 1113 auto OS = std::make_unique<llvm::raw_fd_ostream>(FD, true); 1114 1115 legacy::PassManager CodeGenPasses; 1116 TargetLibraryInfoImpl TLII(Triple(M.getTargetTriple())); 1117 CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII)); 1118 if (TM->addPassesToEmitFile(CodeGenPasses, *OS, nullptr, CGFT_ObjectFile)) 1119 return createStringError(inconvertibleErrorCode(), 1120 "Failed to execute host backend"); 1121 CodeGenPasses.run(M); 1122 1123 return *TempFileOrErr; 1124 } 1125 1126 /// Creates the object file containing the device image and runtime 1127 /// registration code from the device images stored in \p Images. 1128 Expected<StringRef> 1129 wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers, 1130 const ArgList &Args, OffloadKind Kind) { 1131 llvm::TimeTraceScope TimeScope("Wrap bundled images"); 1132 1133 SmallVector<ArrayRef<char>, 4> BuffersToWrap; 1134 for (const auto &Buffer : Buffers) 1135 BuffersToWrap.emplace_back( 1136 ArrayRef<char>(Buffer->getBufferStart(), Buffer->getBufferSize())); 1137 1138 LLVMContext Context; 1139 Module M("offload.wrapper.module", Context); 1140 M.setTargetTriple( 1141 Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple())); 1142 1143 switch (Kind) { 1144 case OFK_OpenMP: 1145 if (Error Err = wrapOpenMPBinaries(M, BuffersToWrap)) 1146 return std::move(Err); 1147 break; 1148 case OFK_Cuda: 1149 if (Error Err = wrapCudaBinary(M, BuffersToWrap.front())) 1150 return std::move(Err); 1151 break; 1152 case OFK_HIP: 1153 if (Error Err = wrapHIPBinary(M, BuffersToWrap.front())) 1154 return std::move(Err); 1155 break; 1156 default: 1157 return createStringError(inconvertibleErrorCode(), 1158 getOffloadKindName(Kind) + 1159 " wrapping is not supported"); 1160 } 1161 1162 if (Args.hasArg(OPT_print_wrapped_module)) 1163 errs() << M; 1164 1165 auto FileOrErr = compileModule(M); 1166 if (!FileOrErr) 1167 return FileOrErr.takeError(); 1168 return *FileOrErr; 1169 } 1170 1171 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>> 1172 bundleOpenMP(ArrayRef<OffloadingImage> Images) { 1173 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers; 1174 for (const OffloadingImage &Image : Images) 1175 Buffers.emplace_back( 1176 MemoryBuffer::getMemBufferCopy(Image.Image->getBuffer())); 1177 1178 return std::move(Buffers); 1179 } 1180 1181 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>> 1182 bundleCuda(ArrayRef<OffloadingImage> Images, const ArgList &Args) { 1183 SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles; 1184 for (const OffloadingImage &Image : Images) 1185 InputFiles.emplace_back(std::make_pair(Image.Image->getBufferIdentifier(), 1186 Image.StringData.lookup("arch"))); 1187 1188 Triple TheTriple = Triple(Images.front().StringData.lookup("triple")); 1189 auto FileOrErr = nvptx::fatbinary(InputFiles, Args); 1190 if (!FileOrErr) 1191 return FileOrErr.takeError(); 1192 1193 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError = 1194 llvm::MemoryBuffer::getFileOrSTDIN(*FileOrErr); 1195 1196 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers; 1197 if (std::error_code EC = ImageOrError.getError()) 1198 return createFileError(*FileOrErr, EC); 1199 Buffers.emplace_back(std::move(*ImageOrError)); 1200 1201 return std::move(Buffers); 1202 } 1203 1204 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>> 1205 bundleHIP(ArrayRef<OffloadingImage> Images, const ArgList &Args) { 1206 SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles; 1207 for (const OffloadingImage &Image : Images) 1208 InputFiles.emplace_back(std::make_pair(Image.Image->getBufferIdentifier(), 1209 Image.StringData.lookup("arch"))); 1210 1211 Triple TheTriple = Triple(Images.front().StringData.lookup("triple")); 1212 auto FileOrErr = amdgcn::fatbinary(InputFiles, Args); 1213 if (!FileOrErr) 1214 return FileOrErr.takeError(); 1215 1216 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError = 1217 llvm::MemoryBuffer::getFileOrSTDIN(*FileOrErr); 1218 1219 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers; 1220 if (std::error_code EC = ImageOrError.getError()) 1221 return createFileError(*FileOrErr, EC); 1222 Buffers.emplace_back(std::move(*ImageOrError)); 1223 1224 return std::move(Buffers); 1225 } 1226 1227 /// Transforms the input \p Images into the binary format the runtime expects 1228 /// for the given \p Kind. 1229 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>> 1230 bundleLinkedOutput(ArrayRef<OffloadingImage> Images, const ArgList &Args, 1231 OffloadKind Kind) { 1232 llvm::TimeTraceScope TimeScope("Bundle linked output"); 1233 switch (Kind) { 1234 case OFK_OpenMP: 1235 return bundleOpenMP(Images); 1236 case OFK_Cuda: 1237 return bundleCuda(Images, Args); 1238 case OFK_HIP: 1239 return bundleHIP(Images, Args); 1240 default: 1241 return createStringError(inconvertibleErrorCode(), 1242 getOffloadKindName(Kind) + 1243 " bundling is not supported"); 1244 } 1245 } 1246 1247 /// Returns a new ArgList containg arguments used for the device linking phase. 1248 DerivedArgList getLinkerArgs(ArrayRef<OffloadFile> Input, 1249 const InputArgList &Args) { 1250 DerivedArgList DAL = DerivedArgList(DerivedArgList(Args)); 1251 for (Arg *A : Args) 1252 DAL.append(A); 1253 1254 // Set the subarchitecture and target triple for this compilation. 1255 const OptTable &Tbl = getOptTable(); 1256 DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_arch_EQ), 1257 Args.MakeArgString(Input.front().getBinary()->getArch())); 1258 DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_triple_EQ), 1259 Args.MakeArgString(Input.front().getBinary()->getTriple())); 1260 1261 // If every input file is bitcode we have whole program visibility as we do 1262 // only support static linking with bitcode. 1263 auto ContainsBitcode = [](const OffloadFile &F) { 1264 return identify_magic(F.getBinary()->getImage()) == file_magic::bitcode; 1265 }; 1266 if (llvm::all_of(Input, ContainsBitcode)) 1267 DAL.AddFlagArg(nullptr, Tbl.getOption(OPT_whole_program)); 1268 1269 // Forward '-Xoffload-linker' options to the appropriate backend. 1270 for (StringRef Arg : Args.getAllArgValues(OPT_device_linker_args_EQ)) { 1271 auto TripleAndValue = Arg.split('='); 1272 if (TripleAndValue.second.empty()) 1273 DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_linker_arg_EQ), 1274 Args.MakeArgString(TripleAndValue.first)); 1275 else if (TripleAndValue.first == DAL.getLastArgValue(OPT_triple_EQ)) 1276 DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_linker_arg_EQ), 1277 Args.MakeArgString(TripleAndValue.second)); 1278 } 1279 1280 return DAL; 1281 } 1282 1283 /// Transforms all the extracted offloading input files into an image that can 1284 /// be registered by the runtime. 1285 Expected<SmallVector<StringRef>> 1286 linkAndWrapDeviceFiles(SmallVectorImpl<OffloadFile> &LinkerInputFiles, 1287 const InputArgList &Args) { 1288 llvm::TimeTraceScope TimeScope("Handle all device input"); 1289 1290 DenseMap<OffloadFile::TargetID, SmallVector<OffloadFile, 4>> InputsForTarget; 1291 for (auto &File : LinkerInputFiles) 1292 InputsForTarget[File].emplace_back(std::move(File)); 1293 LinkerInputFiles.clear(); 1294 1295 DenseMap<OffloadKind, SmallVector<OffloadingImage, 2>> Images; 1296 for (auto &InputForTarget : InputsForTarget) { 1297 llvm::TimeTraceScope TimeScope("Link device input"); 1298 1299 SmallVector<OffloadFile, 4> &Input = InputForTarget.getSecond(); 1300 auto LinkerArgs = getLinkerArgs(Input, Args); 1301 1302 DenseSet<OffloadKind> ActiveOffloadKinds; 1303 for (const auto &File : Input) 1304 ActiveOffloadKinds.insert(File.getBinary()->getOffloadKind()); 1305 1306 // First link and remove all the input files containing bitcode. 1307 SmallVector<StringRef> InputFiles; 1308 if (Error Err = linkBitcodeFiles(Input, InputFiles, LinkerArgs)) 1309 return std::move(Err); 1310 1311 // Write any remaining device inputs to an output file for the linker job. 1312 for (const OffloadFile &File : Input) { 1313 auto FileNameOrErr = writeOffloadFile(File); 1314 if (!FileNameOrErr) 1315 return FileNameOrErr.takeError(); 1316 InputFiles.emplace_back(*FileNameOrErr); 1317 } 1318 1319 // Link the remaining device files, if necessary, using the device linker. 1320 llvm::Triple Triple(LinkerArgs.getLastArgValue(OPT_triple_EQ)); 1321 bool RequiresLinking = 1322 !Args.hasArg(OPT_embed_bitcode) && 1323 !(Input.empty() && InputFiles.size() == 1 && Triple.isNVPTX()); 1324 auto OutputOrErr = RequiresLinking ? linkDevice(InputFiles, LinkerArgs) 1325 : InputFiles.front(); 1326 if (!OutputOrErr) 1327 return OutputOrErr.takeError(); 1328 1329 // Store the offloading image for each linked output file. 1330 for (OffloadKind Kind : ActiveOffloadKinds) { 1331 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr = 1332 llvm::MemoryBuffer::getFileOrSTDIN(*OutputOrErr); 1333 if (std::error_code EC = FileOrErr.getError()) 1334 return createFileError(*OutputOrErr, EC); 1335 1336 OffloadingImage TheImage{}; 1337 TheImage.TheImageKind = IMG_Object; 1338 TheImage.TheOffloadKind = Kind; 1339 TheImage.StringData = { 1340 {"triple", LinkerArgs.getLastArgValue(OPT_triple_EQ)}, 1341 {"arch", LinkerArgs.getLastArgValue(OPT_arch_EQ)}}; 1342 TheImage.Image = std::move(*FileOrErr); 1343 Images[Kind].emplace_back(std::move(TheImage)); 1344 } 1345 } 1346 1347 // Create a binary image of each offloading image and embed it into a new 1348 // object file. 1349 SmallVector<StringRef> WrappedOutput; 1350 for (const auto &KindAndImages : Images) { 1351 OffloadKind Kind = KindAndImages.first; 1352 auto BundledImagesOrErr = 1353 bundleLinkedOutput(KindAndImages.second, Args, Kind); 1354 if (!BundledImagesOrErr) 1355 return BundledImagesOrErr.takeError(); 1356 auto OutputOrErr = wrapDeviceImages(*BundledImagesOrErr, Args, Kind); 1357 if (!OutputOrErr) 1358 return OutputOrErr.takeError(); 1359 WrappedOutput.push_back(*OutputOrErr); 1360 } 1361 1362 return WrappedOutput; 1363 } 1364 1365 Optional<std::string> findFile(StringRef Dir, StringRef Root, 1366 const Twine &Name) { 1367 SmallString<128> Path; 1368 if (Dir.startswith("=")) 1369 sys::path::append(Path, Root, Dir.substr(1), Name); 1370 else 1371 sys::path::append(Path, Dir, Name); 1372 1373 if (sys::fs::exists(Path)) 1374 return static_cast<std::string>(Path); 1375 return None; 1376 } 1377 1378 Optional<std::string> findFromSearchPaths(StringRef Name, StringRef Root, 1379 ArrayRef<StringRef> SearchPaths) { 1380 for (StringRef Dir : SearchPaths) 1381 if (Optional<std::string> File = findFile(Dir, Root, Name)) 1382 return File; 1383 return None; 1384 } 1385 1386 Optional<std::string> searchLibraryBaseName(StringRef Name, StringRef Root, 1387 ArrayRef<StringRef> SearchPaths) { 1388 for (StringRef Dir : SearchPaths) { 1389 if (Optional<std::string> File = findFile(Dir, Root, "lib" + Name + ".so")) 1390 return None; 1391 if (Optional<std::string> File = findFile(Dir, Root, "lib" + Name + ".a")) 1392 return File; 1393 } 1394 return None; 1395 } 1396 1397 /// Search for static libraries in the linker's library path given input like 1398 /// `-lfoo` or `-l:libfoo.a`. 1399 Optional<std::string> searchLibrary(StringRef Input, StringRef Root, 1400 ArrayRef<StringRef> SearchPaths) { 1401 if (Input.startswith(":")) 1402 return findFromSearchPaths(Input.drop_front(), Root, SearchPaths); 1403 return searchLibraryBaseName(Input, Root, SearchPaths); 1404 } 1405 1406 /// Search the input files and libraries for embedded device offloading code and 1407 /// add it to the list of files to be linked. Files coming from static libraries 1408 /// are only added to the input if they are used by an existing input file. 1409 Expected<SmallVector<OffloadFile>> getDeviceInput(const ArgList &Args) { 1410 llvm::TimeTraceScope TimeScope("ExtractDeviceCode"); 1411 1412 StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ); 1413 SmallVector<StringRef> LibraryPaths; 1414 for (const opt::Arg *Arg : Args.filtered(OPT_library_path)) 1415 LibraryPaths.push_back(Arg->getValue()); 1416 1417 // Try to extract device code from the linker input files. 1418 SmallVector<OffloadFile> InputFiles; 1419 SmallVector<OffloadFile> LazyInputFiles; 1420 for (const opt::Arg *Arg : Args.filtered(OPT_INPUT)) { 1421 StringRef Filename = Arg->getValue(); 1422 if (!sys::fs::exists(Filename) || sys::fs::is_directory(Filename)) 1423 continue; 1424 1425 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 1426 MemoryBuffer::getFileOrSTDIN(Filename); 1427 if (std::error_code EC = BufferOrErr.getError()) 1428 reportError(createFileError(Filename, EC)); 1429 1430 bool IsLazy = 1431 identify_magic((*BufferOrErr)->getBuffer()) == file_magic::archive; 1432 if (Error Err = extractFromBuffer(std::move(*BufferOrErr), 1433 IsLazy ? LazyInputFiles : InputFiles)) 1434 reportError(std::move(Err)); 1435 } 1436 1437 // Try to extract input from input libraries. 1438 for (const opt::Arg *Arg : Args.filtered(OPT_library)) { 1439 if (auto Library = searchLibrary(Arg->getValue(), Root, LibraryPaths)) { 1440 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 1441 MemoryBuffer::getFileOrSTDIN(*Library); 1442 if (std::error_code EC = BufferOrErr.getError()) 1443 reportError(createFileError(*Library, EC)); 1444 1445 if (Error Err = 1446 extractFromBuffer(std::move(*BufferOrErr), LazyInputFiles)) 1447 reportError(std::move(Err)); 1448 } 1449 } 1450 1451 for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) { 1452 auto FileOrErr = getInputBitcodeLibrary(Library); 1453 if (!FileOrErr) 1454 reportError(FileOrErr.takeError()); 1455 InputFiles.push_back(std::move(*FileOrErr)); 1456 } 1457 1458 DenseSet<OffloadFile::TargetID> IsTargetUsed; 1459 for (const auto &File : InputFiles) 1460 IsTargetUsed.insert(File); 1461 1462 // We should only include input files that are used. 1463 // TODO: Only load a library if it defined undefined symbols in the input. 1464 for (auto &LazyFile : LazyInputFiles) 1465 if (IsTargetUsed.contains(LazyFile)) 1466 InputFiles.emplace_back(std::move(LazyFile)); 1467 1468 return std::move(InputFiles); 1469 } 1470 1471 } // namespace 1472 1473 int main(int Argc, char **Argv) { 1474 InitLLVM X(Argc, Argv); 1475 InitializeAllTargetInfos(); 1476 InitializeAllTargets(); 1477 InitializeAllTargetMCs(); 1478 InitializeAllAsmParsers(); 1479 InitializeAllAsmPrinters(); 1480 1481 LinkerExecutable = Argv[0]; 1482 sys::PrintStackTraceOnErrorSignal(Argv[0]); 1483 1484 const OptTable &Tbl = getOptTable(); 1485 BumpPtrAllocator Alloc; 1486 StringSaver Saver(Alloc); 1487 auto Args = Tbl.parseArgs(Argc, Argv, OPT_INVALID, Saver, [&](StringRef Err) { 1488 reportError(createStringError(inconvertibleErrorCode(), Err)); 1489 }); 1490 1491 if (Args.hasArg(OPT_help) || Args.hasArg(OPT_help_hidden)) { 1492 Tbl.printHelp( 1493 outs(), 1494 "clang-linker-wrapper [options] -- <options to passed to the linker>", 1495 "\nA wrapper utility over the host linker. It scans the input files\n" 1496 "for sections that require additional processing prior to linking.\n" 1497 "The will then transparently pass all arguments and input to the\n" 1498 "specified host linker to create the final binary.\n", 1499 Args.hasArg(OPT_help_hidden), Args.hasArg(OPT_help_hidden)); 1500 return EXIT_SUCCESS; 1501 } 1502 if (Args.hasArg(OPT_v)) { 1503 printVersion(outs()); 1504 return EXIT_SUCCESS; 1505 } 1506 1507 // This forwards '-mllvm' arguments to LLVM if present. 1508 SmallVector<const char *> NewArgv = {Argv[0]}; 1509 for (const opt::Arg *Arg : Args.filtered(OPT_mllvm)) 1510 NewArgv.push_back(Arg->getValue()); 1511 for (const opt::Arg *Arg : Args.filtered(OPT_offload_opt_eq_minus)) 1512 NewArgv.push_back(Args.MakeArgString(StringRef("-") + Arg->getValue())); 1513 cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]); 1514 1515 Verbose = Args.hasArg(OPT_verbose); 1516 DryRun = Args.hasArg(OPT_dry_run); 1517 SaveTemps = Args.hasArg(OPT_save_temps); 1518 ExecutableName = Args.getLastArgValue(OPT_o, "a.out"); 1519 CudaBinaryPath = Args.getLastArgValue(OPT_cuda_path_EQ).str(); 1520 if (!CudaBinaryPath.empty()) 1521 CudaBinaryPath = CudaBinaryPath + "/bin"; 1522 1523 if (Args.hasArg(OPT_wrapper_time_trace_eq)) { 1524 unsigned Granularity; 1525 Args.getLastArgValue(OPT_wrapper_time_trace_granularity, "500") 1526 .getAsInteger(10, Granularity); 1527 timeTraceProfilerInitialize(Granularity, Argv[0]); 1528 } 1529 1530 { 1531 llvm::TimeTraceScope TimeScope("Execute linker wrapper"); 1532 1533 // Extract the device input files stored in the host fat binary. 1534 auto DeviceInputFiles = getDeviceInput(Args); 1535 if (!DeviceInputFiles) 1536 reportError(DeviceInputFiles.takeError()); 1537 1538 // Link and wrap the device images extracted from the linker input. 1539 auto FilesOrErr = linkAndWrapDeviceFiles(*DeviceInputFiles, Args); 1540 if (!FilesOrErr) 1541 reportError(FilesOrErr.takeError()); 1542 1543 // Run the host linking job with the rendered arguments. 1544 if (Error Err = runLinker(*FilesOrErr, Args)) 1545 reportError(std::move(Err)); 1546 } 1547 1548 if (const opt::Arg *Arg = Args.getLastArg(OPT_wrapper_time_trace_eq)) { 1549 if (Error Err = timeTraceProfilerWrite(Arg->getValue(), ExecutableName)) 1550 reportError(std::move(Err)); 1551 timeTraceProfilerCleanup(); 1552 } 1553 1554 // Remove the temporary files created. 1555 if (!SaveTemps) 1556 for (const auto &TempFile : TempFiles) 1557 if (std::error_code EC = sys::fs::remove(TempFile)) 1558 reportError(createFileError(TempFile, EC)); 1559 1560 return EXIT_SUCCESS; 1561 } 1562