-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[LinkerWrapper] Support relocatable linking for offloading #80066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -241,6 +241,70 @@ Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) { | |
return *Path; | ||
} | ||
|
||
/// Returns the hashed value for a constant string. | ||
std::string getHash(StringRef Str) { | ||
llvm::MD5 Hasher; | ||
llvm::MD5::MD5Result Hash; | ||
Hasher.update(Str); | ||
Hasher.final(Hash); | ||
return llvm::utohexstr(Hash.low(), /*LowerCase=*/true); | ||
} | ||
|
||
/// Renames offloading entry sections in a relocatable link so they do not | ||
/// conflict with a later link job. | ||
Error relocateOffloadSection(const ArgList &Args, StringRef Output) { | ||
llvm::Triple Triple( | ||
Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple())); | ||
if (Triple.isOSWindows()) | ||
return createStringError( | ||
inconvertibleErrorCode(), | ||
"Relocatable linking is not supported on COFF targets"); | ||
|
||
Expected<std::string> ObjcopyPath = | ||
findProgram("llvm-objcopy", {getMainExecutable("llvm-objcopy")}); | ||
if (!ObjcopyPath) | ||
return ObjcopyPath.takeError(); | ||
|
||
// Use the linker output file to get a unique hash. This creates a unique | ||
// identifier to rename the sections to that is deterministic to the contents. | ||
auto BufferOrErr = DryRun ? MemoryBuffer::getMemBuffer("") | ||
: MemoryBuffer::getFileOrSTDIN(Output); | ||
if (!BufferOrErr) | ||
return createStringError(inconvertibleErrorCode(), "Failed to open %s", | ||
Output.str().c_str()); | ||
std::string Suffix = "_" + getHash((*BufferOrErr)->getBuffer()); | ||
|
||
SmallVector<StringRef> ObjcopyArgs = { | ||
*ObjcopyPath, | ||
Output, | ||
}; | ||
|
||
// Remove the old .llvm.offloading section to prevent further linking. | ||
ObjcopyArgs.emplace_back("--remove-section"); | ||
ObjcopyArgs.emplace_back(".llvm.offloading"); | ||
for (StringRef Prefix : {"omp", "cuda", "hip"}) { | ||
auto Section = (Prefix + "_offloading_entries").str(); | ||
// Rename the offloading entires to make them private to this link unit. | ||
ObjcopyArgs.emplace_back("--rename-section"); | ||
ObjcopyArgs.emplace_back( | ||
Args.MakeArgString(Section + "=" + Section + Suffix)); | ||
|
||
// Rename the __start_ / __stop_ symbols appropriately to iterate over the | ||
// newly renamed section containing the offloading entries. | ||
ObjcopyArgs.emplace_back("--redefine-sym"); | ||
ObjcopyArgs.emplace_back(Args.MakeArgString("__start_" + Section + "=" + | ||
"__start_" + Section + Suffix)); | ||
ObjcopyArgs.emplace_back("--redefine-sym"); | ||
ObjcopyArgs.emplace_back(Args.MakeArgString("__stop_" + Section + "=" + | ||
"__stop_" + Section + Suffix)); | ||
} | ||
|
||
if (Error Err = executeCommands(*ObjcopyPath, ObjcopyArgs)) | ||
return Err; | ||
|
||
return Error::success(); | ||
} | ||
|
||
/// Runs the wrapped linker job with the newly created input. | ||
Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) { | ||
llvm::TimeTraceScope TimeScope("Execute host linker"); | ||
|
@@ -265,6 +329,11 @@ Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) { | |
LinkerArgs.push_back(Arg); | ||
if (Error Err = executeCommands(LinkerPath, LinkerArgs)) | ||
return Err; | ||
|
||
if (Args.hasArg(OPT_relocatable)) | ||
if (Error Err = relocateOffloadSection(Args, ExecutableName)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could just |
||
return Err; | ||
|
||
return Error::success(); | ||
} | ||
|
||
|
@@ -910,7 +979,8 @@ wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers, | |
case OFK_OpenMP: | ||
if (Error Err = offloading::wrapOpenMPBinaries( | ||
M, BuffersToWrap, | ||
offloading::getOffloadEntryArray(M, "omp_offloading_entries"))) | ||
offloading::getOffloadEntryArray(M, "omp_offloading_entries"), | ||
/*Suffix=*/"", /*Relocatable=*/Args.hasArg(OPT_relocatable))) | ||
return std::move(Err); | ||
break; | ||
case OFK_Cuda: | ||
|
@@ -1356,12 +1426,6 @@ Expected<SmallVector<SmallVector<OffloadFile>>> | |
getDeviceInput(const ArgList &Args) { | ||
llvm::TimeTraceScope TimeScope("ExtractDeviceCode"); | ||
|
||
// If the user is requesting a reloctable link we ignore the device code. The | ||
// actual linker will merge the embedded device code sections so they can be | ||
// linked when the executable is finally created. | ||
if (Args.hasArg(OPT_relocatable)) | ||
return SmallVector<SmallVector<OffloadFile>>{}; | ||
|
||
StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ); | ||
SmallVector<StringRef> LibraryPaths; | ||
for (const opt::Arg *Arg : Args.filtered(OPT_library_path, OPT_libpath)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,10 +20,12 @@ using EntryArrayTy = std::pair<GlobalVariable *, GlobalVariable *>; | |
/// \param EntryArray Optional pair pointing to the `__start` and `__stop` | ||
/// symbols holding the `__tgt_offload_entry` array. | ||
/// \param Suffix An optional suffix appended to the emitted symbols. | ||
/// \param Relocatable Indicate if we need to change the offloading section. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: "Indicate whether the binary is a relocatable object" may work a bit better for describing intent. Current description seems to describe an implementation detail. |
||
llvm::Error wrapOpenMPBinaries(llvm::Module &M, | ||
llvm::ArrayRef<llvm::ArrayRef<char>> Images, | ||
EntryArrayTy EntryArray, | ||
llvm::StringRef Suffix = ""); | ||
llvm::StringRef Suffix = "", | ||
bool Relocatable = false); | ||
|
||
/// Wraps the input fatbinary image into the module \p M as global symbols and | ||
/// registers the images with the CUDA runtime. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to check device fatbin bundling is done and device wrapper fatbin variable using internal linkage and in postfixed section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test for the HIP and CUDA cases as well as an additional check on passing
-r
to the wrapper image generation.