Skip to content

Commit 5c84054

Browse files
authored
[LinkerWrapper] Support relocatable linking for offloading (#80066)
Summary: The standard GPU compilation process embeds each intermediate object file into the host file at the `.llvm.offloading` section so it can be linked later. We also use a special section called something like `omp_offloading_entries` to store all the globals that need to be registered by the runtime. The linker-wrapper's job is to link the embedded device code stored at this section and then emit code to register the linked image and the kernels and globals in the offloading entry section. One downside to RDC linking is that it can become quite big for very large projects that wish to make use of static linking. This patch changes the support for relocatable linking via `-r` to support a kind of "partial" RDC compilation for offloading languages. This primarily requires manually editing the embedded data in the output object file for the relocatable link. We need to rename the output section to make it distinct from the input sections that will be merged. We then delete the old embedded object code so it won't be linked further. We then need to rename the old offloading section so that it is private to the module. A runtime solution could also be done to defer entries that don't belong to the given GPU executable, but this is easier. Note that this does not work with COFF linking, only the ELF method for handling offloading entries, that could be made to work similarly. Given this support, the following compilation path should produce two distinct images for OpenMP offloading. ``` $ clang foo.c -fopenmp --offload-arch=native -c $ clang foo.c -lomptarget.devicertl --offload-link -r -o merged.o $ clang main.c merged.o -fopenmp --offload-arch=native $ ./a.out ``` Or similarly for HIP to effectively perform non-RDC mode compilation for a subset of files. ``` $ clang -x hip foo.c --offload-arch=native --offload-new-driver -fgpu-rdc -c $ clang -x hip foo.c -lomptarget.devicertl --offload-link -r -o merged.o $ clang -x hip main.c merged.o --offload-arch=native --offload-new-driver -fgpu-rdc $ ./a.out ``` One question is whether or not this should be the default behavior of `-r` when run through the linker-wrapper or a special option. Standard `-r` behavior is still possible if used without invoking the linker-wrapper and it guaranteed to be correct.
1 parent 52bf531 commit 5c84054

File tree

9 files changed

+174
-18
lines changed

9 files changed

+174
-18
lines changed

clang/docs/ClangLinkerWrapper.rst

+18
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,30 @@ only for the linker wrapper will be forwarded to the wrapped linker job.
5454
--pass-remarks=<value> Pass remarks for LTO
5555
--print-wrapped-module Print the wrapped module's IR for testing
5656
--ptxas-arg=<value> Argument to pass to the 'ptxas' invocation
57+
--relocatable Link device code to create a relocatable offloading application
5758
--save-temps Save intermediate results
5859
--sysroot<value> Set the system root
5960
--verbose Verbose output from tools
6061
--v Display the version number and exit
6162
-- The separator for the wrapped linker arguments
6263
64+
Relocatable Linking
65+
===================
66+
67+
The ``clang-linker-wrapper`` handles linking embedded device code and then
68+
registering it with the appropriate runtime. Normally, this is only done when
69+
the executable is created so other files containing device code can be linked
70+
together. This can be somewhat problematic for users who wish to ship static
71+
libraries that contain offloading code to users without a compatible offloading
72+
toolchain.
73+
74+
When using a relocatable link with ``-r``, the ``clang-linker-wrapper`` will
75+
perform the device linking and registration eagerly. This will remove the
76+
embedded device code and register it correctly with the runtime. Semantically,
77+
this is similar to creating a shared library object. If standard relocatable
78+
linking is desired, simply do not run the binaries through the
79+
``clang-linker-wrapper``. This will simply append the embedded device code so
80+
that it can be linked later.
6381

6482
Example
6583
=======

clang/docs/OffloadingDesign.rst

+34
Original file line numberDiff line numberDiff line change
@@ -470,3 +470,37 @@ We can see the steps created by clang to generate the offloading code using the
470470
# "nvptx64-nvidia-cuda" - "NVPTX::Assembler", inputs: ["/tmp/zaxpy-07f434.s"], output: "/tmp/zaxpy-0af7b7.o"
471471
# "x86_64-unknown-linux-gnu" - "clang", inputs: ["/tmp/zaxpy-e6a41b.bc", "/tmp/zaxpy-0af7b7.o"], output: "/tmp/zaxpy-416cad.o"
472472
# "x86_64-unknown-linux-gnu" - "Offload::Linker", inputs: ["/tmp/zaxpy-416cad.o"], output: "a.out"
473+
474+
Relocatable Linking
475+
-------------------
476+
477+
The offloading compilation pipeline normally will defer the final device linking
478+
and runtime registration until the ``clang-linker-wrapper`` is run to create the
479+
executable. This is the standard behaviour when compiling for OpenMP offloading
480+
or CUDA and HIP in ``-fgpu-rdc`` mode. However, there are some cases where the
481+
user may wish to perform this device handling prematurely. This is described in
482+
the :doc:`linker wrapper documentation<ClangLinkerWrapper>`.
483+
484+
Effectively, this allows the user to handle offloading specific linking ahead of
485+
time when shipping objects or static libraries. This can be thought of as
486+
performing a standard ``-fno-gpu-rdc`` compilation on a subset of object files.
487+
This can be useful to reduce link time, prevent users from interacting with the
488+
library's device code, or for shipping libraries to incompatible compilers.
489+
490+
Normally, if a relocatable link is done using ``clang -r`` it will simply merge
491+
the ``.llvm.offloading`` sections which will then be linked later when the
492+
executable is created. However, if the ``-r`` flag is used with the offloading
493+
toolchain, it will perform the device linking and registration phases and then
494+
merge the registration code into the final relocatable object file.
495+
496+
The following example shows how using the relocatable link with the offloading
497+
pipeline can create a static library with offloading code that can be
498+
redistributed without requiring any additional handling.
499+
500+
.. code-block:: console
501+
502+
$ clang++ -fopenmp -fopenmp-targets=nvptx64 foo.cpp -c
503+
$ clang++ -lomptarget.devicertl --offload-link -r foo.o -o merged.o
504+
$ llvm-ar rcs libfoo.a merged.o
505+
# g++ app.cpp -L. -lfoo
506+

clang/test/Driver/linker-wrapper-image.c

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
// RUN: -fembed-offload-object=%t.out
1010
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu \
1111
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=OPENMP,OPENMP-ELF
12+
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run -r --host-triple=x86_64-unknown-linux-gnu \
13+
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=OPENMP-ELF,OPENMP-REL
1214
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-windows-gnu \
1315
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=OPENMP,OPENMP-COFF
1416

@@ -19,6 +21,8 @@
1921
// OPENMP-COFF: @__start_omp_offloading_entries = weak_odr hidden constant [0 x %struct.__tgt_offload_entry] zeroinitializer, section "omp_offloading_entries$OA"
2022
// OPENMP-COFF-NEXT: @__stop_omp_offloading_entries = weak_odr hidden constant [0 x %struct.__tgt_offload_entry] zeroinitializer, section "omp_offloading_entries$OZ"
2123

24+
// OPENMP-REL: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading.relocatable", align 8
25+
2226
// OPENMP: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading", align 8
2327
// OPENMP-NEXT: @.omp_offloading.device_images = internal unnamed_addr constant [1 x %__tgt_device_image] [%__tgt_device_image { ptr getelementptr inbounds ([[[BEGIN:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr getelementptr inbounds ([[[END:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries }]
2428
// OPENMP-NEXT: @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries }
@@ -42,6 +46,8 @@
4246
// RUN: -fembed-offload-object=%t.out
4347
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu \
4448
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=CUDA,CUDA-ELF
49+
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run -r --host-triple=x86_64-unknown-linux-gnu \
50+
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=CUDA,CUDA-ELF
4551
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-windows-gnu \
4652
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=CUDA,CUDA-COFF
4753

@@ -140,6 +146,8 @@
140146
// RUN: -fembed-offload-object=%t.out
141147
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu \
142148
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=HIP,HIP-ELF
149+
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu -r \
150+
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=HIP,HIP-ELF
143151
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-windows-gnu \
144152
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=HIP,HIP-COFF
145153

clang/test/Driver/linker-wrapper.c

+29-3
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,36 @@ __attribute__((visibility("protected"), used)) int x;
176176
// RUN: --image=file=%t.elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu \
177177
// RUN: --image=file=%t.elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu
178178
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
179-
// RUN: llvm-ar rcs %t.a %t.o
180179
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
181-
// RUN: --linker-path=/usr/bin/ld.lld -- -r --whole-archive %t.a --no-whole-archive \
180+
// RUN: --linker-path=/usr/bin/ld.lld -- -r %t.o \
182181
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=RELOCATABLE-LINK
183182

184-
// RELOCATABLE-LINK-NOT: clang{{.*}} -o {{.*}}.img --target=x86_64-unknown-linux-gnu
183+
// RELOCATABLE-LINK: clang{{.*}} -o {{.*}}.img --target=x86_64-unknown-linux-gnu
185184
// RELOCATABLE-LINK: /usr/bin/ld.lld{{.*}}-r
185+
// RELOCATABLE-LINK: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading
186+
187+
// RUN: clang-offload-packager -o %t.out \
188+
// RUN: --image=file=%t.elf.o,kind=hip,triple=amdgcn-amd-amdhsa,arch=gfx90a \
189+
// RUN: --image=file=%t.elf.o,kind=hip,triple=amdgcn-amd-amdhsa,arch=gfx90a
190+
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
191+
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
192+
// RUN: --linker-path=/usr/bin/ld.lld -- -r %t.o \
193+
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=RELOCATABLE-LINK-HIP
194+
195+
// RELOCATABLE-LINK-HIP: clang{{.*}} -o {{.*}}.img --target=amdgcn-amd-amdhsa
196+
// RELOCATABLE-LINK-HIP: clang-offload-bundler{{.*}} -type=o -bundle-align=4096 -targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx90a -input=/dev/null -input={{.*}} -output={{.*}}
197+
// RELOCATABLE-LINK-HIP: /usr/bin/ld.lld{{.*}}-r
198+
// RELOCATABLE-LINK-HIP: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading
199+
200+
// RUN: clang-offload-packager -o %t.out \
201+
// RUN: --image=file=%t.elf.o,kind=cuda,triple=nvptx64-nvidia-cuda,arch=sm_89 \
202+
// RUN: --image=file=%t.elf.o,kind=cuda,triple=nvptx64-nvidia-cuda,arch=sm_89
203+
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
204+
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
205+
// RUN: --linker-path=/usr/bin/ld.lld -- -r %t.o \
206+
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=RELOCATABLE-LINK-CUDA
207+
208+
// RELOCATABLE-LINK-CUDA: clang{{.*}} -o {{.*}}.img --target=nvptx64-nvidia-cuda
209+
// RELOCATABLE-LINK-CUDA: fatbinary{{.*}} -64 --create {{.*}}.fatbin --image=profile=sm_89,file={{.*}}.img
210+
// RELOCATABLE-LINK-CUDA: /usr/bin/ld.lld{{.*}}-r
211+
// RELOCATABLE-LINK-CUDA: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

+70-7
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,70 @@ Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) {
241241
return *Path;
242242
}
243243

244+
/// Returns the hashed value for a constant string.
245+
std::string getHash(StringRef Str) {
246+
llvm::MD5 Hasher;
247+
llvm::MD5::MD5Result Hash;
248+
Hasher.update(Str);
249+
Hasher.final(Hash);
250+
return llvm::utohexstr(Hash.low(), /*LowerCase=*/true);
251+
}
252+
253+
/// Renames offloading entry sections in a relocatable link so they do not
254+
/// conflict with a later link job.
255+
Error relocateOffloadSection(const ArgList &Args, StringRef Output) {
256+
llvm::Triple Triple(
257+
Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
258+
if (Triple.isOSWindows())
259+
return createStringError(
260+
inconvertibleErrorCode(),
261+
"Relocatable linking is not supported on COFF targets");
262+
263+
Expected<std::string> ObjcopyPath =
264+
findProgram("llvm-objcopy", {getMainExecutable("llvm-objcopy")});
265+
if (!ObjcopyPath)
266+
return ObjcopyPath.takeError();
267+
268+
// Use the linker output file to get a unique hash. This creates a unique
269+
// identifier to rename the sections to that is deterministic to the contents.
270+
auto BufferOrErr = DryRun ? MemoryBuffer::getMemBuffer("")
271+
: MemoryBuffer::getFileOrSTDIN(Output);
272+
if (!BufferOrErr)
273+
return createStringError(inconvertibleErrorCode(), "Failed to open %s",
274+
Output.str().c_str());
275+
std::string Suffix = "_" + getHash((*BufferOrErr)->getBuffer());
276+
277+
SmallVector<StringRef> ObjcopyArgs = {
278+
*ObjcopyPath,
279+
Output,
280+
};
281+
282+
// Remove the old .llvm.offloading section to prevent further linking.
283+
ObjcopyArgs.emplace_back("--remove-section");
284+
ObjcopyArgs.emplace_back(".llvm.offloading");
285+
for (StringRef Prefix : {"omp", "cuda", "hip"}) {
286+
auto Section = (Prefix + "_offloading_entries").str();
287+
// Rename the offloading entires to make them private to this link unit.
288+
ObjcopyArgs.emplace_back("--rename-section");
289+
ObjcopyArgs.emplace_back(
290+
Args.MakeArgString(Section + "=" + Section + Suffix));
291+
292+
// Rename the __start_ / __stop_ symbols appropriately to iterate over the
293+
// newly renamed section containing the offloading entries.
294+
ObjcopyArgs.emplace_back("--redefine-sym");
295+
ObjcopyArgs.emplace_back(Args.MakeArgString("__start_" + Section + "=" +
296+
"__start_" + Section + Suffix));
297+
ObjcopyArgs.emplace_back("--redefine-sym");
298+
ObjcopyArgs.emplace_back(Args.MakeArgString("__stop_" + Section + "=" +
299+
"__stop_" + Section + Suffix));
300+
}
301+
302+
if (Error Err = executeCommands(*ObjcopyPath, ObjcopyArgs))
303+
return Err;
304+
305+
return Error::success();
306+
}
307+
244308
/// Runs the wrapped linker job with the newly created input.
245309
Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
246310
llvm::TimeTraceScope TimeScope("Execute host linker");
@@ -265,6 +329,10 @@ Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
265329
LinkerArgs.push_back(Arg);
266330
if (Error Err = executeCommands(LinkerPath, LinkerArgs))
267331
return Err;
332+
333+
if (Args.hasArg(OPT_relocatable))
334+
return relocateOffloadSection(Args, ExecutableName);
335+
268336
return Error::success();
269337
}
270338

@@ -910,7 +978,8 @@ wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
910978
case OFK_OpenMP:
911979
if (Error Err = offloading::wrapOpenMPBinaries(
912980
M, BuffersToWrap,
913-
offloading::getOffloadEntryArray(M, "omp_offloading_entries")))
981+
offloading::getOffloadEntryArray(M, "omp_offloading_entries"),
982+
/*Suffix=*/"", /*Relocatable=*/Args.hasArg(OPT_relocatable)))
914983
return std::move(Err);
915984
break;
916985
case OFK_Cuda:
@@ -1356,12 +1425,6 @@ Expected<SmallVector<SmallVector<OffloadFile>>>
13561425
getDeviceInput(const ArgList &Args) {
13571426
llvm::TimeTraceScope TimeScope("ExtractDeviceCode");
13581427

1359-
// If the user is requesting a reloctable link we ignore the device code. The
1360-
// actual linker will merge the embedded device code sections so they can be
1361-
// linked when the executable is finally created.
1362-
if (Args.hasArg(OPT_relocatable))
1363-
return SmallVector<SmallVector<OffloadFile>>{};
1364-
13651428
StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ);
13661429
SmallVector<StringRef> LibraryPaths;
13671430
for (const opt::Arg *Arg : Args.filtered(OPT_library_path, OPT_libpath))

clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td

+3-2
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ def version : Flag<["--", "-"], "version">, Flags<[HelpHidden]>, Alias<v>;
127127
def whole_archive : Flag<["--", "-"], "whole-archive">, Flags<[HelpHidden]>;
128128
def no_whole_archive : Flag<["--", "-"], "no-whole-archive">, Flags<[HelpHidden]>;
129129

130-
def relocatable : Flag<["--", "-"], "relocatable">, Flags<[HelpHidden]>;
131-
def r : Flag<["-"], "r">, Alias<relocatable>, Flags<[HelpHidden]>;
130+
def relocatable : Flag<["--", "-"], "relocatable">,
131+
HelpText<"Link device code to create a relocatable offloading application">;
132+
def r : Flag<["-"], "r">, Alias<relocatable>;
132133

133134
// link.exe-style linker options.
134135
def out : Joined<["/", "-", "/?", "-?"], "out:">, Flags<[HelpHidden]>;

llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ using EntryArrayTy = std::pair<GlobalVariable *, GlobalVariable *>;
2020
/// \param EntryArray Optional pair pointing to the `__start` and `__stop`
2121
/// symbols holding the `__tgt_offload_entry` array.
2222
/// \param Suffix An optional suffix appended to the emitted symbols.
23+
/// \param Relocatable Indicate if we need to change the offloading section to
24+
/// create a relocatable object.
2325
llvm::Error wrapOpenMPBinaries(llvm::Module &M,
2426
llvm::ArrayRef<llvm::ArrayRef<char>> Images,
2527
EntryArrayTy EntryArray,
26-
llvm::StringRef Suffix = "");
28+
llvm::StringRef Suffix = "",
29+
bool Relocatable = false);
2730

2831
/// Wraps the input fatbinary image into the module \p M as global symbols and
2932
/// registers the images with the CUDA runtime.

llvm/lib/Frontend/Offloading/OffloadWrapper.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ PointerType *getBinDescPtrTy(Module &M) {
112112
///
113113
/// Global variable that represents BinDesc is returned.
114114
GlobalVariable *createBinDesc(Module &M, ArrayRef<ArrayRef<char>> Bufs,
115-
EntryArrayTy EntryArray, StringRef Suffix) {
115+
EntryArrayTy EntryArray, StringRef Suffix,
116+
bool Relocatable) {
116117
LLVMContext &C = M.getContext();
117118
auto [EntriesB, EntriesE] = EntryArray;
118119

@@ -129,7 +130,8 @@ GlobalVariable *createBinDesc(Module &M, ArrayRef<ArrayRef<char>> Bufs,
129130
GlobalVariable::InternalLinkage, Data,
130131
".omp_offloading.device_image" + Suffix);
131132
Image->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
132-
Image->setSection(".llvm.offloading");
133+
Image->setSection(Relocatable ? ".llvm.offloading.relocatable"
134+
: ".llvm.offloading");
133135
Image->setAlignment(Align(object::OffloadBinary::getAlignment()));
134136

135137
StringRef Binary(Buf.data(), Buf.size());
@@ -582,8 +584,9 @@ void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc,
582584

583585
Error offloading::wrapOpenMPBinaries(Module &M, ArrayRef<ArrayRef<char>> Images,
584586
EntryArrayTy EntryArray,
585-
llvm::StringRef Suffix) {
586-
GlobalVariable *Desc = createBinDesc(M, Images, EntryArray, Suffix);
587+
llvm::StringRef Suffix, bool Relocatable) {
588+
GlobalVariable *Desc =
589+
createBinDesc(M, Images, EntryArray, Suffix, Relocatable);
587590
if (!Desc)
588591
return createStringError(inconvertibleErrorCode(),
589592
"No binary descriptors created.");

llvm/lib/Object/OffloadBinary.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Error extractFromObject(const ObjectFile &Obj,
8383
if (!NameOrErr)
8484
return NameOrErr.takeError();
8585

86-
if (!NameOrErr->equals(".llvm.offloading"))
86+
if (!NameOrErr->starts_with(".llvm.offloading"))
8787
continue;
8888
}
8989

0 commit comments

Comments
 (0)