Skip to content

Commit 61b13e0

Browse files
authored
[ClangOffloadBundler] fix unbundling archive (#84195)
When unbundling an archive, need to save the content of each object file to a temporary file before passing it to llvm-objcopy, instead of passing the original input archive file to llvm-objcopy. Also allows extracting host bundles for archives. Fixes: #83509
1 parent 4cfd4a7 commit 61b13e0

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

clang/lib/Driver/OffloadBundler.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,8 @@ class ObjectFileHandler final : public FileHandler {
590590
// Copy fat object contents to the output when extracting host bundle.
591591
std::string ModifiedContent;
592592
if (Content.size() == 1u && Content.front() == 0) {
593-
auto HostBundleOrErr = getHostBundle();
593+
auto HostBundleOrErr = getHostBundle(
594+
StringRef(Input.getBufferStart(), Input.getBufferSize()));
594595
if (!HostBundleOrErr)
595596
return HostBundleOrErr.takeError();
596597

@@ -700,7 +701,7 @@ class ObjectFileHandler final : public FileHandler {
700701
return Error::success();
701702
}
702703

703-
Expected<std::string> getHostBundle() {
704+
Expected<std::string> getHostBundle(StringRef Input) {
704705
TempFileHandlerRAII TempFiles;
705706

706707
auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
@@ -715,7 +716,24 @@ class ObjectFileHandler final : public FileHandler {
715716
ObjcopyArgs.push_back("--regex");
716717
ObjcopyArgs.push_back("--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
717718
ObjcopyArgs.push_back("--");
718-
ObjcopyArgs.push_back(BundlerConfig.InputFileNames.front());
719+
720+
StringRef ObjcopyInputFileName;
721+
// When unbundling an archive, the content of each object file in the
722+
// archive is passed to this function by parameter Input, which is different
723+
// from the content of the original input archive file, therefore it needs
724+
// to be saved to a temporary file before passed to llvm-objcopy. Otherwise,
725+
// Input is the same as the content of the original input file, therefore
726+
// temporary file is not needed.
727+
if (StringRef(BundlerConfig.FilesType).starts_with("a")) {
728+
auto InputFileOrErr =
729+
TempFiles.Create(ArrayRef<char>(Input.data(), Input.size()));
730+
if (!InputFileOrErr)
731+
return InputFileOrErr.takeError();
732+
ObjcopyInputFileName = *InputFileOrErr;
733+
} else
734+
ObjcopyInputFileName = BundlerConfig.InputFileNames.front();
735+
736+
ObjcopyArgs.push_back(ObjcopyInputFileName);
719737
ObjcopyArgs.push_back(ModifiedObjPath);
720738

721739
if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))
@@ -1628,10 +1646,8 @@ Error OffloadBundler::UnbundleArchive() {
16281646
while (!CodeObject.empty()) {
16291647
SmallVector<StringRef> CompatibleTargets;
16301648
auto CodeObjectInfo = OffloadTargetInfo(CodeObject, BundlerConfig);
1631-
if (CodeObjectInfo.hasHostKind()) {
1632-
// Do nothing, we don't extract host code yet.
1633-
} else if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
1634-
BundlerConfig)) {
1649+
if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
1650+
BundlerConfig)) {
16351651
std::string BundleData;
16361652
raw_string_ostream DataStream(BundleData);
16371653
if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))

clang/test/Driver/clang-offload-bundler.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@
1313
// RUN: obj2yaml %t.o > %t.o.yaml
1414
// RUN: %clang -O0 -target %itanium_abi_triple %s -emit-ast -o %t.ast
1515

16+
// RUN: echo 'void a() {}' >%t.a.cpp
17+
// RUN: echo 'void b() {}' >%t.b.cpp
18+
// RUN: %clang -target %itanium_abi_triple %t.a.cpp -c -o %t.a.o
19+
// RUN: %clang -target %itanium_abi_triple %t.b.cpp -c -o %t.b.o
20+
//
21+
// Remove .llvm_addrsig section since its offset changes after llvm-objcopy
22+
// removes clang-offload-bundler sections, therefore not good for comparison.
23+
//
24+
// RUN: llvm-objcopy --remove-section=.llvm_addrsig %t.a.o
25+
// RUN: llvm-objcopy --remove-section=.llvm_addrsig %t.b.o
26+
// RUN: obj2yaml %t.a.o > %t.a.yaml
27+
// RUN: obj2yaml %t.b.o > %t.b.yaml
28+
1629
//
1730
// Generate an empty file to help with the checks of empty files.
1831
//
@@ -414,6 +427,25 @@
414427
// HIP-AR-906-DAG: hip_bundle1-hip-amdgcn-amd-amdhsa--gfx906
415428
// HIP-AR-906-DAG: hip_bundle2-hip-amdgcn-amd-amdhsa--gfx906
416429

430+
//
431+
// Check unbundling archive for host target
432+
//
433+
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,hip-amdgcn-amd-amdhsa--gfx900 \
434+
// RUN: -input=%t.a.o -input=%t.tgt1 -output=%t.a.bundled.o
435+
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,hip-amdgcn-amd-amdhsa--gfx900 \
436+
// RUN: -input=%t.b.o -input=%t.tgt1 -output=%t.b.bundled.o
437+
// RUN: rm -f %t.bundled.a
438+
// RUN: llvm-ar cr %t.bundled.a %t.a.bundled.o %t.b.bundled.o
439+
// RUN: cp %t.bundled.a %t.bundled.a.bak
440+
// RUN: clang-offload-bundler -unbundle --targets=host-%itanium_abi_triple -type=a -input=%t.bundled.a -output=%t.host.a
441+
// RUN: rm -f *%itanium_abi_triple*.a.bundled.o *%itanium_abi_triple*.b.bundled.o
442+
// RUN: llvm-ar -x %t.host.a
443+
// RUN: diff %t.bundled.a %t.bundled.a.bak
444+
// RUN: obj2yaml *%itanium_abi_triple*.a.bundled.o > %t.a.unbundled.yaml
445+
// RUN: diff %t.a.unbundled.yaml %t.a.yaml
446+
// RUN: obj2yaml *%itanium_abi_triple*.b.bundled.o > %t.b.unbundled.yaml
447+
// RUN: diff %t.b.unbundled.yaml %t.b.yaml
448+
//
417449
// Check clang-offload-bundler reporting an error when trying to unbundle an archive but
418450
// the input file is not an archive.
419451
//

0 commit comments

Comments
 (0)