|  | //===-- Scalar.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 "lldb/Utility/Scalar.h" | 
|  | #include "lldb/Utility/DataBufferHeap.h" | 
|  | #include "lldb/Utility/DataExtractor.h" | 
|  | #include "lldb/Utility/Endian.h" | 
|  | #include "lldb/Utility/Status.h" | 
|  | #include "lldb/Utility/Stream.h" | 
|  | #include "lldb/Utility/StreamString.h" | 
|  | #include "lldb/lldb-types.h" | 
|  | #include "llvm/ADT/APSInt.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  |  | 
|  | #include <cinttypes> | 
|  | #include <cstdio> | 
|  |  | 
|  | using namespace lldb; | 
|  | using namespace lldb_private; | 
|  |  | 
|  | using llvm::APFloat; | 
|  | using llvm::APInt; | 
|  | using llvm::APSInt; | 
|  |  | 
|  | Scalar::PromotionKey Scalar::GetPromoKey() const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | return PromotionKey{e_void, 0, false}; | 
|  | case e_int: | 
|  | return PromotionKey{e_int, m_integer.getBitWidth(), m_integer.isUnsigned()}; | 
|  | case e_float: | 
|  | return GetFloatPromoKey(m_float.getSemantics()); | 
|  | } | 
|  | llvm_unreachable("Unhandled category!"); | 
|  | } | 
|  |  | 
|  | Scalar::PromotionKey Scalar::GetFloatPromoKey(const llvm::fltSemantics &sem) { | 
|  | static const llvm::fltSemantics *const order[] = { | 
|  | &APFloat::IEEEsingle(), &APFloat::IEEEdouble(), | 
|  | &APFloat::x87DoubleExtended()}; | 
|  | for (const auto &entry : llvm::enumerate(order)) { | 
|  | if (entry.value() == &sem) | 
|  | return PromotionKey{e_float, entry.index(), false}; | 
|  | } | 
|  | llvm_unreachable("Unsupported semantics!"); | 
|  | } | 
|  |  | 
|  | // Promote to max type currently follows the ANSI C rule for type promotion in | 
|  | // expressions. | 
|  | Scalar::Type Scalar::PromoteToMaxType(Scalar &lhs, Scalar &rhs) { | 
|  | const auto &Promote = [](Scalar &a, const Scalar &b) { | 
|  | switch (b.GetType()) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | a.IntegralPromote(b.m_integer.getBitWidth(), b.m_integer.isSigned()); | 
|  | break; | 
|  | case e_float: | 
|  | a.FloatPromote(b.m_float.getSemantics()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | PromotionKey lhs_key = lhs.GetPromoKey(); | 
|  | PromotionKey rhs_key = rhs.GetPromoKey(); | 
|  |  | 
|  | if (lhs_key > rhs_key) | 
|  | Promote(rhs, lhs); | 
|  | else if (rhs_key > lhs_key) | 
|  | Promote(lhs, rhs); | 
|  |  | 
|  | // Make sure our type promotion worked as expected | 
|  | if (lhs.GetPromoKey() == rhs.GetPromoKey()) | 
|  | return lhs.GetType(); // Return the resulting type | 
|  |  | 
|  | // Return the void type (zero) if we fail to promote either of the values. | 
|  | return Scalar::e_void; | 
|  | } | 
|  |  | 
|  | bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const { | 
|  | size_t byte_size = GetByteSize(); | 
|  | if (byte_size == 0) { | 
|  | data.Clear(); | 
|  | return false; | 
|  | } | 
|  | auto buffer_up = std::make_unique<DataBufferHeap>(byte_size, 0); | 
|  | GetBytes(buffer_up->GetData()); | 
|  | lldb::offset_t offset = 0; | 
|  |  | 
|  | if (limit_byte_size < byte_size) { | 
|  | if (endian::InlHostByteOrder() == eByteOrderLittle) { | 
|  | // On little endian systems if we want fewer bytes from the current | 
|  | // type we just specify fewer bytes since the LSByte is first... | 
|  | byte_size = limit_byte_size; | 
|  | } else if (endian::InlHostByteOrder() == eByteOrderBig) { | 
|  | // On big endian systems if we want fewer bytes from the current type | 
|  | // have to advance our initial byte pointer and trim down the number of | 
|  | // bytes since the MSByte is first | 
|  | offset = byte_size - limit_byte_size; | 
|  | byte_size = limit_byte_size; | 
|  | } | 
|  | } | 
|  |  | 
|  | data.SetData(std::move(buffer_up), offset, byte_size); | 
|  | data.SetByteOrder(endian::InlHostByteOrder()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void Scalar::GetBytes(llvm::MutableArrayRef<uint8_t> storage) const { | 
|  | assert(storage.size() >= GetByteSize()); | 
|  |  | 
|  | const auto &store = [&](const llvm::APInt &val) { | 
|  | StoreIntToMemory(val, storage.data(), (val.getBitWidth() + 7) / 8); | 
|  | }; | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | store(m_integer); | 
|  | break; | 
|  | case e_float: | 
|  | store(m_float.bitcastToAPInt()); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | size_t Scalar::GetByteSize() const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | return (m_integer.getBitWidth() + 7) / 8; | 
|  | case e_float: | 
|  | return (m_float.bitcastToAPInt().getBitWidth() + 7) / 8; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | bool Scalar::IsZero() const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | return m_integer.isZero(); | 
|  | case e_float: | 
|  | return m_float.isZero(); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void Scalar::GetValue(Stream &s, bool show_type) const { | 
|  | if (show_type) | 
|  | s.Printf("(%s) ", GetTypeAsCString()); | 
|  |  | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | s.PutCString(llvm::toString(m_integer, 10)); | 
|  | break; | 
|  | case e_float: | 
|  | llvm::SmallString<24> string; | 
|  | m_float.toString(string); | 
|  | s.PutCString(string); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void Scalar::TruncOrExtendTo(uint16_t bits, bool sign) { | 
|  | m_integer.setIsSigned(sign); | 
|  | m_integer = m_integer.extOrTrunc(bits); | 
|  | } | 
|  |  | 
|  | bool Scalar::IntegralPromote(uint16_t bits, bool sign) { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | case e_float: | 
|  | break; | 
|  | case e_int: | 
|  | if (GetPromoKey() > PromotionKey(e_int, bits, !sign)) | 
|  | break; | 
|  | m_integer = m_integer.extOrTrunc(bits); | 
|  | m_integer.setIsSigned(sign); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Scalar::FloatPromote(const llvm::fltSemantics &semantics) { | 
|  | bool success = false; | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | m_float = llvm::APFloat(semantics); | 
|  | m_float.convertFromAPInt(m_integer, m_integer.isSigned(), | 
|  | llvm::APFloat::rmNearestTiesToEven); | 
|  | success = true; | 
|  | break; | 
|  | case e_float: | 
|  | if (GetFloatPromoKey(semantics) < GetFloatPromoKey(m_float.getSemantics())) | 
|  | break; | 
|  | bool ignore; | 
|  | success = true; | 
|  | m_float.convert(semantics, llvm::APFloat::rmNearestTiesToEven, &ignore); | 
|  | } | 
|  |  | 
|  | if (success) | 
|  | m_type = e_float; | 
|  | return success; | 
|  | } | 
|  |  | 
|  | const char *Scalar::GetValueTypeAsCString(Scalar::Type type) { | 
|  | switch (type) { | 
|  | case e_void: | 
|  | return "void"; | 
|  | case e_int: | 
|  | return "int"; | 
|  | case e_float: | 
|  | return "float"; | 
|  | } | 
|  | return "???"; | 
|  | } | 
|  |  | 
|  | bool Scalar::IsSigned() const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | return false; | 
|  | case e_int: | 
|  | return m_integer.isSigned(); | 
|  | case e_float: | 
|  | return true; | 
|  | } | 
|  | llvm_unreachable("Unrecognized type!"); | 
|  | } | 
|  |  | 
|  | bool Scalar::MakeSigned() { | 
|  | bool success = false; | 
|  |  | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | m_integer.setIsSigned(true); | 
|  | success = true; | 
|  | break; | 
|  | case e_float: | 
|  | success = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | return success; | 
|  | } | 
|  |  | 
|  | bool Scalar::MakeUnsigned() { | 
|  | bool success = false; | 
|  |  | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | m_integer.setIsUnsigned(true); | 
|  | success = true; | 
|  | break; | 
|  | case e_float: | 
|  | success = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | return success; | 
|  | } | 
|  |  | 
|  | static llvm::APInt ToAPInt(const llvm::APFloat &f, unsigned bits, | 
|  | bool is_unsigned) { | 
|  | llvm::APSInt result(bits, is_unsigned); | 
|  | bool isExact; | 
|  | f.convertToInteger(result, llvm::APFloat::rmTowardZero, &isExact); | 
|  | return std::move(result); | 
|  | } | 
|  |  | 
|  | template <typename T> T Scalar::GetAs(T fail_value) const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: { | 
|  | APSInt ext = m_integer.extOrTrunc(sizeof(T) * 8); | 
|  | if (ext.isSigned()) | 
|  | return ext.getSExtValue(); | 
|  | return ext.getZExtValue(); | 
|  | } | 
|  | case e_float: | 
|  | return ToAPInt(m_float, sizeof(T) * 8, std::is_unsigned<T>::value) | 
|  | .getSExtValue(); | 
|  | } | 
|  | return fail_value; | 
|  | } | 
|  |  | 
|  | signed char Scalar::SChar(signed char fail_value) const { | 
|  | return GetAs<signed char>(fail_value); | 
|  | } | 
|  |  | 
|  | unsigned char Scalar::UChar(unsigned char fail_value) const { | 
|  | return GetAs<unsigned char>(fail_value); | 
|  | } | 
|  |  | 
|  | short Scalar::SShort(short fail_value) const { | 
|  | return GetAs<short>(fail_value); | 
|  | } | 
|  |  | 
|  | unsigned short Scalar::UShort(unsigned short fail_value) const { | 
|  | return GetAs<unsigned short>(fail_value); | 
|  | } | 
|  |  | 
|  | int Scalar::SInt(int fail_value) const { return GetAs<int>(fail_value); } | 
|  |  | 
|  | unsigned int Scalar::UInt(unsigned int fail_value) const { | 
|  | return GetAs<unsigned int>(fail_value); | 
|  | } | 
|  |  | 
|  | long Scalar::SLong(long fail_value) const { return GetAs<long>(fail_value); } | 
|  |  | 
|  | unsigned long Scalar::ULong(unsigned long fail_value) const { | 
|  | return GetAs<unsigned long>(fail_value); | 
|  | } | 
|  |  | 
|  | long long Scalar::SLongLong(long long fail_value) const { | 
|  | return GetAs<long long>(fail_value); | 
|  | } | 
|  |  | 
|  | unsigned long long Scalar::ULongLong(unsigned long long fail_value) const { | 
|  | return GetAs<unsigned long long>(fail_value); | 
|  | } | 
|  |  | 
|  | llvm::APInt Scalar::SInt128(const llvm::APInt &fail_value) const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | return m_integer; | 
|  | case e_float: | 
|  | return ToAPInt(m_float, 128, /*is_unsigned=*/false); | 
|  | } | 
|  | return fail_value; | 
|  | } | 
|  |  | 
|  | llvm::APInt Scalar::UInt128(const llvm::APInt &fail_value) const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | return m_integer; | 
|  | case e_float: | 
|  | return ToAPInt(m_float, 128, /*is_unsigned=*/true); | 
|  | } | 
|  | return fail_value; | 
|  | } | 
|  |  | 
|  | float Scalar::Float(float fail_value) const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | if (m_integer.isSigned()) | 
|  | return llvm::APIntOps::RoundSignedAPIntToFloat(m_integer); | 
|  | return llvm::APIntOps::RoundAPIntToFloat(m_integer); | 
|  |  | 
|  | case e_float: { | 
|  | APFloat result = m_float; | 
|  | bool losesInfo; | 
|  | result.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, | 
|  | &losesInfo); | 
|  | return result.convertToFloat(); | 
|  | } | 
|  | } | 
|  | return fail_value; | 
|  | } | 
|  |  | 
|  | double Scalar::Double(double fail_value) const { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | if (m_integer.isSigned()) | 
|  | return llvm::APIntOps::RoundSignedAPIntToDouble(m_integer); | 
|  | return llvm::APIntOps::RoundAPIntToDouble(m_integer); | 
|  |  | 
|  | case e_float: { | 
|  | APFloat result = m_float; | 
|  | bool losesInfo; | 
|  | result.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, | 
|  | &losesInfo); | 
|  | return result.convertToDouble(); | 
|  | } | 
|  | } | 
|  | return fail_value; | 
|  | } | 
|  |  | 
|  | long double Scalar::LongDouble(long double fail_value) const { | 
|  | /// No way to get more precision at the moment. | 
|  | return static_cast<long double>(Double(fail_value)); | 
|  | } | 
|  |  | 
|  | Scalar &Scalar::operator+=(Scalar rhs) { | 
|  | Scalar copy = *this; | 
|  | if ((m_type = PromoteToMaxType(copy, rhs)) != Scalar::e_void) { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | m_integer = copy.m_integer + rhs.m_integer; | 
|  | break; | 
|  |  | 
|  | case e_float: | 
|  | m_float = copy.m_float + rhs.m_float; | 
|  | break; | 
|  | } | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | Scalar &Scalar::operator<<=(const Scalar &rhs) { | 
|  | if (m_type == e_int && rhs.m_type == e_int) | 
|  | static_cast<APInt &>(m_integer) <<= rhs.m_integer; | 
|  | else | 
|  | m_type = e_void; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | bool Scalar::ShiftRightLogical(const Scalar &rhs) { | 
|  | if (m_type == e_int && rhs.m_type == e_int) { | 
|  | m_integer = m_integer.lshr(rhs.m_integer); | 
|  | return true; | 
|  | } | 
|  | m_type = e_void; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Scalar &Scalar::operator>>=(const Scalar &rhs) { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | case e_float: | 
|  | m_type = e_void; | 
|  | break; | 
|  |  | 
|  | case e_int: | 
|  | switch (rhs.m_type) { | 
|  | case e_void: | 
|  | case e_float: | 
|  | m_type = e_void; | 
|  | break; | 
|  | case e_int: | 
|  | m_integer = m_integer.ashr(rhs.m_integer); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | Scalar &Scalar::operator&=(const Scalar &rhs) { | 
|  | if (m_type == e_int && rhs.m_type == e_int) | 
|  | m_integer &= rhs.m_integer; | 
|  | else | 
|  | m_type = e_void; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | bool Scalar::AbsoluteValue() { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  |  | 
|  | case e_int: | 
|  | if (m_integer.isNegative()) | 
|  | m_integer = -m_integer; | 
|  | return true; | 
|  |  | 
|  | case e_float: | 
|  | m_float.clearSign(); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Scalar::UnaryNegate() { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | m_integer = -m_integer; | 
|  | return true; | 
|  | case e_float: | 
|  | m_float.changeSign(); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Scalar::OnesComplement() { | 
|  | if (m_type == e_int) { | 
|  | m_integer = ~m_integer; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator+(const Scalar &lhs, const Scalar &rhs) { | 
|  | Scalar result = lhs; | 
|  | result += rhs; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator-(Scalar lhs, Scalar rhs) { | 
|  | Scalar result; | 
|  | if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { | 
|  | switch (result.m_type) { | 
|  | case Scalar::e_void: | 
|  | break; | 
|  | case Scalar::e_int: | 
|  | result.m_integer = lhs.m_integer - rhs.m_integer; | 
|  | break; | 
|  | case Scalar::e_float: | 
|  | result.m_float = lhs.m_float - rhs.m_float; | 
|  | break; | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator/(Scalar lhs, Scalar rhs) { | 
|  | Scalar result; | 
|  | if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void && | 
|  | !rhs.IsZero()) { | 
|  | switch (result.m_type) { | 
|  | case Scalar::e_void: | 
|  | break; | 
|  | case Scalar::e_int: | 
|  | result.m_integer = lhs.m_integer / rhs.m_integer; | 
|  | return result; | 
|  | case Scalar::e_float: | 
|  | result.m_float = lhs.m_float / rhs.m_float; | 
|  | return result; | 
|  | } | 
|  | } | 
|  | // For division only, the only way it should make it here is if a promotion | 
|  | // failed, or if we are trying to do a divide by zero. | 
|  | result.m_type = Scalar::e_void; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator*(Scalar lhs, Scalar rhs) { | 
|  | Scalar result; | 
|  | if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { | 
|  | switch (result.m_type) { | 
|  | case Scalar::e_void: | 
|  | break; | 
|  | case Scalar::e_int: | 
|  | result.m_integer = lhs.m_integer * rhs.m_integer; | 
|  | break; | 
|  | case Scalar::e_float: | 
|  | result.m_float = lhs.m_float * rhs.m_float; | 
|  | break; | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator&(Scalar lhs, Scalar rhs) { | 
|  | Scalar result; | 
|  | if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { | 
|  | if (result.m_type == Scalar::e_int) | 
|  | result.m_integer = lhs.m_integer & rhs.m_integer; | 
|  | else | 
|  | result.m_type = Scalar::e_void; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator|(Scalar lhs, Scalar rhs) { | 
|  | Scalar result; | 
|  | if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { | 
|  | if (result.m_type == Scalar::e_int) | 
|  | result.m_integer = lhs.m_integer | rhs.m_integer; | 
|  | else | 
|  | result.m_type = Scalar::e_void; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator%(Scalar lhs, Scalar rhs) { | 
|  | Scalar result; | 
|  | if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { | 
|  | if (!rhs.IsZero() && result.m_type == Scalar::e_int) { | 
|  | result.m_integer = lhs.m_integer % rhs.m_integer; | 
|  | return result; | 
|  | } | 
|  | } | 
|  | result.m_type = Scalar::e_void; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator^(Scalar lhs, Scalar rhs) { | 
|  | Scalar result; | 
|  | if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { | 
|  | if (result.m_type == Scalar::e_int) | 
|  | result.m_integer = lhs.m_integer ^ rhs.m_integer; | 
|  | else | 
|  | result.m_type = Scalar::e_void; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator<<(const Scalar &lhs, const Scalar &rhs) { | 
|  | Scalar result = lhs; | 
|  | result <<= rhs; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | const Scalar lldb_private::operator>>(const Scalar &lhs, const Scalar &rhs) { | 
|  | Scalar result = lhs; | 
|  | result >>= rhs; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding, | 
|  | size_t byte_size) { | 
|  | Status error; | 
|  | if (value_str == nullptr || value_str[0] == '\0') { | 
|  | return Status::FromErrorString("Invalid c-string value string."); | 
|  | } | 
|  | switch (encoding) { | 
|  | case eEncodingInvalid: | 
|  | return Status::FromErrorString("Invalid encoding."); | 
|  | break; | 
|  |  | 
|  | case eEncodingSint: | 
|  | case eEncodingUint: { | 
|  | llvm::StringRef str = value_str; | 
|  | bool is_signed = encoding == eEncodingSint; | 
|  | bool is_negative = is_signed && str.consume_front("-"); | 
|  | APInt integer; | 
|  | if (str.getAsInteger(0, integer)) { | 
|  | error = Status::FromErrorStringWithFormatv( | 
|  | "'{0}' is not a valid integer string value", value_str); | 
|  | break; | 
|  | } | 
|  | bool fits; | 
|  | if (is_signed) { | 
|  | integer = integer.zext(integer.getBitWidth() + 1); | 
|  | if (is_negative) | 
|  | integer.negate(); | 
|  | fits = integer.isSignedIntN(byte_size * 8); | 
|  | } else | 
|  | fits = integer.isIntN(byte_size * 8); | 
|  | if (!fits) { | 
|  | error = Status::FromErrorStringWithFormatv( | 
|  | "value {0} is too large to fit in a {1} byte integer value", | 
|  | value_str, byte_size); | 
|  | break; | 
|  | } | 
|  | m_type = e_int; | 
|  | m_integer = | 
|  | APSInt(std::move(integer), !is_signed).extOrTrunc(8 * byte_size); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case eEncodingIEEE754: { | 
|  | // FIXME: It's not possible to unambiguously map a byte size to a floating | 
|  | // point type. This function should be refactored to take an explicit | 
|  | // semantics argument. | 
|  | const llvm::fltSemantics &sem = | 
|  | byte_size <= 4 ? APFloat::IEEEsingle() | 
|  | : byte_size <= 8 ? APFloat::IEEEdouble() | 
|  | : APFloat::x87DoubleExtended(); | 
|  | APFloat f(sem); | 
|  | if (llvm::Expected<APFloat::opStatus> op = | 
|  | f.convertFromString(value_str, APFloat::rmNearestTiesToEven)) { | 
|  | m_type = e_float; | 
|  | m_float = std::move(f); | 
|  | } else | 
|  | error = Status::FromError(op.takeError()); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case eEncodingVector: | 
|  | return Status::FromErrorString("vector encoding unsupported."); | 
|  | break; | 
|  | } | 
|  | if (error.Fail()) | 
|  | m_type = e_void; | 
|  |  | 
|  | return error; | 
|  | } | 
|  |  | 
|  | Status Scalar::SetValueFromData(const DataExtractor &data, | 
|  | lldb::Encoding encoding, size_t byte_size) { | 
|  | Status error; | 
|  | switch (encoding) { | 
|  | case lldb::eEncodingInvalid: | 
|  | return Status::FromErrorString("invalid encoding"); | 
|  | break; | 
|  | case lldb::eEncodingVector: | 
|  | return Status::FromErrorString("vector encoding unsupported"); | 
|  | break; | 
|  | case lldb::eEncodingUint: | 
|  | case lldb::eEncodingSint: { | 
|  | if (data.GetByteSize() < byte_size) | 
|  | return Status::FromErrorString("insufficient data"); | 
|  | m_type = e_int; | 
|  | m_integer = | 
|  | APSInt(APInt::getZero(8 * byte_size), encoding == eEncodingUint); | 
|  | if (data.GetByteOrder() == endian::InlHostByteOrder()) { | 
|  | llvm::LoadIntFromMemory(m_integer, data.GetDataStart(), byte_size); | 
|  | } else { | 
|  | std::vector<uint8_t> buffer(byte_size); | 
|  | std::copy_n(data.GetDataStart(), byte_size, buffer.rbegin()); | 
|  | llvm::LoadIntFromMemory(m_integer, buffer.data(), byte_size); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case lldb::eEncodingIEEE754: { | 
|  | lldb::offset_t offset = 0; | 
|  |  | 
|  | if (byte_size == sizeof(float)) | 
|  | operator=(data.GetFloat(&offset)); | 
|  | else if (byte_size == sizeof(double)) | 
|  | operator=(data.GetDouble(&offset)); | 
|  | else if (byte_size == sizeof(long double)) | 
|  | operator=(data.GetLongDouble(&offset)); | 
|  | else | 
|  | return Status::FromErrorStringWithFormatv( | 
|  | "unsupported float byte size: {0}", static_cast<uint64_t>(byte_size)); | 
|  | } break; | 
|  | } | 
|  |  | 
|  | return error; | 
|  | } | 
|  |  | 
|  | bool Scalar::SignExtend(uint32_t sign_bit_pos) { | 
|  | const uint32_t max_bit_pos = GetByteSize() * 8; | 
|  |  | 
|  | if (sign_bit_pos < max_bit_pos) { | 
|  | switch (m_type) { | 
|  | case Scalar::e_void: | 
|  | case Scalar::e_float: | 
|  | return false; | 
|  |  | 
|  | case Scalar::e_int: | 
|  | if (sign_bit_pos < (max_bit_pos - 1)) { | 
|  | llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1); | 
|  | llvm::APInt bitwize_and = m_integer & sign_bit; | 
|  | if (bitwize_and.getBoolValue()) { | 
|  | llvm::APInt mask = | 
|  | ~(sign_bit) + llvm::APInt(m_integer.getBitWidth(), 1); | 
|  | m_integer |= APSInt(std::move(mask), m_integer.isUnsigned()); | 
|  | } | 
|  | return true; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | size_t Scalar::GetAsMemoryData(void *dst, size_t dst_len, | 
|  | lldb::ByteOrder dst_byte_order, | 
|  | Status &error) const { | 
|  | // Get a data extractor that points to the native scalar data | 
|  | DataExtractor data; | 
|  | if (!GetData(data)) { | 
|  | error = Status::FromErrorString("invalid scalar value"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | const size_t src_len = data.GetByteSize(); | 
|  |  | 
|  | // Prepare a memory buffer that contains some or all of the register value | 
|  | const size_t bytes_copied = | 
|  | data.CopyByteOrderedData(0,               // src offset | 
|  | src_len,         // src length | 
|  | dst,             // dst buffer | 
|  | dst_len,         // dst length | 
|  | dst_byte_order); // dst byte order | 
|  | if (bytes_copied == 0) | 
|  | error = Status::FromErrorString("failed to copy data"); | 
|  |  | 
|  | return bytes_copied; | 
|  | } | 
|  |  | 
|  | bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) { | 
|  | if (bit_size == 0) | 
|  | return true; | 
|  |  | 
|  | switch (m_type) { | 
|  | case Scalar::e_void: | 
|  | case Scalar::e_float: | 
|  | break; | 
|  |  | 
|  | case Scalar::e_int: | 
|  | m_integer >>= bit_offset; | 
|  | m_integer = m_integer.extOrTrunc(bit_size).extOrTrunc(8 * GetByteSize()); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | llvm::APFloat Scalar::CreateAPFloatFromAPSInt(lldb::BasicType basic_type) { | 
|  | switch (basic_type) { | 
|  | case lldb::eBasicTypeFloat: | 
|  | return llvm::APFloat( | 
|  | m_integer.isSigned() | 
|  | ? llvm::APIntOps::RoundSignedAPIntToFloat(m_integer) | 
|  | : llvm::APIntOps::RoundAPIntToFloat(m_integer)); | 
|  | case lldb::eBasicTypeDouble: | 
|  | // No way to get more precision at the moment. | 
|  | case lldb::eBasicTypeLongDouble: | 
|  | return llvm::APFloat( | 
|  | m_integer.isSigned() | 
|  | ? llvm::APIntOps::RoundSignedAPIntToDouble(m_integer) | 
|  | : llvm::APIntOps::RoundAPIntToDouble(m_integer)); | 
|  | default: | 
|  | const llvm::fltSemantics &sem = APFloat::IEEEsingle(); | 
|  | return llvm::APFloat::getNaN(sem); | 
|  | } | 
|  | } | 
|  |  | 
|  | llvm::APFloat Scalar::CreateAPFloatFromAPFloat(lldb::BasicType basic_type) { | 
|  | switch (basic_type) { | 
|  | case lldb::eBasicTypeFloat: { | 
|  | bool loses_info; | 
|  | m_float.convert(llvm::APFloat::IEEEsingle(), | 
|  | llvm::APFloat::rmNearestTiesToEven, &loses_info); | 
|  | return m_float; | 
|  | } | 
|  | case lldb::eBasicTypeDouble: | 
|  | // No way to get more precision at the moment. | 
|  | case lldb::eBasicTypeLongDouble: { | 
|  | bool loses_info; | 
|  | m_float.convert(llvm::APFloat::IEEEdouble(), | 
|  | llvm::APFloat::rmNearestTiesToEven, &loses_info); | 
|  | return m_float; | 
|  | } | 
|  | default: | 
|  | const llvm::fltSemantics &sem = APFloat::IEEEsingle(); | 
|  | return llvm::APFloat::getNaN(sem); | 
|  | } | 
|  | } | 
|  |  | 
|  | APFloat::cmpResult lldb_private::compare(Scalar lhs, Scalar rhs) { | 
|  | // If either entry is void then we can just compare the types | 
|  | if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) | 
|  | return lhs.m_type == rhs.m_type ? APFloat::cmpEqual : APFloat::cmpUnordered; | 
|  |  | 
|  | switch (Scalar::PromoteToMaxType(lhs, rhs)) { | 
|  | case Scalar::e_void: | 
|  | break; | 
|  | case Scalar::e_int: | 
|  | if (lhs.m_integer < rhs.m_integer) | 
|  | return APFloat::cmpLessThan; | 
|  | if (lhs.m_integer > rhs.m_integer) | 
|  | return APFloat::cmpGreaterThan; | 
|  | return APFloat::cmpEqual; | 
|  | case Scalar::e_float: | 
|  | return lhs.m_float.compare(rhs.m_float); | 
|  | } | 
|  | return APFloat::cmpUnordered; | 
|  | } | 
|  |  | 
|  | bool lldb_private::operator==(const Scalar &lhs, const Scalar &rhs) { | 
|  | return compare(lhs, rhs) == APFloat::cmpEqual; | 
|  | } | 
|  |  | 
|  | bool lldb_private::operator!=(const Scalar &lhs, const Scalar &rhs) { | 
|  | return compare(lhs, rhs) != APFloat::cmpEqual; | 
|  | } | 
|  |  | 
|  | bool lldb_private::operator<(const Scalar &lhs, const Scalar &rhs) { | 
|  | return compare(lhs, rhs) == APFloat::cmpLessThan; | 
|  | } | 
|  |  | 
|  | bool lldb_private::operator<=(const Scalar &lhs, const Scalar &rhs) { | 
|  | APFloat::cmpResult Res = compare(lhs, rhs); | 
|  | return Res == APFloat::cmpLessThan || Res == APFloat::cmpEqual; | 
|  | } | 
|  |  | 
|  | bool lldb_private::operator>(const Scalar &lhs, const Scalar &rhs) { | 
|  | return compare(lhs, rhs) == APFloat::cmpGreaterThan; | 
|  | } | 
|  |  | 
|  | bool lldb_private::operator>=(const Scalar &lhs, const Scalar &rhs) { | 
|  | APFloat::cmpResult Res = compare(lhs, rhs); | 
|  | return Res == APFloat::cmpGreaterThan || Res == APFloat::cmpEqual; | 
|  | } | 
|  |  | 
|  | bool Scalar::ClearBit(uint32_t bit) { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | m_integer.clearBit(bit); | 
|  | return true; | 
|  | case e_float: | 
|  | break; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Scalar::SetBit(uint32_t bit) { | 
|  | switch (m_type) { | 
|  | case e_void: | 
|  | break; | 
|  | case e_int: | 
|  | m_integer.setBit(bit); | 
|  | return true; | 
|  | case e_float: | 
|  | break; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &os, const Scalar &scalar) { | 
|  | StreamString s; | 
|  | scalar.GetValue(s, /*show_type*/ true); | 
|  | return os << s.GetString(); | 
|  | } |