clang: lib/Driver/OffloadBundler.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

20#include "llvm/ADT/ArrayRef.h"

21#include "llvm/ADT/SmallString.h"

22#include "llvm/ADT/SmallVector.h"

23#include "llvm/ADT/StringExtras.h"

24#include "llvm/ADT/StringMap.h"

25#include "llvm/ADT/StringRef.h"

26#include "llvm/BinaryFormat/Magic.h"

27#include "llvm/Object/Archive.h"

28#include "llvm/Object/ArchiveWriter.h"

29#include "llvm/Object/Binary.h"

30#include "llvm/Object/ObjectFile.h"

31#include "llvm/Support/Casting.h"

32#include "llvm/Support/Compression.h"

33#include "llvm/Support/Debug.h"

34#include "llvm/Support/EndianStream.h"

35#include "llvm/Support/Errc.h"

36#include "llvm/Support/Error.h"

37#include "llvm/Support/ErrorOr.h"

38#include "llvm/Support/FileSystem.h"

39#include "llvm/Support/MD5.h"

40#include "llvm/Support/ManagedStatic.h"

41#include "llvm/Support/MemoryBuffer.h"

42#include "llvm/Support/Path.h"

43#include "llvm/Support/Program.h"

44#include "llvm/Support/Signals.h"

45#include "llvm/Support/StringSaver.h"

46#include "llvm/Support/Timer.h"

47#include "llvm/Support/WithColor.h"

48#include "llvm/Support/raw_ostream.h"

49#include "llvm/TargetParser/Host.h"

50#include "llvm/TargetParser/Triple.h"

51#include

52#include

53#include

54#include

55#include <forward_list>

56#include <llvm/Support/Process.h>

57#include

58#include

59#include

60#include <system_error>

61#include

62

63using namespace llvm;

64using namespace llvm::object;

65using namespace clang;

66

67namespace {

68struct CreateClangOffloadBundlerTimerGroup {

69 static void *call() {

70 return new TimerGroup("Clang Offload Bundler Timer Group",

71 "Timer group for clang offload bundler");

72 }

73};

74}

75static llvm::ManagedStatic<llvm::TimerGroup,

76 CreateClangOffloadBundlerTimerGroup>

78

79

80#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"

81

84 : BundlerConfig(BC) {

85

86

87 auto TargetFeatures = Target.split(':');

88 auto TripleOrGPU = TargetFeatures.first.rsplit('-');

89

92 auto KindTriple = TripleOrGPU.first.split('-');

94

95

96 llvm::Triple t = llvm::Triple(KindTriple.second);

97 this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(),

98 t.getOSName(), t.getEnvironmentName());

99

100 this->TargetID = Target.substr(Target.find(TripleOrGPU.second));

101 } else {

102 auto KindTriple = TargetFeatures.first.split('-');

104

105

106 llvm::Triple t = llvm::Triple(KindTriple.second);

107 this->Triple = llvm::Triple(t.getArchName(), t.getVendorName(),

108 t.getOSName(), t.getEnvironmentName());

109

111 }

112}

113

116}

117

121}

122

124 const StringRef TargetOffloadKind) const {

125 if ((OffloadKind == TargetOffloadKind) ||

126 (OffloadKind == "hip" && TargetOffloadKind == "hipv4") ||

127 (OffloadKind == "hipv4" && TargetOffloadKind == "hip"))

128 return true;

129

131 bool HIPCompatibleWithOpenMP = OffloadKind.starts_with_insensitive("hip") &&

132 TargetOffloadKind == "openmp";

133 bool OpenMPCompatibleWithHIP =

135 TargetOffloadKind.starts_with_insensitive("hip");

136 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;

137 }

138 return false;

139}

140

142 return Triple.str().empty() && Triple.getArch() != Triple::UnknownArch;

143}

144

148}

149

152}

153

155 StringRef BundleFileName) {

156 if (Device.contains("gfx"))

157 return ".bc";

158 if (Device.contains("sm_"))

159 return ".cubin";

160 return sys::path::extension(BundleFileName);

161}

162

165 StringRef LibName = sys::path::stem(BundleFileName);

167

172}

173

174namespace {

175

176class FileHandler {

177public:

178 struct BundleInfo {

179 StringRef BundleID;

180 };

181

182 FileHandler() {}

183

184 virtual ~FileHandler() {}

185

186

187

188 virtual Error ReadHeader(MemoryBuffer &Input) = 0;

189

190

191

192

194 ReadBundleStart(MemoryBuffer &Input) = 0;

195

196

197 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;

198

199

200 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;

201

202

203

204 virtual Error WriteHeader(raw_ostream &OS,

205 ArrayRef<std::unique_ptr> Inputs) = 0;

206

207

208

209 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;

210

211

212

213 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;

214

215

216 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;

217

218

219 virtual Error finalizeOutputFile() { return Error::success(); }

220

221

222 virtual Error listBundleIDs(MemoryBuffer &Input) {

223 if (Error Err = ReadHeader(Input))

224 return Err;

225 return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {

226 llvm::outs() << Info.BundleID << '\n';

227 Error Err = listBundleIDsCallback(Input, Info);

228 if (Err)

229 return Err;

230 return Error::success();

231 });

232 }

233

234

235 virtual Error getBundleIDs(MemoryBuffer &Input,

236 std::set &BundleIds) {

237 if (Error Err = ReadHeader(Input))

238 return Err;

239 return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {

240 BundleIds.insert(Info.BundleID);

241 Error Err = listBundleIDsCallback(Input, Info);

242 if (Err)

243 return Err;

244 return Error::success();

245 });

246 }

247

248

249 Error forEachBundle(MemoryBuffer &Input,

250 std::function<Error(const BundleInfo &)> Func) {

251 while (true) {

253 ReadBundleStart(Input);

254 if (!CurTripleOrErr)

255 return CurTripleOrErr.takeError();

256

257

258 if (!*CurTripleOrErr)

259 break;

260

261 StringRef CurTriple = **CurTripleOrErr;

262 assert(!CurTriple.empty());

263

264 BundleInfo Info{CurTriple};

265 if (Error Err = Func(Info))

266 return Err;

267 }

268 return Error::success();

269 }

270

271protected:

272 virtual Error listBundleIDsCallback(MemoryBuffer &Input,

273 const BundleInfo &Info) {

274 return Error::success();

275 }

276};

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {

303 return llvm::support::endian::read64le(Buffer.data() + pos);

304}

305

306

307static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {

308 llvm::support::endian::write(OS, Val, llvm::endianness::little);

309}

310

311class BinaryFileHandler final : public FileHandler {

312

313 struct BinaryBundleInfo final : public BundleInfo {

314

316

318

319 BinaryBundleInfo() {}

320 BinaryBundleInfo(uint64_t Size, uint64_t Offset)

321 : Size(Size), Offset(Offset) {}

322 };

323

324

325 StringMap BundlesInfo;

326

327

328 StringMap::iterator CurBundleInfo;

329 StringMap::iterator NextBundleInfo;

330

331

332 std::string CurWriteBundleTarget;

333

334

336

337public:

338

340

341 ~BinaryFileHandler() final {}

342

343 Error ReadHeader(MemoryBuffer &Input) final {

344 StringRef FC = Input.getBuffer();

345

346

347 CurBundleInfo = BundlesInfo.end();

348

349

351 if (ReadChars > FC.size())

352 return Error::success();

353

354

355 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)

356 return Error::success();

357

358

359 if (ReadChars + 8 > FC.size())

360 return Error::success();

361

362 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);

363 ReadChars += 8;

364

365

366 for (uint64_t i = 0; i < NumberOfBundles; ++i) {

367

368

369 if (ReadChars + 8 > FC.size())

370 return Error::success();

371

372 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);

373 ReadChars += 8;

374

375

376 if (ReadChars + 8 > FC.size())

377 return Error::success();

378

379 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);

380 ReadChars += 8;

381

382

383 if (ReadChars + 8 > FC.size())

384 return Error::success();

385

386 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);

387 ReadChars += 8;

388

389

390 if (ReadChars + TripleSize > FC.size())

391 return Error::success();

392

393 StringRef Triple(&FC.data()[ReadChars], TripleSize);

394 ReadChars += TripleSize;

395

396

397 if (!Offset || Offset + Size > FC.size())

398 return Error::success();

399

400 assert(!BundlesInfo.contains(Triple) && "Triple is duplicated??");

401 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);

402 }

403

404 CurBundleInfo = BundlesInfo.end();

405 NextBundleInfo = BundlesInfo.begin();

406 return Error::success();

407 }

408

410 ReadBundleStart(MemoryBuffer &Input) final {

411 if (NextBundleInfo == BundlesInfo.end())

412 return std::nullopt;

413 CurBundleInfo = NextBundleInfo++;

414 return CurBundleInfo->first();

415 }

416

417 Error ReadBundleEnd(MemoryBuffer &Input) final {

418 assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");

419 return Error::success();

420 }

421

422 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {

423 assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");

424 StringRef FC = Input.getBuffer();

425 OS.write(FC.data() + CurBundleInfo->second.Offset,

426 CurBundleInfo->second.Size);

427 return Error::success();

428 }

429

430 Error WriteHeader(raw_ostream &OS,

431 ArrayRef<std::unique_ptr> Inputs) final {

432

433

435

437 HeaderSize += 8;

438

440 HeaderSize += 3 * 8;

441 HeaderSize += T.size();

442 }

443

444

446

447 Write8byteIntegerToBuffer(OS, BundlerConfig.TargetNames.size());

448

449 unsigned Idx = 0;

451 MemoryBuffer &MB = *Inputs[Idx++];

452 HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment);

453

454 Write8byteIntegerToBuffer(OS, HeaderSize);

455

456 Write8byteIntegerToBuffer(OS, MB.getBufferSize());

457 BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);

458 HeaderSize += MB.getBufferSize();

459

460 Write8byteIntegerToBuffer(OS, T.size());

461

462 OS << T;

463 }

464 return Error::success();

465 }

466

467 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final {

468 CurWriteBundleTarget = TargetTriple.str();

469 return Error::success();

470 }

471

472 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final {

473 return Error::success();

474 }

475

476 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final {

477 auto BI = BundlesInfo[CurWriteBundleTarget];

478

479

480 size_t CurrentPos = OS.tell();

481 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;

482 for (size_t I = 0; I < PaddingSize; ++I)

483 OS.write('\0');

484 assert(OS.tell() == BI.Offset);

485

486 OS.write(Input.getBufferStart(), Input.getBufferSize());

487

488 return Error::success();

489 }

490};

491

492

493

494class TempFileHandlerRAII {

495public:

496 ~TempFileHandlerRAII() {

497 for (const auto &File : Files)

498 sys::fs::remove(File);

499 }

500

501

504 if (std::error_code EC =

505 sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File))

506 return createFileError(File, EC);

507 Files.push_front(File);

508

509 if (Contents) {

510 std::error_code EC;

511 raw_fd_ostream OS(File, EC);

512 if (EC)

513 return createFileError(File, EC);

514 OS.write(Contents->data(), Contents->size());

515 }

516 return Files.front().str();

517 }

518

519private:

520 std::forward_list<SmallString<128u>> Files;

521};

522

523

524

525

526

527class ObjectFileHandler final : public FileHandler {

528

529

530 std::unique_ptr Obj;

531

532

533 StringRef getInputFileContents() const { return Obj->getData(); }

534

535

536

538 IsOffloadSection(SectionRef CurSection) {

540 if (!NameOrErr)

541 return NameOrErr.takeError();

542

543

544 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)

545 return std::nullopt;

546

547

549 }

550

551

552 unsigned NumberOfInputs = 0;

553

554

555

556 unsigned NumberOfProcessedInputs = 0;

557

558

559 section_iterator CurrentSection;

560 section_iterator NextSection;

561

562

564

565public:

566

567 ObjectFileHandler(std::unique_ptr ObjIn,

569 : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),

570 NextSection(Obj->section_begin()), BundlerConfig(BC) {}

571

572 ~ObjectFileHandler() final {}

573

574 Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }

575

577 ReadBundleStart(MemoryBuffer &Input) final {

578 while (NextSection != Obj->section_end()) {

579 CurrentSection = NextSection;

580 ++NextSection;

581

582

583

585 IsOffloadSection(*CurrentSection);

586 if (!TripleOrErr)

587 return TripleOrErr.takeError();

588 if (*TripleOrErr)

589 return **TripleOrErr;

590 }

591 return std::nullopt;

592 }

593

594 Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }

595

596 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {

598 if (!ContentOrErr)

599 return ContentOrErr.takeError();

600 StringRef Content = *ContentOrErr;

601

602

603 std::string ModifiedContent;

604 if (Content.size() == 1u && Content.front() == 0) {

605 auto HostBundleOrErr = getHostBundle(

606 StringRef(Input.getBufferStart(), Input.getBufferSize()));

607 if (!HostBundleOrErr)

608 return HostBundleOrErr.takeError();

609

610 ModifiedContent = std::move(*HostBundleOrErr);

611 Content = ModifiedContent;

612 }

613

614 OS.write(Content.data(), Content.size());

615 return Error::success();

616 }

617

618 Error WriteHeader(raw_ostream &OS,

619 ArrayRef<std::unique_ptr> Inputs) final {

621 "Host input index not defined.");

622

623

624 NumberOfInputs = Inputs.size();

625 return Error::success();

626 }

627

628 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final {

629 ++NumberOfProcessedInputs;

630 return Error::success();

631 }

632

633 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final {

634 return Error::success();

635 }

636

637 Error finalizeOutputFile() final {

638 assert(NumberOfProcessedInputs <= NumberOfInputs &&

639 "Processing more inputs that actually exist!");

641 "Host input index not defined.");

642

643

644 if (NumberOfProcessedInputs != NumberOfInputs)

645 return Error::success();

646

647

648

649

650

651

652 assert(BundlerConfig.ObjcopyPath != "" &&

653 "llvm-objcopy path not specified");

654

655

656 TempFileHandlerRAII TempFiles;

657

658

659

660 BumpPtrAllocator Alloc;

661 StringSaver SS{Alloc};

663

664 for (unsigned I = 0; I < NumberOfInputs; ++I) {

665 StringRef InputFile = BundlerConfig.InputFileNames[I];

667

668

669

670

672 if (!TempFileOrErr)

673 return TempFileOrErr.takeError();

674 InputFile = *TempFileOrErr;

675 }

676

677 ObjcopyArgs.push_back(

679 BundlerConfig.TargetNames[I] + "=" + InputFile));

680 ObjcopyArgs.push_back(

682 BundlerConfig.TargetNames[I] + "=readonly,exclude"));

683 }

684 ObjcopyArgs.push_back("--");

685 ObjcopyArgs.push_back(

687 ObjcopyArgs.push_back(BundlerConfig.OutputFileNames.front());

688

689 if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))

690 return Err;

691

692 return Error::success();

693 }

694

695 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final {

696 return Error::success();

697 }

698

699private:

701

702

704 errs() << "\"" << Objcopy << "\"";

705 for (StringRef Arg : drop_begin(Args, 1))

706 errs() << " \"" << Arg << "\"";

707 errs() << "\n";

708 } else {

709 if (sys::ExecuteAndWait(Objcopy, Args))

710 return createStringError(inconvertibleErrorCode(),

711 "'llvm-objcopy' tool failed");

712 }

713 return Error::success();

714 }

715

717 TempFileHandlerRAII TempFiles;

718

719 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);

720 if (!ModifiedObjPathOrErr)

721 return ModifiedObjPathOrErr.takeError();

722 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;

723

724 BumpPtrAllocator Alloc;

725 StringSaver SS{Alloc};

727

728 ObjcopyArgs.push_back("--regex");

729 ObjcopyArgs.push_back("--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");

730 ObjcopyArgs.push_back("--");

731

732 StringRef ObjcopyInputFileName;

733

734

735

736

737

738

739 if (StringRef(BundlerConfig.FilesType).starts_with("a")) {

740 auto InputFileOrErr =

741 TempFiles.Create(ArrayRef(Input.data(), Input.size()));

742 if (!InputFileOrErr)

743 return InputFileOrErr.takeError();

744 ObjcopyInputFileName = *InputFileOrErr;

745 } else

746 ObjcopyInputFileName = BundlerConfig.InputFileNames.front();

747

748 ObjcopyArgs.push_back(ObjcopyInputFileName);

749 ObjcopyArgs.push_back(ModifiedObjPath);

750

751 if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))

752 return std::move(Err);

753

754 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);

755 if (!BufOrErr)

756 return createStringError(BufOrErr.getError(),

757 "Failed to read back the modified object file");

758

759 return BufOrErr->get()->getBuffer().str();

760 }

761};

762

763

764

765

766

767

768

769

770

771

772class TextFileHandler final : public FileHandler {

773

774 StringRef Comment;

775

776

777 std::string BundleStartString;

778

779

780 std::string BundleEndString;

781

782

783 size_t ReadChars = 0u;

784

785protected:

786 Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }

787

789 ReadBundleStart(MemoryBuffer &Input) final {

790 StringRef FC = Input.getBuffer();

791

792

793 ReadChars = FC.find(BundleStartString, ReadChars);

794 if (ReadChars == FC.npos)

795 return std::nullopt;

796

797

798 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();

799

800

801 size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);

802 if (TripleEnd == FC.npos)

803 return std::nullopt;

804

805

806 ++ReadChars;

807

808 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);

809 }

810

811 Error ReadBundleEnd(MemoryBuffer &Input) final {

812 StringRef FC = Input.getBuffer();

813

814

815 assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");

816

817 size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);

818 if (TripleEnd != FC.npos)

819

820 ++ReadChars;

821

822 return Error::success();

823 }

824

825 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {

826 StringRef FC = Input.getBuffer();

827 size_t BundleStart = ReadChars;

828

829

830 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);

831

832 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);

833 OS << Bundle;

834

835 return Error::success();

836 }

837

838 Error WriteHeader(raw_ostream &OS,

839 ArrayRef<std::unique_ptr> Inputs) final {

840 return Error::success();

841 }

842

843 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) final {

844 OS << BundleStartString << TargetTriple << "\n";

845 return Error::success();

846 }

847

848 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) final {

849 OS << BundleEndString << TargetTriple << "\n";

850 return Error::success();

851 }

852

853 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) final {

854 OS << Input.getBuffer();

855 return Error::success();

856 }

857

858public:

859 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {

860 BundleStartString =

862 BundleEndString =

864 }

865

866 Error listBundleIDsCallback(MemoryBuffer &Input,

867 const BundleInfo &Info) final {

868

869

870

871

872 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);

873 if (Error Err = ReadBundleEnd(Input))

874 return Err;

875 return Error::success();

876 }

877};

878}

879

880

881

882

883static std::unique_ptr

886

888

889

890

891 if (errorToBool(BinaryOrErr.takeError()) || !isa(*BinaryOrErr))

892 return std::make_unique(BundlerConfig);

893

894

895

896 return std::make_unique(

897 std::unique_ptr(cast(BinaryOrErr->release())),

898 BundlerConfig);

899}

900

901

905 std::string FilesType = BundlerConfig.FilesType;

906

907 if (FilesType == "i")

908 return std::make_unique("//");

909 if (FilesType == "ii")

910 return std::make_unique("//");

911 if (FilesType == "cui")

912 return std::make_unique("//");

913 if (FilesType == "hipi")

914 return std::make_unique("//");

915

916

917 if (FilesType == "d")

918 return std::make_unique("#");

919 if (FilesType == "ll")

920 return std::make_unique(";");

921 if (FilesType == "bc")

922 return std::make_unique(BundlerConfig);

923 if (FilesType == "s")

924 return std::make_unique("#");

925 if (FilesType == "o")

927 if (FilesType == "a")

929 if (FilesType == "gch")

930 return std::make_unique(BundlerConfig);

931 if (FilesType == "ast")

932 return std::make_unique(BundlerConfig);

933

934 return createStringError(errc::invalid_argument,

935 "'" + FilesType + "': invalid file type specified");

936}

937

940 if (llvm::compression::zstd::isAvailable()) {

942

943

945 } else if (llvm::compression::zlib::isAvailable()) {

947

948

949 CompressionLevel = llvm::compression::zlib::DefaultCompression;

950 }

951 auto IgnoreEnvVarOpt =

952 llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_IGNORE_ENV_VAR");

953 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() == "1")

954 return;

955 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_VERBOSE");

956 if (VerboseEnvVarOpt.has_value())

957 Verbose = VerboseEnvVarOpt.value() == "1";

958 auto CompressEnvVarOpt =

959 llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_COMPRESS");

960 if (CompressEnvVarOpt.has_value())

961 Compress = CompressEnvVarOpt.value() == "1";

962 auto CompressionLevelEnvVarOpt =

963 llvm::sys::Process::GetEnv("OFFLOAD_BUNDLER_COMPRESSION_LEVEL");

964 if (CompressionLevelEnvVarOpt.has_value()) {

965 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();

966 int Level;

967 if (!CompressionLevelStr.getAsInteger(10, Level))

969 else

970 llvm::errs()

971 << "Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "

972 << CompressionLevelStr.str() << ". Ignoring it.\n";

973 }

974 auto CompressedBundleFormatVersionOpt =

975 llvm::sys::Process::GetEnv("COMPRESSED_BUNDLE_FORMAT_VERSION");

976 if (CompressedBundleFormatVersionOpt.has_value()) {

977 llvm::StringRef VersionStr = CompressedBundleFormatVersionOpt.value();

978 uint16_t Version;

979 if (!VersionStr.getAsInteger(10, Version)) {

980 if (Version >= 2 && Version <= 3)

982 else

983 llvm::errs()

984 << "Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "

985 << VersionStr.str()

986 << ". Valid values are 2 or 3. Using default version "

988 } else

989 llvm::errs()

990 << "Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "

991 << VersionStr.str() << ". Using default version "

993 }

994}

995

996

998 std::string Num = std::to_string(Value);

999 int InsertPosition = Num.length() - 3;

1000 while (InsertPosition > 0) {

1001 Num.insert(InsertPosition, ",");

1002 InsertPosition -= 3;

1003 }

1004 return Num;

1005}

1006

1009 const llvm::MemoryBuffer &Input,

1010 uint16_t Version, bool Verbose) {

1011 if (!llvm::compression::zstd::isAvailable() &&

1012 !llvm::compression::zlib::isAvailable())

1013 return createStringError(llvm::inconvertibleErrorCode(),

1014 "Compression not supported");

1015 llvm::Timer HashTimer("Hash Calculation Timer", "Hash calculation time",

1017 if (Verbose)

1018 HashTimer.startTimer();

1019 llvm::MD5 Hash;

1020 llvm::MD5::MD5Result Result;

1021 Hash.update(Input.getBuffer());

1023 uint64_t TruncatedHash = Result.low();

1024 if (Verbose)

1025 HashTimer.stopTimer();

1026

1029 reinterpret_cast<const uint8_t *>(Input.getBuffer().data()),

1030 Input.getBuffer().size());

1031 llvm::Timer CompressTimer("Compression Timer", "Compression time",

1033 if (Verbose)

1034 CompressTimer.startTimer();

1035 llvm::compression::compress(P, BufferUint8, CompressedBuffer);

1036 if (Verbose)

1037 CompressTimer.stopTimer();

1038

1039 uint16_t CompressionMethod = static_cast<uint16_t>(P.format);

1040

1041

1042 uint64_t UncompressedSize64 = Input.getBuffer().size();

1043 uint64_t TotalFileSize64;

1044

1045

1046 if (Version == 2) {

1047

1048 if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())

1049 return createStringError(llvm::inconvertibleErrorCode(),

1050 "Uncompressed size exceeds version 2 limit");

1051 if ((MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +

1052 sizeof(CompressionMethod) + sizeof(uint32_t) + sizeof(TruncatedHash) +

1053 CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())

1054 return createStringError(llvm::inconvertibleErrorCode(),

1055 "Total file size exceeds version 2 limit");

1056

1057 TotalFileSize64 = MagicNumber.size() + sizeof(uint32_t) + sizeof(Version) +

1058 sizeof(CompressionMethod) + sizeof(uint32_t) +

1059 sizeof(TruncatedHash) + CompressedBuffer.size();

1060 } else {

1061 TotalFileSize64 = MagicNumber.size() + sizeof(uint64_t) + sizeof(Version) +

1062 sizeof(CompressionMethod) + sizeof(uint64_t) +

1063 sizeof(TruncatedHash) + CompressedBuffer.size();

1064 }

1065

1067 llvm::raw_svector_ostream OS(FinalBuffer);

1068 OS << MagicNumber;

1069 OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));

1070 OS.write(reinterpret_cast<const char *>(&CompressionMethod),

1071 sizeof(CompressionMethod));

1072

1073

1074 if (Version == 2) {

1075 uint32_t TotalFileSize32 = static_cast<uint32_t>(TotalFileSize64);

1076 uint32_t UncompressedSize32 = static_cast<uint32_t>(UncompressedSize64);

1077 OS.write(reinterpret_cast<const char *>(&TotalFileSize32),

1078 sizeof(TotalFileSize32));

1079 OS.write(reinterpret_cast<const char *>(&UncompressedSize32),

1080 sizeof(UncompressedSize32));

1081 } else {

1082 OS.write(reinterpret_cast<const char *>(&TotalFileSize64),

1083 sizeof(TotalFileSize64));

1084 OS.write(reinterpret_cast<const char *>(&UncompressedSize64),

1085 sizeof(UncompressedSize64));

1086 }

1087

1088 OS.write(reinterpret_cast<const char *>(&TruncatedHash),

1089 sizeof(TruncatedHash));

1090 OS.write(reinterpret_cast<const char *>(CompressedBuffer.data()),

1091 CompressedBuffer.size());

1092

1093 if (Verbose) {

1094 auto MethodUsed =

1095 P.format == llvm::compression::Format::Zstd ? "zstd" : "zlib";

1096 double CompressionRate =

1097 static_cast<double>(UncompressedSize64) / CompressedBuffer.size();

1098 double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();

1099 double CompressionSpeedMBs =

1100 (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;

1101 llvm::errs() << "Compressed bundle format version: " << Version << "\n"

1102 << "Total file size (including headers): "

1104 << "Compression method used: " << MethodUsed << "\n"

1105 << "Compression level: " << P.level << "\n"

1106 << "Binary size before compression: "

1108 << "Binary size after compression: "

1110 << "Compression rate: "

1111 << llvm::format("%.2lf", CompressionRate) << "\n"

1112 << "Compression ratio: "

1113 << llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"

1114 << "Compression speed: "

1115 << llvm::format("%.2lf MB/s", CompressionSpeedMBs) << "\n"

1116 << "Truncated MD5 hash: "

1117 << llvm::format_hex(TruncatedHash, 16) << "\n";

1118 }

1119

1120 return llvm::MemoryBuffer::getMemBufferCopy(

1121 llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));

1122}

1123

1126 bool Verbose) {

1127 StringRef Blob = Input.getBuffer();

1128

1129

1130 if (Blob.size() < V1HeaderSize)

1131 return llvm::MemoryBuffer::getMemBufferCopy(Blob);

1132

1133 if (llvm::identify_magic(Blob) !=

1134 llvm::file_magic::offload_bundle_compressed) {

1135 if (Verbose)

1136 llvm::errs() << "Uncompressed bundle.\n";

1137 return llvm::MemoryBuffer::getMemBufferCopy(Blob);

1138 }

1139

1140 size_t CurrentOffset = MagicSize;

1141

1142

1143 uint16_t ThisVersion;

1144 memcpy(&ThisVersion, Blob.data() + CurrentOffset, sizeof(uint16_t));

1145 CurrentOffset += VersionFieldSize;

1146

1147

1148 if (ThisVersion >= 2 && ThisVersion <= 3) {

1149 size_t RequiredSize = (ThisVersion == 2) ? V2HeaderSize : V3HeaderSize;

1150 if (Blob.size() < RequiredSize)

1151 return createStringError(inconvertibleErrorCode(),

1152 "Compressed bundle header size too small");

1153 }

1154

1155

1156 uint16_t CompressionMethod;

1157 memcpy(&CompressionMethod, Blob.data() + CurrentOffset, sizeof(uint16_t));

1158 CurrentOffset += MethodFieldSize;

1159

1160

1161 uint64_t TotalFileSize = 0;

1162 if (ThisVersion >= 2) {

1163 if (ThisVersion == 2) {

1164 uint32_t TotalFileSize32;

1165 memcpy(&TotalFileSize32, Blob.data() + CurrentOffset, sizeof(uint32_t));

1166 TotalFileSize = TotalFileSize32;

1167 CurrentOffset += FileSizeFieldSizeV2;

1168 } else {

1169 memcpy(&TotalFileSize, Blob.data() + CurrentOffset, sizeof(uint64_t));

1170 CurrentOffset += FileSizeFieldSizeV3;

1171 }

1172 }

1173

1174

1175 uint64_t UncompressedSize = 0;

1176 if (ThisVersion <= 2) {

1177 uint32_t UncompressedSize32;

1178 memcpy(&UncompressedSize32, Blob.data() + CurrentOffset, sizeof(uint32_t));

1179 UncompressedSize = UncompressedSize32;

1180 CurrentOffset += UncompressedSizeFieldSizeV2;

1181 } else {

1182 memcpy(&UncompressedSize, Blob.data() + CurrentOffset, sizeof(uint64_t));

1183 CurrentOffset += UncompressedSizeFieldSizeV3;

1184 }

1185

1186

1187 uint64_t StoredHash;

1188 memcpy(&StoredHash, Blob.data() + CurrentOffset, sizeof(uint64_t));

1189 CurrentOffset += HashFieldSize;

1190

1191

1192 llvm::compression::Format CompressionFormat;

1193 if (CompressionMethod ==

1194 static_cast<uint16_t>(llvm::compression::Format::Zlib))

1195 CompressionFormat = llvm::compression::Format::Zlib;

1196 else if (CompressionMethod ==

1197 static_cast<uint16_t>(llvm::compression::Format::Zstd))

1198 CompressionFormat = llvm::compression::Format::Zstd;

1199 else

1200 return createStringError(inconvertibleErrorCode(),

1201 "Unknown compressing method");

1202

1203 llvm::Timer DecompressTimer("Decompression Timer", "Decompression time",

1205 if (Verbose)

1206 DecompressTimer.startTimer();

1207

1209 StringRef CompressedData = Blob.substr(CurrentOffset);

1210 if (llvm::Error DecompressionError = llvm::compression::decompress(

1211 CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),

1212 DecompressedData, UncompressedSize))

1213 return createStringError(inconvertibleErrorCode(),

1214 "Could not decompress embedded file contents: " +

1215 llvm::toString(std::move(DecompressionError)));

1216

1217 if (Verbose) {

1218 DecompressTimer.stopTimer();

1219

1220 double DecompressionTimeSeconds =

1221 DecompressTimer.getTotalTime().getWallTime();

1222

1223

1224 llvm::Timer HashRecalcTimer("Hash Recalculation Timer",

1225 "Hash recalculation time",

1227 HashRecalcTimer.startTimer();

1228 llvm::MD5 Hash;

1229 llvm::MD5::MD5Result Result;

1231 DecompressedData.size()));

1233 uint64_t RecalculatedHash = Result.low();

1234 HashRecalcTimer.stopTimer();

1235 bool HashMatch = (StoredHash == RecalculatedHash);

1236

1237 double CompressionRate =

1238 static_cast<double>(UncompressedSize) / CompressedData.size();

1239 double DecompressionSpeedMBs =

1240 (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;

1241

1242 llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n";

1243 if (ThisVersion >= 2)

1244 llvm::errs() << "Total file size (from header): "

1246 llvm::errs() << "Decompression method: "

1247 << (CompressionFormat == llvm::compression::Format::Zlib

1248 ? "zlib"

1249 : "zstd")

1250 << "\n"

1251 << "Size before decompression: "

1253 << "Size after decompression: "

1255 << "Compression rate: "

1256 << llvm::format("%.2lf", CompressionRate) << "\n"

1257 << "Compression ratio: "

1258 << llvm::format("%.2lf%%", 100.0 / CompressionRate) << "\n"

1259 << "Decompression speed: "

1260 << llvm::format("%.2lf MB/s", DecompressionSpeedMBs) << "\n"

1261 << "Stored hash: " << llvm::format_hex(StoredHash, 16) << "\n"

1262 << "Recalculated hash: "

1263 << llvm::format_hex(RecalculatedHash, 16) << "\n"

1264 << "Hashes match: " << (HashMatch ? "Yes" : "No") << "\n";

1265 }

1266

1267 return llvm::MemoryBuffer::getMemBufferCopy(

1268 llvm::toStringRef(DecompressedData));

1269}

1270

1271

1274

1275 ErrorOr<std::unique_ptr> CodeOrErr =

1276 MemoryBuffer::getFileOrSTDIN(InputFileName, true);

1277 if (std::error_code EC = CodeOrErr.getError())

1278 return createFileError(InputFileName, EC);

1279

1280

1283 if (!DecompressedBufferOrErr)

1284 return createStringError(

1285 inconvertibleErrorCode(),

1286 "Failed to decompress input: " +

1287 llvm::toString(DecompressedBufferOrErr.takeError()));

1288

1289 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;

1290

1291

1294 if (!FileHandlerOrErr)

1295 return FileHandlerOrErr.takeError();

1296

1297 std::unique_ptr &FH = *FileHandlerOrErr;

1298 assert(FH);

1299 return FH->listBundleIDs(DecompressedInput);

1300}

1301

1302

1303

1304

1307

1308

1310 DEBUG_WITH_TYPE("CodeObjectCompatibility",

1311 dbgs() << "Compatible: Exact match: \t[CodeObject: "

1312 << CodeObjectInfo.str()

1313 << "]\t:\t[Target: " << TargetInfo.str() << "]\n");

1314 return true;

1315 }

1316

1317

1319 !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {

1320 DEBUG_WITH_TYPE(

1321 "CodeObjectCompatibility",

1322 dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "

1323 << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()

1324 << "]\n");

1325 return false;

1326 }

1327

1328

1329 llvm::StringMap CodeObjectFeatureMap, TargetFeatureMap;

1331 CodeObjectInfo.Triple, CodeObjectInfo.TargetID, &CodeObjectFeatureMap);

1334

1335

1336 if (!TargetProc || !CodeObjectProc ||

1337 CodeObjectProc.value() != TargetProc.value()) {

1338 DEBUG_WITH_TYPE("CodeObjectCompatibility",

1339 dbgs() << "Incompatible: Processor mismatch \t[CodeObject: "

1340 << CodeObjectInfo.str()

1341 << "]\t:\t[Target: " << TargetInfo.str() << "]\n");

1342 return false;

1343 }

1344

1345

1346

1347 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {

1348 DEBUG_WITH_TYPE("CodeObjectCompatibility",

1349 dbgs() << "Incompatible: CodeObject has more features "

1350 "than target \t[CodeObject: "

1351 << CodeObjectInfo.str()

1352 << "]\t:\t[Target: " << TargetInfo.str() << "]\n");

1353 return false;

1354 }

1355

1356

1357

1358

1359

1360 for (const auto &CodeObjectFeature : CodeObjectFeatureMap) {

1361 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());

1362 if (TargetFeature == TargetFeatureMap.end()) {

1363 DEBUG_WITH_TYPE(

1364 "CodeObjectCompatibility",

1365 dbgs()

1366 << "Incompatible: Value of CodeObject's non-ANY feature is "

1367 "not matching with Target feature's ANY value \t[CodeObject: "

1368 << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()

1369 << "]\n");

1370 return false;

1371 } else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {

1372 DEBUG_WITH_TYPE(

1373 "CodeObjectCompatibility",

1374 dbgs() << "Incompatible: Value of CodeObject's non-ANY feature is "

1375 "not matching with Target feature's non-ANY value "

1376 "\t[CodeObject: "

1377 << CodeObjectInfo.str()

1378 << "]\t:\t[Target: " << TargetInfo.str() << "]\n");

1379 return false;

1380 }

1381 }

1382

1383

1384

1385

1386

1387 DEBUG_WITH_TYPE(

1388 "CodeObjectCompatibility",

1389 dbgs() << "Compatible: Target IDs are compatible \t[CodeObject: "

1390 << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()

1391 << "]\n");

1392 return true;

1393}

1394

1395

1397 std::error_code EC;

1398

1399

1401 llvm::raw_svector_ostream BufferStream(Buffer);

1402

1403

1407 ErrorOr<std::unique_ptr> CodeOrErr =

1408 MemoryBuffer::getFileOrSTDIN(I, true);

1409 if (std::error_code EC = CodeOrErr.getError())

1410 return createFileError(I, EC);

1411 InputBuffers.emplace_back(std::move(*CodeOrErr));

1412 }

1413

1414

1416 "Host input index undefined??");

1421 if (!FileHandlerOrErr)

1422 return FileHandlerOrErr.takeError();

1423

1424 std::unique_ptr &FH = *FileHandlerOrErr;

1425 assert(FH);

1426

1427

1428 if (Error Err = FH->WriteHeader(BufferStream, InputBuffers))

1429 return Err;

1430

1431

1432

1433 auto Input = InputBuffers.begin();

1435 if (Error Err = FH->WriteBundleStart(BufferStream, Triple))

1436 return Err;

1437 if (Error Err = FH->WriteBundle(BufferStream, **Input))

1438 return Err;

1439 if (Error Err = FH->WriteBundleEnd(BufferStream, Triple))

1440 return Err;

1441 ++Input;

1442 }

1443

1445 sys::fs::OF_None);

1446 if (EC)

1448

1451 std::unique_ptrllvm::MemoryBuffer BufferMemory =

1452 llvm::MemoryBuffer::getMemBufferCopy(

1453 llvm::StringRef(Buffer.data(), Buffer.size()));

1456 true},

1459 if (auto Error = CompressionResult.takeError())

1460 return Error;

1461

1462 auto CompressedMemBuffer = std::move(CompressionResult.get());

1463 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),

1464 CompressedMemBuffer->getBufferEnd());

1465 } else

1466 CompressedBuffer = Buffer;

1467

1468 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());

1469

1470 return FH->finalizeOutputFile();

1471}

1472

1473

1475

1476 ErrorOr<std::unique_ptr> CodeOrErr =

1478 true);

1479 if (std::error_code EC = CodeOrErr.getError())

1481

1482

1485 if (!DecompressedBufferOrErr)

1486 return createStringError(

1487 inconvertibleErrorCode(),

1488 "Failed to decompress input: " +

1489 llvm::toString(DecompressedBufferOrErr.takeError()));

1490

1491 MemoryBuffer &Input = **DecompressedBufferOrErr;

1492

1493

1496 if (!FileHandlerOrErr)

1497 return FileHandlerOrErr.takeError();

1498

1499 std::unique_ptr &FH = *FileHandlerOrErr;

1500 assert(FH);

1501

1502

1503 if (Error Err = FH->ReadHeader(Input))

1504 return Err;

1505

1506

1507 StringMap Worklist;

1510 Worklist[Triple] = *Output;

1511 ++Output;

1512 }

1513

1514

1515

1516 bool FoundHostBundle = false;

1517 while (!Worklist.empty()) {

1519 FH->ReadBundleStart(Input);

1520 if (!CurTripleOrErr)

1521 return CurTripleOrErr.takeError();

1522

1523

1524 if (!*CurTripleOrErr)

1525 break;

1526

1527 StringRef CurTriple = **CurTripleOrErr;

1528 assert(!CurTriple.empty());

1529

1530 auto Output = Worklist.begin();

1531 for (auto E = Worklist.end(); Output != E; Output++) {

1535 break;

1536 }

1537 }

1538

1539 if (Output == Worklist.end())

1540 continue;

1541

1542 std::error_code EC;

1543 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);

1544 if (EC)

1545 return createFileError((*Output).second, EC);

1546 if (Error Err = FH->ReadBundle(OutputFile, Input))

1547 return Err;

1548 if (Error Err = FH->ReadBundleEnd(Input))

1549 return Err;

1550 Worklist.erase(Output);

1551

1552

1554 if (OffloadInfo.hasHostKind())

1555 FoundHostBundle = true;

1556 }

1557

1559 std::string ErrMsg = "Can't find bundles for";

1560 std::set Sorted;

1561 for (auto &E : Worklist)

1562 Sorted.insert(E.first());

1563 unsigned I = 0;

1564 unsigned Last = Sorted.size() - 1;

1565 for (auto &E : Sorted) {

1566 if (I != 0 && Last > 1)

1567 ErrMsg += ",";

1568 ErrMsg += " ";

1569 if (I == Last && I != 0)

1570 ErrMsg += "and ";

1571 ErrMsg += E.str();

1572 ++I;

1573 }

1574 return createStringError(inconvertibleErrorCode(), ErrMsg);

1575 }

1576

1577

1578

1580 for (auto &E : Worklist) {

1581 std::error_code EC;

1582 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);

1583 if (EC)

1584 return createFileError(E.second, EC);

1585

1586

1588 if (OffloadInfo.hasHostKind())

1589 OutputFile.write(Input.getBufferStart(), Input.getBufferSize());

1590 }

1591 return Error::success();

1592 }

1593

1594

1595

1598 return createStringError(inconvertibleErrorCode(),

1599 "Can't find bundle for the host target");

1600

1601

1602 for (auto &E : Worklist) {

1603 std::error_code EC;

1604 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);

1605 if (EC)

1606 return createFileError(E.second, EC);

1607 }

1608

1609 return Error::success();

1610}

1611

1613 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN

1614 : Archive::K_GNU;

1615}

1616

1617

1618

1619

1620

1621

1622

1623static bool

1627 if (!CompatibleTargets.empty()) {

1628 DEBUG_WITH_TYPE("CodeObjectCompatibility",

1629 dbgs() << "CompatibleTargets list should be empty\n");

1630 return false;

1631 }

1635 CompatibleTargets.push_back(Target);

1636 }

1637 return !CompatibleTargets.empty();

1638}

1639

1640

1641

1642

1643

1647 std::vector<std::unique_ptr> ArchiveBuffers;

1648 ErrorOr<std::unique_ptr> BufOrErr =

1649 MemoryBuffer::getFileOrSTDIN(ArchiveName, true, false);

1650 if (std::error_code EC = BufOrErr.getError())

1651 return createFileError(ArchiveName, EC);

1652

1653 ArchiveBuffers.push_back(std::move(*BufOrErr));

1655 Archive::create(ArchiveBuffers.back()->getMemBufferRef());

1656 if (!LibOrErr)

1657 return LibOrErr.takeError();

1658

1659 auto Archive = std::move(*LibOrErr);

1660

1661 Error ArchiveErr = Error::success();

1662 auto ChildEnd = Archive->child_end();

1663

1664

1665 for (auto ArchiveIter = Archive->child_begin(ArchiveErr);

1666 ArchiveIter != ChildEnd; ++ArchiveIter) {

1667 if (ArchiveErr)

1668 return ArchiveErr;

1669 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();

1670 if (!ArchiveChildNameOrErr)

1671 return ArchiveChildNameOrErr.takeError();

1672

1673 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();

1674 if (!CodeObjectBufferRefOrErr)

1675 return CodeObjectBufferRefOrErr.takeError();

1676

1677 auto CodeObjectBuffer =

1678 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);

1679

1682 if (!FileHandlerOrErr)

1683 return FileHandlerOrErr.takeError();

1684

1685 std::unique_ptr &FileHandler = *FileHandlerOrErr;

1686 assert(FileHandler);

1687

1688 std::set BundleIds;

1689 auto CodeObjectFileError =

1690 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);

1691 if (CodeObjectFileError)

1692 return CodeObjectFileError;

1693

1695 if (ConflictingArchs) {

1696 std::string ErrMsg =

1697 Twine("conflicting TargetIDs [" + ConflictingArchs.value().first +

1698 ", " + ConflictingArchs.value().second + "] found in " +

1699 ArchiveChildNameOrErr.get() + " of " + ArchiveName)

1700 .str();

1701 return createStringError(inconvertibleErrorCode(), ErrMsg);

1702 }

1703 }

1704

1705 return ArchiveErr;

1706}

1707

1708

1709

1710

1711

1712

1713

1714

1716 std::vector<std::unique_ptr> ArchiveBuffers;

1717

1718

1719

1720 StringMap<std::vector> OutputArchivesMap;

1721

1722

1723 StringMap TargetOutputFileNameMap;

1724

1727 TargetOutputFileNameMap[Target] = *Output;

1728 ++Output;

1729 }

1730

1732

1734

1735

1736

1738 if (ArchiveError) {

1739 return ArchiveError;

1740 }

1741 }

1742

1743 ErrorOr<std::unique_ptr> BufOrErr =

1744 MemoryBuffer::getFileOrSTDIN(IFName, true, false);

1745 if (std::error_code EC = BufOrErr.getError())

1747

1748 ArchiveBuffers.push_back(std::move(*BufOrErr));

1750 Archive::create(ArchiveBuffers.back()->getMemBufferRef());

1751 if (!LibOrErr)

1752 return LibOrErr.takeError();

1753

1754 auto Archive = std::move(*LibOrErr);

1755

1756 Error ArchiveErr = Error::success();

1757 auto ChildEnd = Archive->child_end();

1758

1759

1760 for (auto ArchiveIter = Archive->child_begin(ArchiveErr);

1761 ArchiveIter != ChildEnd; ++ArchiveIter) {

1762 if (ArchiveErr)

1763 return ArchiveErr;

1764 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();

1765 if (!ArchiveChildNameOrErr)

1766 return ArchiveChildNameOrErr.takeError();

1767

1768 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);

1769

1770 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();

1771 if (!CodeObjectBufferRefOrErr)

1772 return CodeObjectBufferRefOrErr.takeError();

1773

1774 auto TempCodeObjectBuffer =

1775 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);

1776

1777

1781 if (!DecompressedBufferOrErr)

1782 return createStringError(

1783 inconvertibleErrorCode(),

1784 "Failed to decompress code object: " +

1785 llvm::toString(DecompressedBufferOrErr.takeError()));

1786

1787 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;

1788

1791 if (!FileHandlerOrErr)

1792 return FileHandlerOrErr.takeError();

1793

1794 std::unique_ptr &FileHandler = *FileHandlerOrErr;

1795 assert(FileHandler &&

1796 "FileHandle creation failed for file in the archive!");

1797

1798 if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer))

1799 return ReadErr;

1800

1802 FileHandler->ReadBundleStart(CodeObjectBuffer);

1803 if (!CurBundleIDOrErr)

1804 return CurBundleIDOrErr.takeError();

1805

1806 std::optional OptionalCurBundleID = *CurBundleIDOrErr;

1807

1808 if (!OptionalCurBundleID)

1809 continue;

1810 StringRef CodeObject = *OptionalCurBundleID;

1811

1812

1813

1814 while (!CodeObject.empty()) {

1819 std::string BundleData;

1820 raw_string_ostream DataStream(BundleData);

1821 if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))

1822 return Err;

1823

1824 for (auto &CompatibleTarget : CompatibleTargets) {

1826 BundledObjectFileName.assign(BundledObjectFile);

1827 auto OutputBundleName =

1828 Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +

1829 CodeObject +

1831 CodeObjectInfo.TargetID))

1832 .str();

1833

1834

1835 std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',

1836 '_');

1837

1838 std::unique_ptr MemBuf = MemoryBuffer::getMemBufferCopy(

1839 DataStream.str(), OutputBundleName);

1840 ArchiveBuffers.push_back(std::move(MemBuf));

1841 llvm::MemoryBufferRef MemBufRef =

1842 MemoryBufferRef(*(ArchiveBuffers.back()));

1843

1844

1845

1846 OutputArchivesMap[CompatibleTarget].push_back(

1847 NewArchiveMember(MemBufRef));

1848 }

1849 }

1850

1851 if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))

1852 return Err;

1853

1855 FileHandler->ReadBundleStart(CodeObjectBuffer);

1856 if (!NextTripleOrErr)

1857 return NextTripleOrErr.takeError();

1858

1859 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr : "";

1860 }

1861 }

1862

1863 assert(!ArchiveErr && "Error occurred while reading archive!");

1864

1865

1867 StringRef FileName = TargetOutputFileNameMap[Target];

1868 StringMapIterator<std::vectorllvm::NewArchiveMember> CurArchiveMembers =

1869 OutputArchivesMap.find(Target);

1870 if (CurArchiveMembers != OutputArchivesMap.end()) {

1871 if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),

1872 SymtabWritingMode::NormalSymtab,

1874 false, nullptr))

1875 return WriteErr;

1877 std::string ErrMsg =

1878 Twine("no compatible code object found for the target '" + Target +

1879 "' in heterogeneous archive library: " + IFName)

1880 .str();

1881 return createStringError(inconvertibleErrorCode(), ErrMsg);

1882 } else {

1883

1884

1885

1886 std::vectorllvm::NewArchiveMember EmptyArchive;

1887 EmptyArchive.clear();

1888 if (Error WriteErr = writeArchive(

1889 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,

1891 return WriteErr;

1892 }

1893 }

1894

1895 return Error::success();

1896}

llvm::MachO::Target Target

static std::string getDeviceLibraryFileName(StringRef BundleFileName, StringRef Device)

static llvm::ManagedStatic< llvm::TimerGroup, CreateClangOffloadBundlerTimerGroup > ClangOffloadBundlerTimerGroup

static StringRef getDeviceFileExtension(StringRef Device, StringRef BundleFileName)

static Expected< std::unique_ptr< FileHandler > > CreateFileHandler(MemoryBuffer &FirstInput, const OffloadBundlerConfig &BundlerConfig)

Return an appropriate handler given the input files and options.

#define OFFLOAD_BUNDLER_MAGIC_STR

Magic string that marks the existence of offloading data.

bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo, const OffloadTargetInfo &TargetInfo)

Checks if a code object CodeObjectInfo is compatible with a given target TargetInfo.

static Error CheckHeterogeneousArchive(StringRef ArchiveName, const OffloadBundlerConfig &BundlerConfig)

static std::unique_ptr< FileHandler > CreateObjectFileHandler(MemoryBuffer &FirstInput, const OffloadBundlerConfig &BundlerConfig)

Return an appropriate object file handler.

static Archive::Kind getDefaultArchiveKindForHost()

static std::string formatWithCommas(unsigned long long Value)

static bool getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo, SmallVectorImpl< StringRef > &CompatibleTargets, const OffloadBundlerConfig &BundlerConfig)

Computes a list of targets among all given targets which are compatible with this code object.

This file defines an offload bundling API that bundles different files that relate with the same sour...

__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)

static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > decompress(const llvm::MemoryBuffer &Input, bool Verbose=false)

static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input, uint16_t Version, bool Verbose=false)

llvm::compression::Format CompressionFormat

std::vector< std::string > OutputFileNames

std::vector< std::string > TargetNames

uint16_t CompressedBundleVersion

std::vector< std::string > InputFileNames

bool PrintExternalCommands

llvm::Error BundleFiles()

Bundle the files. Return true if an error was found.

llvm::Error UnbundleFiles()

llvm::Error UnbundleArchive()

UnbundleArchive takes an archive file (".a") as input containing bundled code object files,...

static llvm::Error ListBundleIDsInFile(llvm::StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig)

const OffloadBundlerConfig & BundlerConfig

Exposes information about the current target.

bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)

The JSON file list parser is used to communicate input to InstallAPI.

std::optional< llvm::StringRef > parseTargetID(const llvm::Triple &T, llvm::StringRef OffloadArch, llvm::StringMap< bool > *FeatureMap)

Parse a target ID to get processor and feature map.

@ Create

'create' clause, allowed on Compute and Combined constructs, plus 'data', 'enter data',...

std::optional< std::pair< llvm::StringRef, llvm::StringRef > > getConflictTargetIDCombination(const std::set< llvm::StringRef > &TargetIDs)

Get the conflicted pair of target IDs for a compilation or a bundled code object, assuming TargetIDs ...

@ Result

The result type of a method or function.

OffloadArch StringToOffloadArch(llvm::StringRef S)

const FunctionProtoType * T

Diagnostic wrappers for TextAPI types for error reporting.

Obtain the offload kind, real machine triple, and an optional TargetID out of the target information ...

bool operator==(const OffloadTargetInfo &Target) const

bool isOffloadKindCompatible(const llvm::StringRef TargetOffloadKind) const

bool isTripleValid() const

OffloadTargetInfo(const llvm::StringRef Target, const OffloadBundlerConfig &BC)

llvm::StringRef OffloadKind

bool isOffloadKindValid() const

const OffloadBundlerConfig & BundlerConfig