-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang-linker-wrapper] Add ELF packaging for spirv64-intel OpenMP images #125737
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
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
Signed-off-by: Sarnie, Nick <[email protected]>
@llvm/pr-subscribers-clang Author: Nick Sarnie (sarnex) ChangesAdd manual ELF packaging for Full diff: https://github.com/llvm/llvm-project/pull/125737.diff 8 Files Affected:
diff --git a/clang/test/Tooling/Inputs/clang-linker-wrapper-spirv-elf.o b/clang/test/Tooling/Inputs/clang-linker-wrapper-spirv-elf.o
new file mode 100644
index 000000000000000..3e5bddcedfff163
Binary files /dev/null and b/clang/test/Tooling/Inputs/clang-linker-wrapper-spirv-elf.o differ
diff --git a/clang/test/Tooling/clang-linker-wrapper-spirv-elf.cpp b/clang/test/Tooling/clang-linker-wrapper-spirv-elf.cpp
new file mode 100644
index 000000000000000..602132172d0248f
--- /dev/null
+++ b/clang/test/Tooling/clang-linker-wrapper-spirv-elf.cpp
@@ -0,0 +1,14 @@
+// Verify the ELF packaging of OpenMP SPIR-V device images.
+// REQUIRES: system-linux
+// REQUIRES: spirv-tools
+// RUN: mkdir -p %t_tmp
+// RUN: cd %t_tmp
+// RUN: not clang-linker-wrapper -o a.out %S/Inputs/clang-linker-wrapper-spirv-elf.o --save-temps --linker-path=ld
+// RUN: clang-offload-packager --image=triple=spirv64-intel,kind=openmp,file=%t.elf %t_tmp/a.out.openmp.image.wrapper.o
+// RUN: llvm-readelf -t %t.elf | FileCheck -check-prefix=CHECK-SECTION %s
+// RUN: llvm-readelf -n %t.elf | FileCheck -check-prefix=CHECK-NOTES %s
+
+// CHECK-SECTION: .note.inteloneompoffload
+// CHECK-SECTION: __openmp_offload_spirv_0
+
+// CHECK-NOTES-COUNT-3: INTELONEOMPOFFLOAD
diff --git a/clang/test/Tooling/lit.local.cfg b/clang/test/Tooling/lit.local.cfg
index 4cd8ba72fa76715..bc2a096c8f64f88 100644
--- a/clang/test/Tooling/lit.local.cfg
+++ b/clang/test/Tooling/lit.local.cfg
@@ -1,2 +1,8 @@
if not config.root.clang_staticanalyzer:
config.unsupported = True
+
+if config.spirv_tools_tests:
+ config.available_features.add("spirv-tools")
+ config.substitutions.append(("spirv-dis", os.path.join(config.llvm_tools_dir, "spirv-dis")))
+ config.substitutions.append(("spirv-val", os.path.join(config.llvm_tools_dir, "spirv-val")))
+ config.substitutions.append(("spirv-as", os.path.join(config.llvm_tools_dir, "spirv-as")))
diff --git a/clang/test/lit.site.cfg.py.in b/clang/test/lit.site.cfg.py.in
index ae8b927624e23f8..ce10e9128a1dfe1 100644
--- a/clang/test/lit.site.cfg.py.in
+++ b/clang/test/lit.site.cfg.py.in
@@ -43,6 +43,7 @@ config.llvm_external_lit = path(r"@LLVM_EXTERNAL_LIT@")
config.standalone_build = @CLANG_BUILT_STANDALONE@
config.ppc_linux_default_ieeelongdouble = @PPC_LINUX_DEFAULT_IEEELONGDOUBLE@
config.have_llvm_driver = @LLVM_TOOL_LLVM_DRIVER_BUILD@
+config.spirv_tools_tests = "@LLVM_INCLUDE_SPIRV_TOOLS_TESTS@"
config.substitutions.append(("%llvm-version-major", "@LLVM_VERSION_MAJOR@"))
import lit.llvm
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index c92590581a645cc..d7d6418a4b5e2e0 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -605,6 +605,17 @@ Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
}
}
+Error containerizeRawImage(std::unique_ptr<MemoryBuffer> &Img, OffloadKind Kind,
+ const ArgList &Args) {
+ llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
+ if (Kind != OFK_OpenMP || !Triple.isSPIRV() ||
+ Triple.getVendor() != llvm::Triple::Intel)
+ return Error::success();
+ if (Error E = offloading::intel::containerizeOpenMPSPIRVImage(Img))
+ return E;
+ return Error::success();
+}
+
Expected<StringRef> writeOffloadFile(const OffloadFile &File) {
const OffloadBinary &Binary = *File.getBinary();
@@ -960,6 +971,10 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
return createFileError(*OutputOrErr, EC);
}
+ // Manually containerize offloading images not in ELF format.
+ if (Error E = containerizeRawImage(*FileOrErr, Kind, LinkerArgs))
+ return E;
+
std::scoped_lock<decltype(ImageMtx)> Guard(ImageMtx);
OffloadingImage TheImage{};
TheImage.TheImageKind =
diff --git a/llvm/include/llvm/Frontend/Offloading/Utility.h b/llvm/include/llvm/Frontend/Offloading/Utility.h
index 7932fd5acbe1e26..9140371a8c2ed21 100644
--- a/llvm/include/llvm/Frontend/Offloading/Utility.h
+++ b/llvm/include/llvm/Frontend/Offloading/Utility.h
@@ -10,6 +10,7 @@
#define LLVM_FRONTEND_OFFLOADING_UTILITY_H
#include <cstdint>
+#include <memory>
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -152,6 +153,11 @@ Error getAMDGPUMetaDataFromImage(MemoryBufferRef MemBuffer,
StringMap<AMDGPUKernelMetaData> &KernelInfoMap,
uint16_t &ELFABIVersion);
} // namespace amdgpu
+namespace intel {
+/// Containerizes an offloading binary into the ELF binary format expected by
+/// the Intel runtime offload plugin.
+Error containerizeOpenMPSPIRVImage(std::unique_ptr<MemoryBuffer> &Binary);
+} // namespace intel
} // namespace offloading
} // namespace llvm
diff --git a/llvm/lib/Frontend/Offloading/CMakeLists.txt b/llvm/lib/Frontend/Offloading/CMakeLists.txt
index ce445ad9cc4cb60..8e1ede9c72b391a 100644
--- a/llvm/lib/Frontend/Offloading/CMakeLists.txt
+++ b/llvm/lib/Frontend/Offloading/CMakeLists.txt
@@ -12,6 +12,7 @@ add_llvm_component_library(LLVMFrontendOffloading
Core
BinaryFormat
Object
+ ObjectYAML
Support
TransformUtils
TargetParser
diff --git a/llvm/lib/Frontend/Offloading/Utility.cpp b/llvm/lib/Frontend/Offloading/Utility.cpp
index 8117a42b8a45cd1..f9c74ab975d1023 100644
--- a/llvm/lib/Frontend/Offloading/Utility.cpp
+++ b/llvm/lib/Frontend/Offloading/Utility.cpp
@@ -15,6 +15,8 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Value.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
@@ -373,3 +375,86 @@ Error llvm::offloading::amdgpu::getAMDGPUMetaDataFromImage(
}
return Error::success();
}
+Error offloading::intel::containerizeOpenMPSPIRVImage(
+ std::unique_ptr<MemoryBuffer> &Img) {
+ constexpr char INTEL_ONEOMP_OFFLOAD_VERSION[] = "1.0";
+ constexpr int NT_INTEL_ONEOMP_OFFLOAD_VERSION = 1;
+ constexpr int NT_INTEL_ONEOMP_OFFLOAD_IMAGE_COUNT = 2;
+ constexpr int NT_INTEL_ONEOMP_OFFLOAD_IMAGE_AUX = 3;
+
+ // Start creating notes for the ELF container.
+ std::vector<ELFYAML::NoteEntry> Notes;
+ std::string Version = toHex(INTEL_ONEOMP_OFFLOAD_VERSION);
+ Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
+ yaml::BinaryRef(Version),
+ NT_INTEL_ONEOMP_OFFLOAD_VERSION});
+
+ // The AuxInfo string will hold auxiliary information for the image.
+ // ELFYAML::NoteEntry structures will hold references to the
+ // string, so we have to make sure the string is valid.
+ std::string AuxInfo;
+
+ // TODO: Pass compile/link opts
+ StringRef CompileOpts = "";
+ StringRef LinkOpts = "";
+
+ unsigned ImageFmt = 1; // SPIR-V format
+
+ AuxInfo = toHex((Twine(0) + Twine('\0') + Twine(ImageFmt) + Twine('\0') +
+ CompileOpts + Twine('\0') + LinkOpts)
+ .str());
+ Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
+ yaml::BinaryRef(AuxInfo),
+ NT_INTEL_ONEOMP_OFFLOAD_IMAGE_AUX});
+
+ std::string ImgCount = toHex(Twine(1).str()); // always one image per ELF
+ Notes.emplace_back(ELFYAML::NoteEntry{"INTELONEOMPOFFLOAD",
+ yaml::BinaryRef(ImgCount),
+ NT_INTEL_ONEOMP_OFFLOAD_IMAGE_COUNT});
+
+ std::string YamlFile;
+ llvm::raw_string_ostream YamlFileStream(YamlFile);
+
+ // Write YAML template file.
+ {
+ // We use 64-bit little-endian ELF currently.
+ ELFYAML::FileHeader Header{};
+ Header.Class = ELF::ELFCLASS64;
+ Header.Data = ELF::ELFDATA2LSB;
+ Header.Type = ELF::ET_DYN;
+ // Use an existing Intel machine type as there is not one specifically for
+ // Intel GPUs.
+ Header.Machine = ELF::EM_IA_64;
+
+ // Create a section with notes.
+ ELFYAML::NoteSection Section{};
+ Section.Type = ELF::SHT_NOTE;
+ Section.AddressAlign = 0;
+ Section.Name = ".note.inteloneompoffload";
+ Section.Notes.emplace(std::move(Notes));
+
+ ELFYAML::Object Object{};
+ Object.Header = Header;
+ Object.Chunks.push_back(
+ std::make_unique<ELFYAML::NoteSection>(std::move(Section)));
+
+ // Create the section that will hold the image
+ ELFYAML::RawContentSection ImageSection{};
+ ImageSection.Type = ELF::SHT_PROGBITS;
+ ImageSection.AddressAlign = 0;
+ std::string Name = "__openmp_offload_spirv_0";
+ ImageSection.Name = Name;
+ ImageSection.Content =
+ llvm::yaml::BinaryRef(arrayRefFromStringRef(Img->getBuffer()));
+ Object.Chunks.push_back(
+ std::make_unique<ELFYAML::RawContentSection>(std::move(ImageSection)));
+ Error Err = Error::success();
+ llvm::yaml::yaml2elf(
+ Object, YamlFileStream,
+ [&Err](const Twine &Msg) { Err = createStringError(Msg); }, UINT64_MAX);
+ if (Err)
+ return Err;
+ }
+ Img = MemoryBuffer::getMemBufferCopy(YamlFile);
+ return Error::success();
+}
|
Signed-off-by: Sarnie, Nick <[email protected]>
Hi @sarnex, the test you added seems to be failing on a buildbot, can you take a look? https://lab.llvm.org/buildbot/#/builders/144/builds/17530
|
looking |
I wonder if it is only happening on a rebuild not a clean build. This one was clean: But your test did not fail (I assume did not run). This one is a rebuild: Where it does fail. I have seen this before and it was because I had missed some part of adding a new feature to lit.You may want to look at other variables like |
yeah my test should only run if
the lit feature i added should only be enabled if |
Might just be a stale config, I don't know what causes those rules to be regenerated. |
what should i do in that case? can i just ignore the failure or is there a way to clear the build cache? |
I got the failure locally as well, unsure, maybe there's a dependency missing somewhere. |
ok cool if you can repro it it's almost surely a real issue. can you share the repro steps? my local repro has it as unsupported as i expect |
If you cannot fix this soon, can you revert to get the bots back to green while you investigate? |
yes i will revert if i dont have a fix pr within 30 minutes |
|
thanks a lot, i think i see the problem, but would help if i could repro :P |
Fix for lit fail from #125737 Signed-off-by: Sarnie, Nick <[email protected]>
…26098) Fix for lit fail from llvm/llvm-project#125737 Signed-off-by: Sarnie, Nick <[email protected]>
…ges (llvm#125737) Add manual ELF packaging for `spirv64-intel` images as there is no SPIR-V linker available. This format will be expected by the runtime plugin we will submit in the future and is compatible with the format we already use downstream. --------- Signed-off-by: Sarnie, Nick <[email protected]>
Fix for lit fail from llvm#125737 Signed-off-by: Sarnie, Nick <[email protected]>
Add manual ELF packaging for
spirv64-intel
images as there is no SPIR-V linker available. This format will be expected by the runtime plugin we will submit in the future and is compatible with the format we already use downstream.