diff --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h --- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h +++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h @@ -15,6 +15,7 @@ #include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/ObjectYAML/MachOYAML.h" #include "llvm/ObjectYAML/MinidumpYAML.h" +#include "llvm/ObjectYAML/OffloadYAML.h" #include "llvm/ObjectYAML/WasmYAML.h" #include "llvm/ObjectYAML/XCOFFYAML.h" #include "llvm/Support/YAMLTraits.h" @@ -32,6 +33,7 @@ std::unique_ptr MachO; std::unique_ptr FatMachO; std::unique_ptr Minidump; + std::unique_ptr Offload; std::unique_ptr Wasm; std::unique_ptr Xcoff; std::unique_ptr DXContainer; diff --git a/llvm/include/llvm/ObjectYAML/OffloadYAML.h b/llvm/include/llvm/ObjectYAML/OffloadYAML.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/ObjectYAML/OffloadYAML.h @@ -0,0 +1,74 @@ +//===- OffloadYAML.h - Offload Binary YAMLIO implementation -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares classes for handling the YAML representation of +/// offloading binaries. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_OFFLOADYAML_H +#define LLVM_OBJECTYAML_OFFLOADYAML_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/Object/OffloadBinary.h" +#include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { +namespace OffloadYAML { + +struct Binary { + struct StringEntry { + StringRef Key; + StringRef Value; + }; + struct Member { + Optional ImageKind; + Optional OffloadKind; + Optional Flags; + Optional> StringEntries; + Optional Content; + }; + + std::vector Members; +}; + +} // end namespace OffloadYAML +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::OffloadYAML::Binary::Member) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::OffloadYAML::Binary::StringEntry) + +namespace llvm { +namespace yaml { + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, object::ImageKind &Value); +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, object::OffloadKind &Value); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, OffloadYAML::Binary &O); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, OffloadYAML::Binary::StringEntry &M); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, OffloadYAML::Binary::Member &M); +}; + +} // end namespace yaml +} // end namespace llvm + +#endif // LLVM_OBJECTYAML_ARCHIVEYAML_H diff --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h --- a/llvm/include/llvm/ObjectYAML/yaml2obj.h +++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h @@ -36,6 +36,10 @@ struct Object; } +namespace OffloadYAML { +struct Binary; +} + namespace WasmYAML { struct Object; } @@ -65,6 +69,7 @@ bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH); bool yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); +bool yaml2offload(OffloadYAML::Binary &Doc, raw_ostream &Out, ErrorHandler EH); bool yaml2wasm(WasmYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out, diff --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt --- a/llvm/lib/ObjectYAML/CMakeLists.txt +++ b/llvm/lib/ObjectYAML/CMakeLists.txt @@ -18,6 +18,8 @@ ObjectYAML.cpp MinidumpEmitter.cpp MinidumpYAML.cpp + OffloadEmitter.cpp + OffloadYAML.cpp WasmEmitter.cpp WasmYAML.cpp XCOFFEmitter.cpp diff --git a/llvm/lib/ObjectYAML/ObjectYAML.cpp b/llvm/lib/ObjectYAML/ObjectYAML.cpp --- a/llvm/lib/ObjectYAML/ObjectYAML.cpp +++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp @@ -56,6 +56,9 @@ } else if (IO.mapTag("!minidump")) { ObjectFile.Minidump.reset(new MinidumpYAML::Object()); MappingTraits::mapping(IO, *ObjectFile.Minidump); + } else if (IO.mapTag("!Offload")) { + ObjectFile.Offload.reset(new OffloadYAML::Binary()); + MappingTraits::mapping(IO, *ObjectFile.Offload); } else if (IO.mapTag("!WASM")) { ObjectFile.Wasm.reset(new WasmYAML::Object()); MappingTraits::mapping(IO, *ObjectFile.Wasm); diff --git a/llvm/lib/ObjectYAML/OffloadEmitter.cpp b/llvm/lib/ObjectYAML/OffloadEmitter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/ObjectYAML/OffloadEmitter.cpp @@ -0,0 +1,52 @@ +//===- OffloadEmitter.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/OffloadBinary.h" +#include "llvm/ObjectYAML/OffloadYAML.h" +#include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace OffloadYAML; + +namespace llvm { +namespace yaml { + +bool yaml2offload(Binary &Doc, raw_ostream &Out, ErrorHandler EH) { + for (const auto &Member : Doc.Members) { + object::OffloadBinary::OffloadingImage Image{}; + if (Member.ImageKind) + Image.TheImageKind = *Member.ImageKind; + if (Member.OffloadKind) + Image.TheOffloadKind = *Member.OffloadKind; + if (Member.Flags) + Image.Flags = *Member.Flags; + + StringMap &StringData = Image.StringData; + if (Member.StringEntries) { + for (const auto &Entry : *Member.StringEntries) { + StringData[Entry.Key] = Entry.Value; + } + } + + SmallVector Data; + raw_svector_ostream OS(Data); + if (Member.Content) + Member.Content->writeAsBinary(OS); + Image.Image = MemoryBuffer::getMemBufferCopy(OS.str()); + + auto Binary = object::OffloadBinary::write(Image); + Out.write(Binary->getBufferStart(), Binary->getBufferSize()); + } + + return true; +} + +} // namespace yaml +} // namespace llvm diff --git a/llvm/lib/ObjectYAML/OffloadYAML.cpp b/llvm/lib/ObjectYAML/OffloadYAML.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/ObjectYAML/OffloadYAML.cpp @@ -0,0 +1,74 @@ +//===- OffloadYAML.cpp - Offload Binary YAMLIO implementation -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines classes for handling the YAML representation of offload +// binaries. +// +//===----------------------------------------------------------------------===// + +#include + +namespace llvm { + +namespace yaml { + +void ScalarEnumerationTraits::enumeration( + IO &IO, object::ImageKind &Value) { +#define ECase(X) IO.enumCase(Value, #X, object::X) + ECase(IMG_None); + ECase(IMG_Object); + ECase(IMG_Bitcode); + ECase(IMG_Cubin); + ECase(IMG_Fatbinary); + ECase(IMG_PTX); + ECase(IMG_LAST); +#undef ECase + IO.enumFallback(Value); +} + +void ScalarEnumerationTraits::enumeration( + IO &IO, object::OffloadKind &Value) { +#define ECase(X) IO.enumCase(Value, #X, object::X) + ECase(OFK_None); + ECase(OFK_OpenMP); + ECase(OFK_Cuda); + ECase(OFK_HIP); + ECase(OFK_LAST); +#undef ECase + IO.enumFallback(Value); +} + +void MappingTraits::mapping(IO &IO, + OffloadYAML::Binary &O) { + assert(!IO.getContext() && "The IO context is initialized already"); + IO.setContext(&O); + IO.mapTag("!Offload", true); + IO.mapRequired("Members", O.Members); + IO.setContext(nullptr); +} + +void MappingTraits::mapping( + IO &IO, OffloadYAML::Binary::StringEntry &SE) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Key", SE.Key); + IO.mapRequired("Value", SE.Value); +} + +void MappingTraits::mapping( + IO &IO, OffloadYAML::Binary::Member &M) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapOptional("ImageKind", M.ImageKind); + IO.mapOptional("OffloadKind", M.OffloadKind); + IO.mapOptional("Flags", M.Flags); + IO.mapOptional("String", M.StringEntries); + IO.mapOptional("Content", M.Content); +} + +} // namespace yaml + +} // namespace llvm diff --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp --- a/llvm/lib/ObjectYAML/yaml2obj.cpp +++ b/llvm/lib/ObjectYAML/yaml2obj.cpp @@ -42,6 +42,8 @@ return yaml2macho(Doc, Out, ErrHandler); if (Doc.Minidump) return yaml2minidump(*Doc.Minidump, Out, ErrHandler); + if (Doc.Offload) + return yaml2offload(*Doc.Offload, Out, ErrHandler); if (Doc.Wasm) return yaml2wasm(*Doc.Wasm, Out, ErrHandler); if (Doc.Xcoff) diff --git a/llvm/test/ObjectYAML/Offload/binary.yaml b/llvm/test/ObjectYAML/Offload/binary.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/ObjectYAML/Offload/binary.yaml @@ -0,0 +1,25 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +!Offload +Members: + - ImageKind: IMG_Cubin + OffloadKind: OFK_OpenMP + Flags: 0 + String: + - Key: "triple" + Value: "nvptx64-nvidia-cuda" + - Key: "arch" + Value: "sm_70" + Content: "deadbeef" + + # CHECK: --- !Offload +# CHECK-NEXT: Members: +# CHECK-NEXT: - ImageKind: IMG_Cubin +# CHECK-NEXT: OffloadKind: OFK_OpenMP +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: String: +# CHECK-NEXT: - Key: triple +# CHECK-NEXT: Value: nvptx64-nvidia-cuda +# CHECK-NEXT: - Key: arch +# CHECK-NEXT: Value: sm_70 +# CHECK-NEXT: Content: DEADBEEF +# CHECK-NEXT: ... diff --git a/llvm/test/ObjectYAML/Offload/default.yaml b/llvm/test/ObjectYAML/Offload/default.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/ObjectYAML/Offload/default.yaml @@ -0,0 +1,11 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +!Offload +Members: + - + +# CHECK: --- !Offload +# CHECK-NEXT: Members: +# CHECK-NEXT: - ImageKind: IMG_None +# CHECK-NEXT: OffloadKind: OFK_None +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: ... diff --git a/llvm/test/ObjectYAML/Offload/enumeration_kinds.yaml b/llvm/test/ObjectYAML/Offload/enumeration_kinds.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/ObjectYAML/Offload/enumeration_kinds.yaml @@ -0,0 +1,40 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +!Offload +Members: + - ImageKind: IMG_None + OffloadKind: OFK_None + - ImageKind: IMG_Object + OffloadKind: OFK_OpenMP + - ImageKind: IMG_Bitcode + OffloadKind: OFK_Cuda + - ImageKind: IMG_Cubin + OffloadKind: OFK_HIP + - ImageKind: IMG_Fatbinary + - ImageKind: IMG_PTX + - ImageKind: 999 + OffloadKind: 999 + +# CHECK: --- !Offload +# CHECK-NEXT: Members: +# CHECK-NEXT: - ImageKind: IMG_None +# CHECK-NEXT: OffloadKind: OFK_None +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: - ImageKind: IMG_Object +# CHECK-NEXT: OffloadKind: OFK_OpenMP +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: - ImageKind: IMG_Bitcode +# CHECK-NEXT: OffloadKind: OFK_Cuda +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: - ImageKind: IMG_Cubin +# CHECK-NEXT: OffloadKind: OFK_HIP +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: - ImageKind: IMG_Fatbinary +# CHECK-NEXT: OffloadKind: OFK_None +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: - ImageKind: IMG_PTX +# CHECK-NEXT: OffloadKind: OFK_None +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: - ImageKind: 0x3E7 +# CHECK-NEXT: OffloadKind: 0x3E7 +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: ... diff --git a/llvm/test/ObjectYAML/Offload/multiple_members.yaml b/llvm/test/ObjectYAML/Offload/multiple_members.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/ObjectYAML/Offload/multiple_members.yaml @@ -0,0 +1,43 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s +!Offload +Members: + - ImageKind: IMG_Cubin + OffloadKind: OFK_OpenMP + Flags: 0 + String: + - Key: "triple" + Value: "nvptx64-nvidia-cuda" + - Key: "arch" + Value: "sm_70" + Content: "deadbeef" + - ImageKind: IMG_Bitcode + OffloadKind: OFK_OpenMP + Flags: 0 + String: + - Key: "triple" + Value: "amdgcn-amd-amdhsa" + - Key: "arch" + Value: "gfx908" + Content: "cafefeed" + +# CHECK: --- !Offload +# CHECK-NEXT: Members: +# CHECK-NEXT: - ImageKind: IMG_Cubin +# CHECK-NEXT: OffloadKind: OFK_OpenMP +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: String: +# CHECK-NEXT: - Key: triple +# CHECK-NEXT: Value: nvptx64-nvidia-cuda +# CHECK-NEXT: - Key: arch +# CHECK-NEXT: Value: sm_70 +# CHECK-NEXT: Content: DEADBEEF +# CHECK-NEXT: - ImageKind: IMG_Bitcode +# CHECK-NEXT: OffloadKind: OFK_OpenMP +# CHECK-NEXT: Flags: 0 +# CHECK-NEXT: String: +# CHECK-NEXT: - Key: triple +# CHECK-NEXT: Value: amdgcn-amd-amdhsa +# CHECK-NEXT: - Key: arch +# CHECK-NEXT: Value: gfx908 +# CHECK-NEXT: Content: CAFEFEED +# CHECK-NEXT: ... diff --git a/llvm/tools/obj2yaml/CMakeLists.txt b/llvm/tools/obj2yaml/CMakeLists.txt --- a/llvm/tools/obj2yaml/CMakeLists.txt +++ b/llvm/tools/obj2yaml/CMakeLists.txt @@ -16,6 +16,7 @@ elf2yaml.cpp macho2yaml.cpp minidump2yaml.cpp + offload2yaml.cpp xcoff2yaml.cpp wasm2yaml.cpp ) diff --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h --- a/llvm/tools/obj2yaml/obj2yaml.h +++ b/llvm/tools/obj2yaml/obj2yaml.h @@ -16,15 +16,15 @@ #include "llvm/Object/Minidump.h" #include "llvm/Object/Wasm.h" #include "llvm/Object/XCOFFObjectFile.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/MemoryBufferRef.h" +#include "llvm/Support/raw_ostream.h" #include enum RawSegments : unsigned { none = 0, data = 1, linkedit = 1 << 1 }; std::error_code coff2yaml(llvm::raw_ostream &Out, const llvm::object::COFFObjectFile &Obj); llvm::Error elf2yaml(llvm::raw_ostream &Out, - const llvm::object::ObjectFile &Obj); + const llvm::object::ObjectFile &Obj); llvm::Error macho2yaml(llvm::raw_ostream &Out, const llvm::object::Binary &Obj, unsigned RawSegments); llvm::Error minidump2yaml(llvm::raw_ostream &Out, @@ -34,6 +34,7 @@ std::error_code wasm2yaml(llvm::raw_ostream &Out, const llvm::object::WasmObjectFile &Obj); llvm::Error archive2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source); +llvm::Error offload2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source); llvm::Error dxcontainer2yaml(llvm::raw_ostream &Out, llvm::MemoryBufferRef Source); @@ -43,7 +44,7 @@ namespace DWARFYAML { struct Data; } -} +} // namespace llvm void dumpDebugAbbrev(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y); llvm::Error dumpDebugAddr(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y); diff --git a/llvm/tools/obj2yaml/obj2yaml.cpp b/llvm/tools/obj2yaml/obj2yaml.cpp --- a/llvm/tools/obj2yaml/obj2yaml.cpp +++ b/llvm/tools/obj2yaml/obj2yaml.cpp @@ -55,6 +55,8 @@ return archive2yaml(outs(), MemBuf); case file_magic::dxcontainer_object: return dxcontainer2yaml(outs(), MemBuf); + case file_magic::offload_binary: + return offload2yaml(outs(), MemBuf); default: break; } diff --git a/llvm/tools/obj2yaml/offload2yaml.cpp b/llvm/tools/obj2yaml/offload2yaml.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/obj2yaml/offload2yaml.cpp @@ -0,0 +1,82 @@ +//===------ offload2yaml.cpp - obj2yaml conversion tool ---*- C++ -------*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "obj2yaml.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Object/OffloadBinary.h" +#include "llvm/ObjectYAML/OffloadYAML.h" +#include "llvm/Support/StringSaver.h" + +using namespace llvm; + +namespace { + +void populateYAML(OffloadYAML::Binary &YAMLBinary, object::OffloadBinary &OB, + UniqueStringSaver Saver) { + YAMLBinary.Members.emplace_back(); + auto &Member = YAMLBinary.Members.back(); + Member.ImageKind = OB.getImageKind(); + Member.OffloadKind = OB.getOffloadKind(); + Member.Flags = OB.getFlags(); + if (!OB.strings().empty()) { + Member.StringEntries = std::vector(); + for (const auto &Entry : OB.strings()) + Member.StringEntries->emplace_back(OffloadYAML::Binary::StringEntry( + {Saver.save(Entry.getKey()), Saver.save(Entry.getValue())})); + } + + if (!OB.getImage().empty()) + Member.Content = arrayRefFromStringRef(OB.getImage()); +} + +Expected dump(MemoryBufferRef Source, + UniqueStringSaver Saver) { + Expected> OB = + object::OffloadBinary::create(Source); + if (!OB) + return OB.takeError(); + + std::unique_ptr YAMLBinary = + std::make_unique(); + + YAMLBinary->Members = std::vector(); + + uint64_t Offset = 0; + while (Offset < (*OB)->getMemoryBufferRef().getBufferSize()) { + MemoryBufferRef Buffer = MemoryBufferRef( + (*OB)->getData().drop_front(Offset), (*OB)->getFileName()); + auto BinaryOrErr = object::OffloadBinary::create(Buffer); + if (!BinaryOrErr) + return BinaryOrErr.takeError(); + + object::OffloadBinary &Binary = **BinaryOrErr; + + populateYAML(*YAMLBinary, Binary, Saver); + + Offset += Binary.getSize(); + } + + return YAMLBinary.release(); +} + +} // namespace + +Error offload2yaml(raw_ostream &Out, MemoryBufferRef Source) { + BumpPtrAllocator Alloc; + UniqueStringSaver Saver(Alloc); + + Expected YAMLOrErr = dump(Source, Saver); + if (!YAMLOrErr) + return YAMLOrErr.takeError(); + + std::unique_ptr YAML(YAMLOrErr.get()); + yaml::Output Yout(Out); + Yout << *YAML; + + return Error::success(); +}