diff options
Diffstat (limited to 'lib/BinaryFormat')
-rw-r--r-- | lib/BinaryFormat/AMDGPUMetadataVerifier.cpp | 324 | ||||
-rw-r--r-- | lib/BinaryFormat/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/BinaryFormat/Dwarf.cpp | 40 | ||||
-rw-r--r-- | lib/BinaryFormat/Magic.cpp | 2 | ||||
-rw-r--r-- | lib/BinaryFormat/MsgPackReader.cpp | 255 | ||||
-rw-r--r-- | lib/BinaryFormat/MsgPackTypes.cpp | 303 | ||||
-rw-r--r-- | lib/BinaryFormat/MsgPackWriter.cpp | 209 | ||||
-rw-r--r-- | lib/BinaryFormat/Wasm.cpp | 6 |
8 files changed, 1136 insertions, 7 deletions
diff --git a/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp b/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp new file mode 100644 index 000000000000..b789f646b5f6 --- /dev/null +++ b/lib/BinaryFormat/AMDGPUMetadataVerifier.cpp @@ -0,0 +1,324 @@ +//===- AMDGPUMetadataVerifier.cpp - MsgPack Types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Implements a verifier for AMDGPU HSA metadata. +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" +#include "llvm/Support/AMDGPUMetadata.h" + +namespace llvm { +namespace AMDGPU { +namespace HSAMD { +namespace V3 { + +bool MetadataVerifier::verifyScalar( + msgpack::Node &Node, msgpack::ScalarNode::ScalarKind SKind, + function_ref<bool(msgpack::ScalarNode &)> verifyValue) { + auto ScalarPtr = dyn_cast<msgpack::ScalarNode>(&Node); + if (!ScalarPtr) + return false; + auto &Scalar = *ScalarPtr; + // Do not output extraneous tags for types we know from the spec. + Scalar.IgnoreTag = true; + if (Scalar.getScalarKind() != SKind) { + if (Strict) + return false; + // If we are not strict, we interpret string values as "implicitly typed" + // and attempt to coerce them to the expected type here. + if (Scalar.getScalarKind() != msgpack::ScalarNode::SK_String) + return false; + std::string StringValue = Scalar.getString(); + Scalar.setScalarKind(SKind); + if (Scalar.inputYAML(StringValue) != StringRef()) + return false; + } + if (verifyValue) + return verifyValue(Scalar); + return true; +} + +bool MetadataVerifier::verifyInteger(msgpack::Node &Node) { + if (!verifyScalar(Node, msgpack::ScalarNode::SK_UInt)) + if (!verifyScalar(Node, msgpack::ScalarNode::SK_Int)) + return false; + return true; +} + +bool MetadataVerifier::verifyArray( + msgpack::Node &Node, function_ref<bool(msgpack::Node &)> verifyNode, + Optional<size_t> Size) { + auto ArrayPtr = dyn_cast<msgpack::ArrayNode>(&Node); + if (!ArrayPtr) + return false; + auto &Array = *ArrayPtr; + if (Size && Array.size() != *Size) + return false; + for (auto &Item : Array) + if (!verifyNode(*Item.get())) + return false; + + return true; +} + +bool MetadataVerifier::verifyEntry( + msgpack::MapNode &MapNode, StringRef Key, bool Required, + function_ref<bool(msgpack::Node &)> verifyNode) { + auto Entry = MapNode.find(Key); + if (Entry == MapNode.end()) + return !Required; + return verifyNode(*Entry->second.get()); +} + +bool MetadataVerifier::verifyScalarEntry( + msgpack::MapNode &MapNode, StringRef Key, bool Required, + msgpack::ScalarNode::ScalarKind SKind, + function_ref<bool(msgpack::ScalarNode &)> verifyValue) { + return verifyEntry(MapNode, Key, Required, [=](msgpack::Node &Node) { + return verifyScalar(Node, SKind, verifyValue); + }); +} + +bool MetadataVerifier::verifyIntegerEntry(msgpack::MapNode &MapNode, + StringRef Key, bool Required) { + return verifyEntry(MapNode, Key, Required, [this](msgpack::Node &Node) { + return verifyInteger(Node); + }); +} + +bool MetadataVerifier::verifyKernelArgs(msgpack::Node &Node) { + auto ArgsMapPtr = dyn_cast<msgpack::MapNode>(&Node); + if (!ArgsMapPtr) + return false; + auto &ArgsMap = *ArgsMapPtr; + + if (!verifyScalarEntry(ArgsMap, ".name", false, + msgpack::ScalarNode::SK_String)) + return false; + if (!verifyScalarEntry(ArgsMap, ".type_name", false, + msgpack::ScalarNode::SK_String)) + return false; + if (!verifyIntegerEntry(ArgsMap, ".size", true)) + return false; + if (!verifyIntegerEntry(ArgsMap, ".offset", true)) + return false; + if (!verifyScalarEntry(ArgsMap, ".value_kind", true, + msgpack::ScalarNode::SK_String, + [](msgpack::ScalarNode &SNode) { + return StringSwitch<bool>(SNode.getString()) + .Case("by_value", true) + .Case("global_buffer", true) + .Case("dynamic_shared_pointer", true) + .Case("sampler", true) + .Case("image", true) + .Case("pipe", true) + .Case("queue", true) + .Case("hidden_global_offset_x", true) + .Case("hidden_global_offset_y", true) + .Case("hidden_global_offset_z", true) + .Case("hidden_none", true) + .Case("hidden_printf_buffer", true) + .Case("hidden_default_queue", true) + .Case("hidden_completion_action", true) + .Default(false); + })) + return false; + if (!verifyScalarEntry(ArgsMap, ".value_type", true, + msgpack::ScalarNode::SK_String, + [](msgpack::ScalarNode &SNode) { + return StringSwitch<bool>(SNode.getString()) + .Case("struct", true) + .Case("i8", true) + .Case("u8", true) + .Case("i16", true) + .Case("u16", true) + .Case("f16", true) + .Case("i32", true) + .Case("u32", true) + .Case("f32", true) + .Case("i64", true) + .Case("u64", true) + .Case("f64", true) + .Default(false); + })) + return false; + if (!verifyIntegerEntry(ArgsMap, ".pointee_align", false)) + return false; + if (!verifyScalarEntry(ArgsMap, ".address_space", false, + msgpack::ScalarNode::SK_String, + [](msgpack::ScalarNode &SNode) { + return StringSwitch<bool>(SNode.getString()) + .Case("private", true) + .Case("global", true) + .Case("constant", true) + .Case("local", true) + .Case("generic", true) + .Case("region", true) + .Default(false); + })) + return false; + if (!verifyScalarEntry(ArgsMap, ".access", false, + msgpack::ScalarNode::SK_String, + [](msgpack::ScalarNode &SNode) { + return StringSwitch<bool>(SNode.getString()) + .Case("read_only", true) + .Case("write_only", true) + .Case("read_write", true) + .Default(false); + })) + return false; + if (!verifyScalarEntry(ArgsMap, ".actual_access", false, + msgpack::ScalarNode::SK_String, + [](msgpack::ScalarNode &SNode) { + return StringSwitch<bool>(SNode.getString()) + .Case("read_only", true) + .Case("write_only", true) + .Case("read_write", true) + .Default(false); + })) + return false; + if (!verifyScalarEntry(ArgsMap, ".is_const", false, + msgpack::ScalarNode::SK_Boolean)) + return false; + if (!verifyScalarEntry(ArgsMap, ".is_restrict", false, + msgpack::ScalarNode::SK_Boolean)) + return false; + if (!verifyScalarEntry(ArgsMap, ".is_volatile", false, + msgpack::ScalarNode::SK_Boolean)) + return false; + if (!verifyScalarEntry(ArgsMap, ".is_pipe", false, + msgpack::ScalarNode::SK_Boolean)) + return false; + + return true; +} + +bool MetadataVerifier::verifyKernel(msgpack::Node &Node) { + auto KernelMapPtr = dyn_cast<msgpack::MapNode>(&Node); + if (!KernelMapPtr) + return false; + auto &KernelMap = *KernelMapPtr; + + if (!verifyScalarEntry(KernelMap, ".name", true, + msgpack::ScalarNode::SK_String)) + return false; + if (!verifyScalarEntry(KernelMap, ".symbol", true, + msgpack::ScalarNode::SK_String)) + return false; + if (!verifyScalarEntry(KernelMap, ".language", false, + msgpack::ScalarNode::SK_String, + [](msgpack::ScalarNode &SNode) { + return StringSwitch<bool>(SNode.getString()) + .Case("OpenCL C", true) + .Case("OpenCL C++", true) + .Case("HCC", true) + .Case("HIP", true) + .Case("OpenMP", true) + .Case("Assembler", true) + .Default(false); + })) + return false; + if (!verifyEntry( + KernelMap, ".language_version", false, [this](msgpack::Node &Node) { + return verifyArray( + Node, + [this](msgpack::Node &Node) { return verifyInteger(Node); }, 2); + })) + return false; + if (!verifyEntry(KernelMap, ".args", false, [this](msgpack::Node &Node) { + return verifyArray(Node, [this](msgpack::Node &Node) { + return verifyKernelArgs(Node); + }); + })) + return false; + if (!verifyEntry(KernelMap, ".reqd_workgroup_size", false, + [this](msgpack::Node &Node) { + return verifyArray(Node, + [this](msgpack::Node &Node) { + return verifyInteger(Node); + }, + 3); + })) + return false; + if (!verifyEntry(KernelMap, ".workgroup_size_hint", false, + [this](msgpack::Node &Node) { + return verifyArray(Node, + [this](msgpack::Node &Node) { + return verifyInteger(Node); + }, + 3); + })) + return false; + if (!verifyScalarEntry(KernelMap, ".vec_type_hint", false, + msgpack::ScalarNode::SK_String)) + return false; + if (!verifyScalarEntry(KernelMap, ".device_enqueue_symbol", false, + msgpack::ScalarNode::SK_String)) + return false; + if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_size", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".group_segment_fixed_size", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".private_segment_fixed_size", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".kernarg_segment_align", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".wavefront_size", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".sgpr_count", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".vgpr_count", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".max_flat_workgroup_size", true)) + return false; + if (!verifyIntegerEntry(KernelMap, ".sgpr_spill_count", false)) + return false; + if (!verifyIntegerEntry(KernelMap, ".vgpr_spill_count", false)) + return false; + + return true; +} + +bool MetadataVerifier::verify(msgpack::Node &HSAMetadataRoot) { + auto RootMapPtr = dyn_cast<msgpack::MapNode>(&HSAMetadataRoot); + if (!RootMapPtr) + return false; + auto &RootMap = *RootMapPtr; + + if (!verifyEntry( + RootMap, "amdhsa.version", true, [this](msgpack::Node &Node) { + return verifyArray( + Node, + [this](msgpack::Node &Node) { return verifyInteger(Node); }, 2); + })) + return false; + if (!verifyEntry( + RootMap, "amdhsa.printf", false, [this](msgpack::Node &Node) { + return verifyArray(Node, [this](msgpack::Node &Node) { + return verifyScalar(Node, msgpack::ScalarNode::SK_String); + }); + })) + return false; + if (!verifyEntry(RootMap, "amdhsa.kernels", true, + [this](msgpack::Node &Node) { + return verifyArray(Node, [this](msgpack::Node &Node) { + return verifyKernel(Node); + }); + })) + return false; + + return true; +} + +} // end namespace V3 +} // end namespace HSAMD +} // end namespace AMDGPU +} // end namespace llvm diff --git a/lib/BinaryFormat/CMakeLists.txt b/lib/BinaryFormat/CMakeLists.txt index 06826010c762..d645279d0ac5 100644 --- a/lib/BinaryFormat/CMakeLists.txt +++ b/lib/BinaryFormat/CMakeLists.txt @@ -1,6 +1,10 @@ add_llvm_library(LLVMBinaryFormat + AMDGPUMetadataVerifier.cpp Dwarf.cpp Magic.cpp + MsgPackReader.cpp + MsgPackTypes.cpp + MsgPackWriter.cpp Wasm.cpp ADDITIONAL_HEADER_DIRS diff --git a/lib/BinaryFormat/Dwarf.cpp b/lib/BinaryFormat/Dwarf.cpp index 5984de73ae63..46f8056774b7 100644 --- a/lib/BinaryFormat/Dwarf.cpp +++ b/lib/BinaryFormat/Dwarf.cpp @@ -13,6 +13,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -300,7 +301,7 @@ StringRef llvm::dwarf::LanguageString(unsigned Language) { switch (Language) { default: return StringRef(); -#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ +#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR) \ case DW_LANG_##NAME: \ return "DW_LANG_" #NAME; #include "llvm/BinaryFormat/Dwarf.def" @@ -309,7 +310,7 @@ StringRef llvm::dwarf::LanguageString(unsigned Language) { unsigned llvm::dwarf::getLanguage(StringRef LanguageString) { return StringSwitch<unsigned>(LanguageString) -#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ +#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR) \ .Case("DW_LANG_" #NAME, DW_LANG_##NAME) #include "llvm/BinaryFormat/Dwarf.def" .Default(0); @@ -319,7 +320,7 @@ unsigned llvm::dwarf::LanguageVersion(dwarf::SourceLanguage Lang) { switch (Lang) { default: return 0; -#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ +#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR) \ case DW_LANG_##NAME: \ return VERSION; #include "llvm/BinaryFormat/Dwarf.def" @@ -330,13 +331,24 @@ unsigned llvm::dwarf::LanguageVendor(dwarf::SourceLanguage Lang) { switch (Lang) { default: return 0; -#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ +#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR) \ case DW_LANG_##NAME: \ return DWARF_VENDOR_##VENDOR; #include "llvm/BinaryFormat/Dwarf.def" } } +Optional<unsigned> llvm::dwarf::LanguageLowerBound(dwarf::SourceLanguage Lang) { + switch (Lang) { + default: + return None; +#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR) \ + case DW_LANG_##NAME: \ + return LOWER_BOUND; +#include "llvm/BinaryFormat/Dwarf.def" + } +} + StringRef llvm::dwarf::CaseString(unsigned Case) { switch (Case) { case DW_ID_case_sensitive: @@ -455,14 +467,32 @@ StringRef llvm::dwarf::RangeListEncodingString(unsigned Encoding) { } } -StringRef llvm::dwarf::CallFrameString(unsigned Encoding) { +StringRef llvm::dwarf::CallFrameString(unsigned Encoding, + Triple::ArchType Arch) { + assert(Arch != llvm::Triple::ArchType::UnknownArch); +#define SELECT_AARCH64 (Arch == llvm::Triple::aarch64_be || Arch == llvm::Triple::aarch64) +#define SELECT_MIPS64 Arch == llvm::Triple::mips64 +#define SELECT_SPARC (Arch == llvm::Triple::sparc || Arch == llvm::Triple::sparcv9) +#define SELECT_X86 (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) +#define HANDLE_DW_CFA(ID, NAME) +#define HANDLE_DW_CFA_PRED(ID, NAME, PRED) \ + if (ID == Encoding && PRED) \ + return "DW_CFA_" #NAME; +#include "llvm/BinaryFormat/Dwarf.def" + switch (Encoding) { default: return StringRef(); +#define HANDLE_DW_CFA_PRED(ID, NAME, PRED) #define HANDLE_DW_CFA(ID, NAME) \ case DW_CFA_##NAME: \ return "DW_CFA_" #NAME; #include "llvm/BinaryFormat/Dwarf.def" + +#undef SELECT_X86 +#undef SELECT_SPARC +#undef SELECT_MIPS64 +#undef SELECT_AARCH64 } } diff --git a/lib/BinaryFormat/Magic.cpp b/lib/BinaryFormat/Magic.cpp index 5a339583fca1..78efa6ec87be 100644 --- a/lib/BinaryFormat/Magic.cpp +++ b/lib/BinaryFormat/Magic.cpp @@ -206,7 +206,7 @@ file_magic llvm::identify_magic(StringRef Magic) { } std::error_code llvm::identify_magic(const Twine &Path, file_magic &Result) { - auto FileOrError = MemoryBuffer::getFile(Path); + auto FileOrError = MemoryBuffer::getFile(Path, -1LL, false); if (!FileOrError) return FileOrError.getError(); diff --git a/lib/BinaryFormat/MsgPackReader.cpp b/lib/BinaryFormat/MsgPackReader.cpp new file mode 100644 index 000000000000..b510fdba9608 --- /dev/null +++ b/lib/BinaryFormat/MsgPackReader.cpp @@ -0,0 +1,255 @@ +//===- MsgPackReader.cpp - Simple MsgPack reader ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements a MessagePack reader. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/MsgPackReader.h" +#include "llvm/BinaryFormat/MsgPack.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace msgpack; + +Reader::Reader(MemoryBufferRef InputBuffer) + : InputBuffer(InputBuffer), Current(InputBuffer.getBufferStart()), + End(InputBuffer.getBufferEnd()) {} + +Reader::Reader(StringRef Input) : Reader({Input, "MsgPack"}) {} + +Expected<bool> Reader::read(Object &Obj) { + if (Current == End) + return false; + + uint8_t FB = static_cast<uint8_t>(*Current++); + + switch (FB) { + case FirstByte::Nil: + Obj.Kind = Type::Nil; + return true; + case FirstByte::True: + Obj.Kind = Type::Boolean; + Obj.Bool = true; + return true; + case FirstByte::False: + Obj.Kind = Type::Boolean; + Obj.Bool = false; + return true; + case FirstByte::Int8: + Obj.Kind = Type::Int; + return readInt<int8_t>(Obj); + case FirstByte::Int16: + Obj.Kind = Type::Int; + return readInt<int16_t>(Obj); + case FirstByte::Int32: + Obj.Kind = Type::Int; + return readInt<int32_t>(Obj); + case FirstByte::Int64: + Obj.Kind = Type::Int; + return readInt<int64_t>(Obj); + case FirstByte::UInt8: + Obj.Kind = Type::UInt; + return readUInt<uint8_t>(Obj); + case FirstByte::UInt16: + Obj.Kind = Type::UInt; + return readUInt<uint16_t>(Obj); + case FirstByte::UInt32: + Obj.Kind = Type::UInt; + return readUInt<uint32_t>(Obj); + case FirstByte::UInt64: + Obj.Kind = Type::UInt; + return readUInt<uint64_t>(Obj); + case FirstByte::Float32: + Obj.Kind = Type::Float; + if (sizeof(float) > remainingSpace()) + return make_error<StringError>( + "Invalid Float32 with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Float = BitsToFloat(endian::read<uint32_t, Endianness>(Current)); + Current += sizeof(float); + return true; + case FirstByte::Float64: + Obj.Kind = Type::Float; + if (sizeof(double) > remainingSpace()) + return make_error<StringError>( + "Invalid Float64 with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Float = BitsToDouble(endian::read<uint64_t, Endianness>(Current)); + Current += sizeof(double); + return true; + case FirstByte::Str8: + Obj.Kind = Type::String; + return readRaw<uint8_t>(Obj); + case FirstByte::Str16: + Obj.Kind = Type::String; + return readRaw<uint16_t>(Obj); + case FirstByte::Str32: + Obj.Kind = Type::String; + return readRaw<uint32_t>(Obj); + case FirstByte::Bin8: + Obj.Kind = Type::Binary; + return readRaw<uint8_t>(Obj); + case FirstByte::Bin16: + Obj.Kind = Type::Binary; + return readRaw<uint16_t>(Obj); + case FirstByte::Bin32: + Obj.Kind = Type::Binary; + return readRaw<uint32_t>(Obj); + case FirstByte::Array16: + Obj.Kind = Type::Array; + return readLength<uint16_t>(Obj); + case FirstByte::Array32: + Obj.Kind = Type::Array; + return readLength<uint32_t>(Obj); + case FirstByte::Map16: + Obj.Kind = Type::Map; + return readLength<uint16_t>(Obj); + case FirstByte::Map32: + Obj.Kind = Type::Map; + return readLength<uint32_t>(Obj); + case FirstByte::FixExt1: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext1); + case FirstByte::FixExt2: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext2); + case FirstByte::FixExt4: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext4); + case FirstByte::FixExt8: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext8); + case FirstByte::FixExt16: + Obj.Kind = Type::Extension; + return createExt(Obj, FixLen::Ext16); + case FirstByte::Ext8: + Obj.Kind = Type::Extension; + return readExt<uint8_t>(Obj); + case FirstByte::Ext16: + Obj.Kind = Type::Extension; + return readExt<uint16_t>(Obj); + case FirstByte::Ext32: + Obj.Kind = Type::Extension; + return readExt<uint32_t>(Obj); + } + + if ((FB & FixBitsMask::NegativeInt) == FixBits::NegativeInt) { + Obj.Kind = Type::Int; + int8_t I; + static_assert(sizeof(I) == sizeof(FB), "Unexpected type sizes"); + memcpy(&I, &FB, sizeof(FB)); + Obj.Int = I; + return true; + } + + if ((FB & FixBitsMask::PositiveInt) == FixBits::PositiveInt) { + Obj.Kind = Type::UInt; + Obj.UInt = FB; + return true; + } + + if ((FB & FixBitsMask::String) == FixBits::String) { + Obj.Kind = Type::String; + uint8_t Size = FB & ~FixBitsMask::String; + return createRaw(Obj, Size); + } + + if ((FB & FixBitsMask::Array) == FixBits::Array) { + Obj.Kind = Type::Array; + Obj.Length = FB & ~FixBitsMask::Array; + return true; + } + + if ((FB & FixBitsMask::Map) == FixBits::Map) { + Obj.Kind = Type::Map; + Obj.Length = FB & ~FixBitsMask::Map; + return true; + } + + return make_error<StringError>( + "Invalid first byte", std::make_error_code(std::errc::invalid_argument)); +} + +template <class T> Expected<bool> Reader::readRaw(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error<StringError>( + "Invalid Raw with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + T Size = endian::read<T, Endianness>(Current); + Current += sizeof(T); + return createRaw(Obj, Size); +} + +template <class T> Expected<bool> Reader::readInt(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error<StringError>( + "Invalid Int with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Int = static_cast<int64_t>(endian::read<T, Endianness>(Current)); + Current += sizeof(T); + return true; +} + +template <class T> Expected<bool> Reader::readUInt(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error<StringError>( + "Invalid Int with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.UInt = static_cast<uint64_t>(endian::read<T, Endianness>(Current)); + Current += sizeof(T); + return true; +} + +template <class T> Expected<bool> Reader::readLength(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error<StringError>( + "Invalid Map/Array with invalid length", + std::make_error_code(std::errc::invalid_argument)); + Obj.Length = static_cast<size_t>(endian::read<T, Endianness>(Current)); + Current += sizeof(T); + return true; +} + +template <class T> Expected<bool> Reader::readExt(Object &Obj) { + if (sizeof(T) > remainingSpace()) + return make_error<StringError>( + "Invalid Ext with invalid length", + std::make_error_code(std::errc::invalid_argument)); + T Size = endian::read<T, Endianness>(Current); + Current += sizeof(T); + return createExt(Obj, Size); +} + +Expected<bool> Reader::createRaw(Object &Obj, uint32_t Size) { + if (Size > remainingSpace()) + return make_error<StringError>( + "Invalid Raw with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Raw = StringRef(Current, Size); + Current += Size; + return true; +} + +Expected<bool> Reader::createExt(Object &Obj, uint32_t Size) { + if (Current == End) + return make_error<StringError>( + "Invalid Ext with no type", + std::make_error_code(std::errc::invalid_argument)); + Obj.Extension.Type = *Current++; + if (Size > remainingSpace()) + return make_error<StringError>( + "Invalid Ext with insufficient payload", + std::make_error_code(std::errc::invalid_argument)); + Obj.Extension.Bytes = StringRef(Current, Size); + Current += Size; + return true; +} diff --git a/lib/BinaryFormat/MsgPackTypes.cpp b/lib/BinaryFormat/MsgPackTypes.cpp new file mode 100644 index 000000000000..4a8f70b10fb8 --- /dev/null +++ b/lib/BinaryFormat/MsgPackTypes.cpp @@ -0,0 +1,303 @@ +//===- MsgPackTypes.cpp - MsgPack Types -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Implementation of types representing MessagePack "documents". +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/MsgPackTypes.h" +#include "llvm/Support/Error.h" + +using namespace llvm; +using namespace msgpack; + +namespace llvm { +namespace msgpack { +void ScalarNode::anchor() {} +void ArrayNode::anchor() {} +void MapNode::anchor() {} +} +} + +Expected<OptNodePtr> Node::readArray(Reader &MPReader, size_t Length) { + auto A = std::make_shared<ArrayNode>(); + for (size_t I = 0; I < Length; ++I) { + auto OptNodeOrErr = Node::read(MPReader); + if (auto Err = OptNodeOrErr.takeError()) + return std::move(Err); + if (!*OptNodeOrErr) + return make_error<StringError>( + "Insufficient array elements", + std::make_error_code(std::errc::invalid_argument)); + A->push_back(std::move(**OptNodeOrErr)); + } + return OptNodePtr(std::move(A)); +} + +Expected<OptNodePtr> Node::readMap(Reader &MPReader, size_t Length) { + auto M = std::make_shared<MapNode>(); + for (size_t I = 0; I < Length; ++I) { + auto OptKeyOrErr = Node::read(MPReader); + if (auto Err = OptKeyOrErr.takeError()) + return std::move(Err); + if (!*OptKeyOrErr) + return make_error<StringError>( + "Insufficient map elements", + std::make_error_code(std::errc::invalid_argument)); + auto OptValOrErr = Node::read(MPReader); + if (auto Err = OptValOrErr.takeError()) + return std::move(Err); + if (!*OptValOrErr) + return make_error<StringError>( + "Insufficient map elements", + std::make_error_code(std::errc::invalid_argument)); + auto *Key = dyn_cast<ScalarNode>((*OptKeyOrErr)->get()); + if (!Key) + return make_error<StringError>( + "Only string map keys are supported", + std::make_error_code(std::errc::invalid_argument)); + if (Key->getScalarKind() != ScalarNode::SK_String) + return make_error<StringError>( + "Only string map keys are supported", + std::make_error_code(std::errc::invalid_argument)); + M->try_emplace(Key->getString(), std::move(**OptValOrErr)); + } + return OptNodePtr(std::move(M)); +} + +Expected<OptNodePtr> Node::read(Reader &MPReader) { + Object Obj; + + auto ContinueOrErr = MPReader.read(Obj); + if (auto Err = ContinueOrErr.takeError()) + return std::move(Err); + if (!*ContinueOrErr) + return None; + + switch (Obj.Kind) { + case Type::Int: + return OptNodePtr(std::make_shared<ScalarNode>(Obj.Int)); + case Type::UInt: + return OptNodePtr(std::make_shared<ScalarNode>(Obj.UInt)); + case Type::Nil: + return OptNodePtr(std::make_shared<ScalarNode>()); + case Type::Boolean: + return OptNodePtr(std::make_shared<ScalarNode>(Obj.Bool)); + case Type::Float: + return OptNodePtr(std::make_shared<ScalarNode>(Obj.Float)); + case Type::String: + return OptNodePtr(std::make_shared<ScalarNode>(Obj.Raw)); + case Type::Binary: + return OptNodePtr(std::make_shared<ScalarNode>(Obj.Raw)); + case Type::Array: + return Node::readArray(MPReader, Obj.Length); + case Type::Map: + return Node::readMap(MPReader, Obj.Length); + case Type::Extension: + return make_error<StringError>( + "Extension types are not supported", + std::make_error_code(std::errc::invalid_argument)); + } + llvm_unreachable("msgpack::Type not handled"); +} + +void ScalarNode::destroy() { + switch (SKind) { + case SK_String: + case SK_Binary: + StringValue.~basic_string(); + break; + default: + // POD types do not require destruction + break; + } +} + +ScalarNode::ScalarNode(int64_t IntValue) + : Node(NK_Scalar), SKind(SK_Int), IntValue(IntValue) {} + +ScalarNode::ScalarNode(int32_t IntValue) + : ScalarNode(static_cast<int64_t>(IntValue)) {} + +ScalarNode::ScalarNode(uint64_t UIntValue) + : Node(NK_Scalar), SKind(SK_UInt), UIntValue(UIntValue) {} + +ScalarNode::ScalarNode(uint32_t IntValue) + : ScalarNode(static_cast<uint64_t>(IntValue)) {} + +ScalarNode::ScalarNode() : Node(NK_Scalar), SKind(SK_Nil) {} + +ScalarNode::ScalarNode(bool BoolValue) + : Node(NK_Scalar), SKind(SK_Boolean), BoolValue(BoolValue) {} + +ScalarNode::ScalarNode(double FloatValue) + : Node(NK_Scalar), SKind(SK_Float), BoolValue(FloatValue) {} + +ScalarNode::ScalarNode(StringRef StringValue) + : Node(NK_Scalar), SKind(SK_String) { + new (&this->StringValue) std::string(StringValue); +} + +ScalarNode::ScalarNode(const char *StringValue) + : ScalarNode(StringRef(StringValue)) {} + +ScalarNode::ScalarNode(std::string &&StringValue) + : Node(NK_Scalar), SKind(SK_String) { + new (&this->StringValue) std::string(StringValue); +} + +ScalarNode::ScalarNode(MemoryBufferRef BinaryValue) + : Node(NK_Scalar), SKind(SK_Binary) { + new (&StringValue) std::string(BinaryValue.getBuffer()); +} + +ScalarNode::~ScalarNode() { destroy(); } + +ScalarNode &ScalarNode::operator=(ScalarNode &&RHS) { + destroy(); + switch (SKind = RHS.SKind) { + case SK_Int: + IntValue = RHS.IntValue; + break; + case SK_UInt: + UIntValue = RHS.UIntValue; + break; + case SK_Boolean: + BoolValue = RHS.BoolValue; + break; + case SK_Float: + FloatValue = RHS.FloatValue; + break; + case SK_String: + case SK_Binary: + new (&StringValue) std::string(std::move(RHS.StringValue)); + break; + case SK_Nil: + // pass + break; + } + return *this; +} + +StringRef ScalarNode::inputYAML(StringRef ScalarStr) { + switch (SKind) { + case SK_Int: + return yaml::ScalarTraits<int64_t>::input(ScalarStr, nullptr, IntValue); + case SK_UInt: + return yaml::ScalarTraits<uint64_t>::input(ScalarStr, nullptr, UIntValue); + case SK_Nil: + return StringRef(); + case SK_Boolean: + return yaml::ScalarTraits<bool>::input(ScalarStr, nullptr, BoolValue); + case SK_Float: + return yaml::ScalarTraits<double>::input(ScalarStr, nullptr, FloatValue); + case SK_Binary: + case SK_String: + return yaml::ScalarTraits<std::string>::input(ScalarStr, nullptr, + StringValue); + } + llvm_unreachable("unrecognized ScalarKind"); +} + +void ScalarNode::outputYAML(raw_ostream &OS) const { + switch (SKind) { + case SK_Int: + yaml::ScalarTraits<int64_t>::output(IntValue, nullptr, OS); + break; + case SK_UInt: + yaml::ScalarTraits<uint64_t>::output(UIntValue, nullptr, OS); + break; + case SK_Nil: + yaml::ScalarTraits<StringRef>::output("", nullptr, OS); + break; + case SK_Boolean: + yaml::ScalarTraits<bool>::output(BoolValue, nullptr, OS); + break; + case SK_Float: + yaml::ScalarTraits<double>::output(FloatValue, nullptr, OS); + break; + case SK_Binary: + case SK_String: + yaml::ScalarTraits<std::string>::output(StringValue, nullptr, OS); + break; + } +} + +yaml::QuotingType ScalarNode::mustQuoteYAML(StringRef ScalarStr) const { + switch (SKind) { + case SK_Int: + return yaml::ScalarTraits<int64_t>::mustQuote(ScalarStr); + case SK_UInt: + return yaml::ScalarTraits<uint64_t>::mustQuote(ScalarStr); + case SK_Nil: + return yaml::ScalarTraits<StringRef>::mustQuote(ScalarStr); + case SK_Boolean: + return yaml::ScalarTraits<bool>::mustQuote(ScalarStr); + case SK_Float: + return yaml::ScalarTraits<double>::mustQuote(ScalarStr); + case SK_Binary: + case SK_String: + return yaml::ScalarTraits<std::string>::mustQuote(ScalarStr); + } + llvm_unreachable("unrecognized ScalarKind"); +} + +const char *ScalarNode::IntTag = "!int"; +const char *ScalarNode::NilTag = "!nil"; +const char *ScalarNode::BooleanTag = "!bool"; +const char *ScalarNode::FloatTag = "!float"; +const char *ScalarNode::StringTag = "!str"; +const char *ScalarNode::BinaryTag = "!bin"; + +StringRef ScalarNode::getYAMLTag() const { + switch (SKind) { + case SK_Int: + return IntTag; + case SK_UInt: + return IntTag; + case SK_Nil: + return NilTag; + case SK_Boolean: + return BooleanTag; + case SK_Float: + return FloatTag; + case SK_String: + return StringTag; + case SK_Binary: + return BinaryTag; + } + llvm_unreachable("unrecognized ScalarKind"); +} + +void ScalarNode::write(Writer &MPWriter) { + switch (SKind) { + case SK_Int: + MPWriter.write(IntValue); + break; + case SK_UInt: + MPWriter.write(UIntValue); + break; + case SK_Nil: + MPWriter.writeNil(); + break; + case SK_Boolean: + MPWriter.write(BoolValue); + break; + case SK_Float: + MPWriter.write(FloatValue); + break; + case SK_String: + MPWriter.write(StringValue); + break; + case SK_Binary: + MPWriter.write(MemoryBufferRef(StringValue, "")); + break; + } +} diff --git a/lib/BinaryFormat/MsgPackWriter.cpp b/lib/BinaryFormat/MsgPackWriter.cpp new file mode 100644 index 000000000000..d024bb0fcdb2 --- /dev/null +++ b/lib/BinaryFormat/MsgPackWriter.cpp @@ -0,0 +1,209 @@ +//===- MsgPackWriter.cpp - Simple MsgPack writer ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements a MessagePack writer. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/MsgPackWriter.h" +#include "llvm/BinaryFormat/MsgPack.h" + +using namespace llvm; +using namespace msgpack; + +Writer::Writer(raw_ostream &OS, bool Compatible) + : EW(OS, Endianness), Compatible(Compatible) {} + +void Writer::writeNil() { EW.write(FirstByte::Nil); } + +void Writer::write(bool b) { EW.write(b ? FirstByte::True : FirstByte::False); } + +void Writer::write(int64_t i) { + if (i >= 0) { + write(static_cast<uint64_t>(i)); + return; + } + + if (i >= FixMin::NegativeInt) { + EW.write(static_cast<int8_t>(i)); + return; + } + + if (i >= INT8_MIN) { + EW.write(FirstByte::Int8); + EW.write(static_cast<int8_t>(i)); + return; + } + + if (i >= INT16_MIN) { + EW.write(FirstByte::Int16); + EW.write(static_cast<int16_t>(i)); + return; + } + + if (i >= INT32_MIN) { + EW.write(FirstByte::Int32); + EW.write(static_cast<int32_t>(i)); + return; + } + + EW.write(FirstByte::Int64); + EW.write(i); +} + +void Writer::write(uint64_t u) { + if (u <= FixMax::PositiveInt) { + EW.write(static_cast<uint8_t>(u)); + return; + } + + if (u <= UINT8_MAX) { + EW.write(FirstByte::UInt8); + EW.write(static_cast<uint8_t>(u)); + return; + } + + if (u <= UINT16_MAX) { + EW.write(FirstByte::UInt16); + EW.write(static_cast<uint16_t>(u)); + return; + } + + if (u <= UINT32_MAX) { + EW.write(FirstByte::UInt32); + EW.write(static_cast<uint32_t>(u)); + return; + } + + EW.write(FirstByte::UInt64); + EW.write(u); +} + +void Writer::write(double d) { + // If no loss of precision, encode as a Float32. + double a = std::fabs(d); + if (a >= std::numeric_limits<float>::min() && + a <= std::numeric_limits<float>::max()) { + EW.write(FirstByte::Float32); + EW.write(static_cast<float>(d)); + } else { + EW.write(FirstByte::Float64); + EW.write(d); + } +} + +void Writer::write(StringRef s) { + size_t Size = s.size(); + + if (Size <= FixMax::String) + EW.write(static_cast<uint8_t>(FixBits::String | Size)); + else if (!Compatible && Size <= UINT8_MAX) { + EW.write(FirstByte::Str8); + EW.write(static_cast<uint8_t>(Size)); + } else if (Size <= UINT16_MAX) { + EW.write(FirstByte::Str16); + EW.write(static_cast<uint16_t>(Size)); + } else { + assert(Size <= UINT32_MAX && "String object too long to be encoded"); + EW.write(FirstByte::Str32); + EW.write(static_cast<uint32_t>(Size)); + } + + EW.OS << s; +} + +void Writer::write(MemoryBufferRef Buffer) { + assert(!Compatible && "Attempt to write Bin format in compatible mode"); + + size_t Size = Buffer.getBufferSize(); + + if (Size <= UINT8_MAX) { + EW.write(FirstByte::Bin8); + EW.write(static_cast<uint8_t>(Size)); + } else if (Size <= UINT16_MAX) { + EW.write(FirstByte::Bin16); + EW.write(static_cast<uint16_t>(Size)); + } else { + assert(Size <= UINT32_MAX && "Binary object too long to be encoded"); + EW.write(FirstByte::Bin32); + EW.write(static_cast<uint32_t>(Size)); + } + + EW.OS.write(Buffer.getBufferStart(), Size); +} + +void Writer::writeArraySize(uint32_t Size) { + if (Size <= FixMax::Array) { + EW.write(static_cast<uint8_t>(FixBits::Array | Size)); + return; + } + + if (Size <= UINT16_MAX) { + EW.write(FirstByte::Array16); + EW.write(static_cast<uint16_t>(Size)); + return; + } + + EW.write(FirstByte::Array32); + EW.write(Size); +} + +void Writer::writeMapSize(uint32_t Size) { + if (Size <= FixMax::Map) { + EW.write(static_cast<uint8_t>(FixBits::Map | Size)); + return; + } + + if (Size <= UINT16_MAX) { + EW.write(FirstByte::Map16); + EW.write(static_cast<uint16_t>(Size)); + return; + } + + EW.write(FirstByte::Map32); + EW.write(Size); +} + +void Writer::writeExt(int8_t Type, MemoryBufferRef Buffer) { + size_t Size = Buffer.getBufferSize(); + + switch (Size) { + case FixLen::Ext1: + EW.write(FirstByte::FixExt1); + break; + case FixLen::Ext2: + EW.write(FirstByte::FixExt2); + break; + case FixLen::Ext4: + EW.write(FirstByte::FixExt4); + break; + case FixLen::Ext8: + EW.write(FirstByte::FixExt8); + break; + case FixLen::Ext16: + EW.write(FirstByte::FixExt16); + break; + default: + if (Size <= UINT8_MAX) { + EW.write(FirstByte::Ext8); + EW.write(static_cast<uint8_t>(Size)); + } else if (Size <= UINT16_MAX) { + EW.write(FirstByte::Ext16); + EW.write(static_cast<uint16_t>(Size)); + } else { + assert(Size <= UINT32_MAX && "Ext size too large to be encoded"); + EW.write(FirstByte::Ext32); + EW.write(static_cast<uint32_t>(Size)); + } + } + + EW.write(Type); + EW.OS.write(Buffer.getBufferStart(), Size); +} diff --git a/lib/BinaryFormat/Wasm.cpp b/lib/BinaryFormat/Wasm.cpp index 35360d0ae4f0..94d40bf02a39 100644 --- a/lib/BinaryFormat/Wasm.cpp +++ b/lib/BinaryFormat/Wasm.cpp @@ -19,13 +19,17 @@ std::string llvm::wasm::toString(wasm::WasmSymbolType type) { return "WASM_SYMBOL_TYPE_DATA"; case wasm::WASM_SYMBOL_TYPE_SECTION: return "WASM_SYMBOL_TYPE_SECTION"; + case wasm::WASM_SYMBOL_TYPE_EVENT: + return "WASM_SYMBOL_TYPE_EVENT"; } llvm_unreachable("unknown symbol type"); } std::string llvm::wasm::relocTypetoString(uint32_t type) { switch (type) { -#define WASM_RELOC(NAME, VALUE) case VALUE: return #NAME; +#define WASM_RELOC(NAME, VALUE) \ + case VALUE: \ + return #NAME; #include "llvm/BinaryFormat/WasmRelocs.def" #undef WASM_RELOC default: |