summaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/lib/DebugInfo/DWARF/DWARFExpression.cpp
diff options
context:
space:
mode:
authorvitalyisaev <[email protected]>2023-06-29 10:00:50 +0300
committervitalyisaev <[email protected]>2023-06-29 10:00:50 +0300
commit6ffe9e53658409f212834330e13564e4952558f6 (patch)
tree85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/llvm16/lib/DebugInfo/DWARF/DWARFExpression.cpp
parent726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff)
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/llvm16/lib/DebugInfo/DWARF/DWARFExpression.cpp')
-rw-r--r--contrib/libs/llvm16/lib/DebugInfo/DWARF/DWARFExpression.cpp512
1 files changed, 512 insertions, 0 deletions
diff --git a/contrib/libs/llvm16/lib/DebugInfo/DWARF/DWARFExpression.cpp b/contrib/libs/llvm16/lib/DebugInfo/DWARF/DWARFExpression.cpp
new file mode 100644
index 00000000000..523dee486d2
--- /dev/null
+++ b/contrib/libs/llvm16/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -0,0 +1,512 @@
+//===-- DWARFExpression.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/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Format.h"
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+namespace llvm {
+
+typedef std::vector<DWARFExpression::Operation::Description> DescVector;
+
+static DescVector getDescriptions() {
+ DescVector Descriptions;
+ typedef DWARFExpression::Operation Op;
+ typedef Op::Description Desc;
+
+ Descriptions.resize(0xff);
+ Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr);
+ Descriptions[DW_OP_deref] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1);
+ Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2);
+ Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4);
+ Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4);
+ Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8);
+ Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8);
+ Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_dup] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_drop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_over] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_swap] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_rot] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_abs] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_and] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_div] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_minus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mod] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mul] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_neg] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_not] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_or] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_shl] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shr] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shra] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xor] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_eq] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ge] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_gt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_le] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_lt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ne] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB);
+ Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_nop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2);
+ Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4);
+ Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr);
+ Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB);
+ Descriptions[DW_OP_implicit_value] =
+ Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
+ Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_WASM_location] =
+ Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg);
+ Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
+
+ Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
+ Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
+ Descriptions[DW_OP_regval_type] =
+ Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef);
+
+ return Descriptions;
+}
+
+static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) {
+ // FIXME: Make this constexpr once all compilers are smart enough to do it.
+ static DescVector Descriptions = getDescriptions();
+ // Handle possible corrupted or unsupported operation.
+ if (OpCode >= Descriptions.size())
+ return {};
+ return Descriptions[OpCode];
+}
+
+bool DWARFExpression::Operation::extract(DataExtractor Data,
+ uint8_t AddressSize, uint64_t Offset,
+ std::optional<DwarfFormat> Format) {
+ EndOffset = Offset;
+ Opcode = Data.getU8(&Offset);
+
+ Desc = getOpDesc(Opcode);
+ if (Desc.Version == Operation::DwarfNA)
+ return false;
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ switch (Size & ~Operation::SignBit) {
+ case Operation::Size1:
+ Operands[Operand] = Data.getU8(&Offset);
+ if (Signed)
+ Operands[Operand] = (int8_t)Operands[Operand];
+ break;
+ case Operation::Size2:
+ Operands[Operand] = Data.getU16(&Offset);
+ if (Signed)
+ Operands[Operand] = (int16_t)Operands[Operand];
+ break;
+ case Operation::Size4:
+ Operands[Operand] = Data.getU32(&Offset);
+ if (Signed)
+ Operands[Operand] = (int32_t)Operands[Operand];
+ break;
+ case Operation::Size8:
+ Operands[Operand] = Data.getU64(&Offset);
+ break;
+ case Operation::SizeAddr:
+ Operands[Operand] = Data.getUnsigned(&Offset, AddressSize);
+ break;
+ case Operation::SizeRefAddr:
+ if (!Format)
+ return false;
+ Operands[Operand] =
+ Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format));
+ break;
+ case Operation::SizeLEB:
+ if (Signed)
+ Operands[Operand] = Data.getSLEB128(&Offset);
+ else
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case Operation::BaseTypeRef:
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case Operation::WasmLocationArg:
+ assert(Operand == 1);
+ switch (Operands[0]) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case 3: // global as uint32
+ Operands[Operand] = Data.getU32(&Offset);
+ break;
+ default:
+ return false; // Unknown Wasm location
+ }
+ break;
+ case Operation::SizeBlock:
+ // We need a size, so this cannot be the first operand
+ if (Operand == 0)
+ return false;
+ // Store the offset of the block as the value.
+ Operands[Operand] = Offset;
+ Offset += Operands[Operand - 1];
+ break;
+ default:
+ llvm_unreachable("Unknown DWARFExpression Op size");
+ }
+
+ OperandEndOffsets[Operand] = Offset;
+ }
+
+ EndOffset = Offset;
+ return true;
+}
+
+static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS,
+ DIDumpOptions DumpOpts,
+ const uint64_t Operands[2],
+ unsigned Operand) {
+ assert(Operand < 2 && "operand out of bounds");
+ auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
+ if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
+ OS << " (";
+ if (DumpOpts.Verbose)
+ OS << format("0x%08" PRIx64 " -> ", Operands[Operand]);
+ OS << format("0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);
+ if (auto Name = dwarf::toString(Die.find(dwarf::DW_AT_name)))
+ OS << " \"" << *Name << "\"";
+ } else {
+ OS << format(" <invalid base_type ref: 0x%" PRIx64 ">",
+ Operands[Operand]);
+ }
+}
+
+bool DWARFExpression::prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
+ DIDumpOptions DumpOpts,
+ uint8_t Opcode,
+ const uint64_t Operands[2]) {
+ if (!DumpOpts.GetNameForDWARFReg)
+ return false;
+
+ uint64_t DwarfRegNum;
+ unsigned OpNum = 0;
+
+ if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
+ Opcode == DW_OP_regval_type)
+ DwarfRegNum = Operands[OpNum++];
+ else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
+ DwarfRegNum = Opcode - DW_OP_breg0;
+ else
+ DwarfRegNum = Opcode - DW_OP_reg0;
+
+ auto RegName = DumpOpts.GetNameForDWARFReg(DwarfRegNum, DumpOpts.IsEH);
+ if (!RegName.empty()) {
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ Opcode == DW_OP_bregx)
+ OS << ' ' << RegName << format("%+" PRId64, Operands[OpNum]);
+ else
+ OS << ' ' << RegName.data();
+
+ if (Opcode == DW_OP_regval_type)
+ prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, 1);
+ return true;
+ }
+
+ return false;
+}
+
+bool DWARFExpression::Operation::print(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const DWARFExpression *Expr,
+ DWARFUnit *U) const {
+ if (Error) {
+ OS << "<decoding error>";
+ return false;
+ }
+
+ StringRef Name = OperationEncodingString(Opcode);
+ assert(!Name.empty() && "DW_OP has no name!");
+ OS << Name;
+
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) ||
+ Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
+ Opcode == DW_OP_regval_type)
+ if (prettyPrintRegisterOp(U, OS, DumpOpts, Opcode, Operands))
+ return true;
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ if (Size == Operation::BaseTypeRef && U) {
+ // For DW_OP_convert the operand may be 0 to indicate that conversion to
+ // the generic type should be done. The same holds for DW_OP_reinterpret,
+ // which is currently not supported.
+ if (Opcode == DW_OP_convert && Operands[Operand] == 0)
+ OS << " 0x0";
+ else
+ prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, Operand);
+ } else if (Size == Operation::WasmLocationArg) {
+ assert(Operand == 1);
+ switch (Operands[0]) {
+ case 0:
+ case 1:
+ case 2:
+ case 3: // global as uint32
+ case 4:
+ OS << format(" 0x%" PRIx64, Operands[Operand]);
+ break;
+ default: assert(false);
+ }
+ } else if (Size == Operation::SizeBlock) {
+ uint64_t Offset = Operands[Operand];
+ for (unsigned i = 0; i < Operands[Operand - 1]; ++i)
+ OS << format(" 0x%02x", Expr->Data.getU8(&Offset));
+ } else {
+ if (Signed)
+ OS << format(" %+" PRId64, (int64_t)Operands[Operand]);
+ else if (Opcode != DW_OP_entry_value &&
+ Opcode != DW_OP_GNU_entry_value)
+ OS << format(" 0x%" PRIx64, Operands[Operand]);
+ }
+ }
+ return true;
+}
+
+void DWARFExpression::print(raw_ostream &OS, DIDumpOptions DumpOpts,
+ DWARFUnit *U, bool IsEH) const {
+ uint32_t EntryValExprSize = 0;
+ uint64_t EntryValStartOffset = 0;
+ if (Data.getData().empty())
+ OS << "<empty>";
+
+ for (auto &Op : *this) {
+ DumpOpts.IsEH = IsEH;
+ if (!Op.print(OS, DumpOpts, this, U)) {
+ uint64_t FailOffset = Op.getEndOffset();
+ while (FailOffset < Data.getData().size())
+ OS << format(" %02x", Data.getU8(&FailOffset));
+ return;
+ }
+
+ if (Op.getCode() == DW_OP_entry_value ||
+ Op.getCode() == DW_OP_GNU_entry_value) {
+ OS << "(";
+ EntryValExprSize = Op.getRawOperand(0);
+ EntryValStartOffset = Op.getEndOffset();
+ continue;
+ }
+
+ if (EntryValExprSize) {
+ EntryValExprSize -= Op.getEndOffset() - EntryValStartOffset;
+ if (EntryValExprSize == 0)
+ OS << ")";
+ }
+
+ if (Op.getEndOffset() < Data.getData().size())
+ OS << ", ";
+ }
+}
+
+bool DWARFExpression::Operation::verify(const Operation &Op, DWARFUnit *U) {
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Op.Desc.Op[Operand];
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ if (Size == Operation::BaseTypeRef) {
+ // For DW_OP_convert the operand may be 0 to indicate that conversion to
+ // the generic type should be done, so don't look up a base type in that
+ // case. The same holds for DW_OP_reinterpret, which is currently not
+ // supported.
+ if (Op.Opcode == DW_OP_convert && Op.Operands[Operand] == 0)
+ continue;
+ auto Die = U->getDIEForOffset(U->getOffset() + Op.Operands[Operand]);
+ if (!Die || Die.getTag() != dwarf::DW_TAG_base_type)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool DWARFExpression::verify(DWARFUnit *U) {
+ for (auto &Op : *this)
+ if (!Operation::verify(Op, U))
+ return false;
+
+ return true;
+}
+
+/// A user-facing string representation of a DWARF expression. This might be an
+/// Address expression, in which case it will be implicitly dereferenced, or a
+/// Value expression.
+struct PrintedExpr {
+ enum ExprKind {
+ Address,
+ Value,
+ };
+ ExprKind Kind;
+ SmallString<16> String;
+
+ PrintedExpr(ExprKind K = Address) : Kind(K) {}
+};
+
+static bool printCompactDWARFExpr(
+ raw_ostream &OS, DWARFExpression::iterator I,
+ const DWARFExpression::iterator E,
+ std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg =
+ nullptr) {
+ SmallVector<PrintedExpr, 4> Stack;
+
+ while (I != E) {
+ const DWARFExpression::Operation &Op = *I;
+ uint8_t Opcode = Op.getCode();
+ switch (Opcode) {
+ case dwarf::DW_OP_regx: {
+ // DW_OP_regx: A register, with the register num given as an operand.
+ // Printed as the plain register name.
+ uint64_t DwarfRegNum = Op.getRawOperand(0);
+ auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
+ if (RegName.empty())
+ return false;
+ raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+ S << RegName;
+ break;
+ }
+ case dwarf::DW_OP_bregx: {
+ int DwarfRegNum = Op.getRawOperand(0);
+ int64_t Offset = Op.getRawOperand(1);
+ auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
+ if (RegName.empty())
+ return false;
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << RegName;
+ if (Offset)
+ S << format("%+" PRId64, Offset);
+ break;
+ }
+ case dwarf::DW_OP_entry_value:
+ case dwarf::DW_OP_GNU_entry_value: {
+ // DW_OP_entry_value contains a sub-expression which must be rendered
+ // separately.
+ uint64_t SubExprLength = Op.getRawOperand(0);
+ DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength);
+ ++I;
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << "entry(";
+ printCompactDWARFExpr(S, I, SubExprEnd, GetNameForDWARFReg);
+ S << ")";
+ I = SubExprEnd;
+ continue;
+ }
+ case dwarf::DW_OP_stack_value: {
+ // The top stack entry should be treated as the actual value of tne
+ // variable, rather than the address of the variable in memory.
+ assert(!Stack.empty());
+ Stack.back().Kind = PrintedExpr::Value;
+ break;
+ }
+ default:
+ if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {
+ // DW_OP_reg<N>: A register, with the register num implied by the
+ // opcode. Printed as the plain register name.
+ uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;
+ auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
+ if (RegName.empty())
+ return false;
+ raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+ S << RegName;
+ } else if (Opcode >= dwarf::DW_OP_breg0 &&
+ Opcode <= dwarf::DW_OP_breg31) {
+ int DwarfRegNum = Opcode - dwarf::DW_OP_breg0;
+ int64_t Offset = Op.getRawOperand(0);
+ auto RegName = GetNameForDWARFReg(DwarfRegNum, false);
+ if (RegName.empty())
+ return false;
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << RegName;
+ if (Offset)
+ S << format("%+" PRId64, Offset);
+ } else {
+ // If we hit an unknown operand, we don't know its effect on the stack,
+ // so bail out on the whole expression.
+ OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " ("
+ << (int)Opcode << ")>";
+ return false;
+ }
+ break;
+ }
+ ++I;
+ }
+
+ assert(Stack.size() == 1 && "expected one value on stack");
+
+ if (Stack.front().Kind == PrintedExpr::Address)
+ OS << "[" << Stack.front().String << "]";
+ else
+ OS << Stack.front().String;
+
+ return true;
+}
+
+bool DWARFExpression::printCompact(
+ raw_ostream &OS,
+ std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
+ return printCompactDWARFExpr(OS, begin(), end(), GetNameForDWARFReg);
+}
+
+bool DWARFExpression::operator==(const DWARFExpression &RHS) const {
+ if (AddressSize != RHS.AddressSize || Format != RHS.Format)
+ return false;
+ return Data.getData() == RHS.Data.getData();
+}
+
+} // namespace llvm