1343181Sdim//===-- Scalar.h ------------------------------------------------*- C++ -*-===// 2343181Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343181Sdim// 7343181Sdim//===----------------------------------------------------------------------===// 8343181Sdim 9343181Sdim#ifndef LLDB_UTILITY_SCALAR_H 10343181Sdim#define LLDB_UTILITY_SCALAR_H 11343181Sdim 12343181Sdim#include "lldb/Utility/Status.h" 13343181Sdim#include "lldb/lldb-enumerations.h" 14343181Sdim#include "lldb/lldb-private-types.h" 15353358Sdim#include "lldb/Utility/LLDBAssert.h" 16343181Sdim#include "llvm/ADT/APFloat.h" 17343181Sdim#include "llvm/ADT/APInt.h" 18343181Sdim#include <cstddef> 19343181Sdim#include <cstdint> 20343181Sdim 21343181Sdimnamespace lldb_private { 22343181Sdimclass DataExtractor; 23343181Sdimclass Stream; 24343181Sdim} // namespace lldb_private 25343181Sdim 26343181Sdim#define NUM_OF_WORDS_INT128 2 27343181Sdim#define BITWIDTH_INT128 128 28343181Sdim#define NUM_OF_WORDS_INT256 4 29343181Sdim#define BITWIDTH_INT256 256 30353358Sdim#define NUM_OF_WORDS_INT512 8 31353358Sdim#define BITWIDTH_INT512 512 32343181Sdim 33343181Sdimnamespace lldb_private { 34343181Sdim 35343181Sdim// A class designed to hold onto values and their corresponding types. 36343181Sdim// Operators are defined and Scalar objects will correctly promote their types 37343181Sdim// and values before performing these operations. Type promotion currently 38343181Sdim// follows the ANSI C type promotion rules. 39343181Sdimclass Scalar { 40343181Sdimpublic: 41360784Sdim // FIXME: These are host types which seems to be an odd choice. 42343181Sdim enum Type { 43343181Sdim e_void = 0, 44343181Sdim e_sint, 45343181Sdim e_uint, 46343181Sdim e_slong, 47343181Sdim e_ulong, 48343181Sdim e_slonglong, 49343181Sdim e_ulonglong, 50343181Sdim e_sint128, 51343181Sdim e_uint128, 52343181Sdim e_sint256, 53343181Sdim e_uint256, 54353358Sdim e_sint512, 55353358Sdim e_uint512, 56343181Sdim e_float, 57343181Sdim e_double, 58343181Sdim e_long_double 59343181Sdim }; 60343181Sdim 61343181Sdim // Constructors and Destructors 62343181Sdim Scalar(); 63353358Sdim Scalar(int v) : m_type(e_sint), m_float(static_cast<float>(0)) { 64343181Sdim m_integer = llvm::APInt(sizeof(int) * 8, v, true); 65343181Sdim } 66353358Sdim Scalar(unsigned int v) : m_type(e_uint), m_float(static_cast<float>(0)) { 67343181Sdim m_integer = llvm::APInt(sizeof(int) * 8, v); 68343181Sdim } 69353358Sdim Scalar(long v) : m_type(e_slong), m_float(static_cast<float>(0)) { 70343181Sdim m_integer = llvm::APInt(sizeof(long) * 8, v, true); 71343181Sdim } 72353358Sdim Scalar(unsigned long v) : m_type(e_ulong), m_float(static_cast<float>(0)) { 73343181Sdim m_integer = llvm::APInt(sizeof(long) * 8, v); 74343181Sdim } 75353358Sdim Scalar(long long v) : m_type(e_slonglong), m_float(static_cast<float>(0)) { 76343181Sdim m_integer = llvm::APInt(sizeof(long long) * 8, v, true); 77343181Sdim } 78353358Sdim Scalar(unsigned long long v) 79353358Sdim : m_type(e_ulonglong), m_float(static_cast<float>(0)) { 80343181Sdim m_integer = llvm::APInt(sizeof(long long) * 8, v); 81343181Sdim } 82343181Sdim Scalar(float v) : m_type(e_float), m_float(v) { m_float = llvm::APFloat(v); } 83343181Sdim Scalar(double v) : m_type(e_double), m_float(v) { 84343181Sdim m_float = llvm::APFloat(v); 85343181Sdim } 86343181Sdim Scalar(long double v, bool ieee_quad) 87353358Sdim : m_type(e_long_double), m_float(static_cast<float>(0)), 88353358Sdim m_ieee_quad(ieee_quad) { 89343181Sdim if (ieee_quad) 90353358Sdim m_float = 91353358Sdim llvm::APFloat(llvm::APFloat::IEEEquad(), 92353358Sdim llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, 93353358Sdim (reinterpret_cast<type128 *>(&v))->x)); 94343181Sdim else 95353358Sdim m_float = 96353358Sdim llvm::APFloat(llvm::APFloat::x87DoubleExtended(), 97353358Sdim llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, 98353358Sdim (reinterpret_cast<type128 *>(&v))->x)); 99343181Sdim } 100353358Sdim Scalar(llvm::APInt v) : m_type(), m_float(static_cast<float>(0)) { 101343181Sdim m_integer = llvm::APInt(v); 102360784Sdim m_type = GetBestTypeForBitSize(m_integer.getBitWidth(), true); 103343181Sdim } 104343181Sdim // Scalar(const RegisterValue& reg_value); 105343181Sdim virtual ~Scalar(); 106343181Sdim 107360784Sdim /// Return the most efficient Scalar::Type for the requested bit size. 108360784Sdim static Type GetBestTypeForBitSize(size_t bit_size, bool sign); 109360784Sdim 110343181Sdim bool SignExtend(uint32_t bit_pos); 111343181Sdim 112343181Sdim bool ExtractBitfield(uint32_t bit_size, uint32_t bit_offset); 113343181Sdim 114343181Sdim bool SetBit(uint32_t bit); 115343181Sdim 116343181Sdim bool ClearBit(uint32_t bit); 117343181Sdim 118343181Sdim const void *GetBytes() const; 119343181Sdim 120343181Sdim size_t GetByteSize() const; 121343181Sdim 122343181Sdim bool GetData(DataExtractor &data, size_t limit_byte_size = UINT32_MAX) const; 123343181Sdim 124343181Sdim size_t GetAsMemoryData(void *dst, size_t dst_len, 125343181Sdim lldb::ByteOrder dst_byte_order, Status &error) const; 126343181Sdim 127343181Sdim bool IsZero() const; 128343181Sdim 129343181Sdim void Clear() { 130343181Sdim m_type = e_void; 131343181Sdim m_integer.clearAllBits(); 132343181Sdim } 133343181Sdim 134343181Sdim const char *GetTypeAsCString() const; 135343181Sdim 136343181Sdim void GetValue(Stream *s, bool show_type) const; 137343181Sdim 138343181Sdim bool IsValid() const { 139343181Sdim return (m_type >= e_sint) && (m_type <= e_long_double); 140343181Sdim } 141343181Sdim 142360784Sdim /// Convert integer to \p type, limited to \p bits size. 143360784Sdim void TruncOrExtendTo(Scalar::Type type, uint16_t bits); 144360784Sdim 145343181Sdim bool Promote(Scalar::Type type); 146343181Sdim 147343181Sdim bool MakeSigned(); 148343181Sdim 149343181Sdim bool MakeUnsigned(); 150343181Sdim 151343181Sdim static const char *GetValueTypeAsCString(Scalar::Type value_type); 152343181Sdim 153343181Sdim static Scalar::Type 154343181Sdim GetValueTypeForSignedIntegerWithByteSize(size_t byte_size); 155343181Sdim 156343181Sdim static Scalar::Type 157343181Sdim GetValueTypeForUnsignedIntegerWithByteSize(size_t byte_size); 158343181Sdim 159343181Sdim static Scalar::Type GetValueTypeForFloatWithByteSize(size_t byte_size); 160343181Sdim 161343181Sdim // All operators can benefits from the implicit conversions that will happen 162343181Sdim // automagically by the compiler, so no temporary objects will need to be 163343181Sdim // created. As a result, we currently don't need a variety of overloaded set 164343181Sdim // value accessors. 165343181Sdim Scalar &operator=(const int i); 166343181Sdim Scalar &operator=(unsigned int v); 167343181Sdim Scalar &operator=(long v); 168343181Sdim Scalar &operator=(unsigned long v); 169343181Sdim Scalar &operator=(long long v); 170343181Sdim Scalar &operator=(unsigned long long v); 171343181Sdim Scalar &operator=(float v); 172343181Sdim Scalar &operator=(double v); 173343181Sdim Scalar &operator=(long double v); 174343181Sdim Scalar &operator=(llvm::APInt v); 175343181Sdim Scalar &operator+=(const Scalar &rhs); 176343181Sdim Scalar &operator<<=(const Scalar &rhs); // Shift left 177343181Sdim Scalar &operator>>=(const Scalar &rhs); // Shift right (arithmetic) 178343181Sdim Scalar &operator&=(const Scalar &rhs); 179343181Sdim 180343181Sdim // Shifts the current value to the right without maintaining the current sign 181343181Sdim // of the value (if it is signed). 182343181Sdim bool ShiftRightLogical(const Scalar &rhs); // Returns true on success 183343181Sdim 184343181Sdim // Takes the absolute value of the current value if it is signed, else the 185343181Sdim // value remains unchanged. Returns false if the contained value has a void 186343181Sdim // type. 187343181Sdim bool AbsoluteValue(); // Returns true on success 188343181Sdim // Negates the current value (even for unsigned values). Returns false if the 189343181Sdim // contained value has a void type. 190343181Sdim bool UnaryNegate(); // Returns true on success 191343181Sdim // Inverts all bits in the current value as long as it isn't void or a 192343181Sdim // float/double/long double type. Returns false if the contained value has a 193343181Sdim // void/float/double/long double type, else the value is inverted and true is 194343181Sdim // returned. 195343181Sdim bool OnesComplement(); // Returns true on success 196343181Sdim 197343181Sdim // Access the type of the current value. 198343181Sdim Scalar::Type GetType() const { return m_type; } 199343181Sdim 200343181Sdim // Returns a casted value of the current contained data without modifying the 201343181Sdim // current value. FAIL_VALUE will be returned if the type of the value is 202343181Sdim // void or invalid. 203343181Sdim int SInt(int fail_value = 0) const; 204343181Sdim 205343181Sdim unsigned char UChar(unsigned char fail_value = 0) const; 206343181Sdim 207343181Sdim signed char SChar(char fail_value = 0) const; 208343181Sdim 209343181Sdim unsigned short UShort(unsigned short fail_value = 0) const; 210343181Sdim 211343181Sdim short SShort(short fail_value = 0) const; 212343181Sdim 213343181Sdim unsigned int UInt(unsigned int fail_value = 0) const; 214343181Sdim 215343181Sdim long SLong(long fail_value = 0) const; 216343181Sdim 217343181Sdim unsigned long ULong(unsigned long fail_value = 0) const; 218343181Sdim 219343181Sdim long long SLongLong(long long fail_value = 0) const; 220343181Sdim 221343181Sdim unsigned long long ULongLong(unsigned long long fail_value = 0) const; 222343181Sdim 223343181Sdim llvm::APInt SInt128(llvm::APInt &fail_value) const; 224343181Sdim 225343181Sdim llvm::APInt UInt128(const llvm::APInt &fail_value) const; 226343181Sdim 227343181Sdim float Float(float fail_value = 0.0f) const; 228343181Sdim 229343181Sdim double Double(double fail_value = 0.0) const; 230343181Sdim 231343181Sdim long double LongDouble(long double fail_value = 0.0) const; 232343181Sdim 233343181Sdim Status SetValueFromCString(const char *s, lldb::Encoding encoding, 234343181Sdim size_t byte_size); 235343181Sdim 236343181Sdim Status SetValueFromData(DataExtractor &data, lldb::Encoding encoding, 237343181Sdim size_t byte_size); 238343181Sdim 239343181Sdim static bool UIntValueIsValidForSize(uint64_t uval64, size_t total_byte_size) { 240343181Sdim if (total_byte_size > 8) 241343181Sdim return false; 242343181Sdim 243343181Sdim if (total_byte_size == 8) 244343181Sdim return true; 245343181Sdim 246353358Sdim const uint64_t max = (static_cast<uint64_t>(1) 247353358Sdim << static_cast<uint64_t>(total_byte_size * 8)) - 248353358Sdim 1; 249343181Sdim return uval64 <= max; 250343181Sdim } 251343181Sdim 252343181Sdim static bool SIntValueIsValidForSize(int64_t sval64, size_t total_byte_size) { 253343181Sdim if (total_byte_size > 8) 254343181Sdim return false; 255343181Sdim 256343181Sdim if (total_byte_size == 8) 257343181Sdim return true; 258343181Sdim 259353358Sdim const int64_t max = (static_cast<int64_t>(1) 260353358Sdim << static_cast<uint64_t>(total_byte_size * 8 - 1)) - 261353358Sdim 1; 262343181Sdim const int64_t min = ~(max); 263343181Sdim return min <= sval64 && sval64 <= max; 264343181Sdim } 265343181Sdim 266343181Sdimprotected: 267343181Sdim typedef char schar_t; 268343181Sdim typedef unsigned char uchar_t; 269343181Sdim typedef short sshort_t; 270343181Sdim typedef unsigned short ushort_t; 271343181Sdim typedef int sint_t; 272343181Sdim typedef unsigned int uint_t; 273343181Sdim typedef long slong_t; 274343181Sdim typedef unsigned long ulong_t; 275343181Sdim typedef long long slonglong_t; 276343181Sdim typedef unsigned long long ulonglong_t; 277343181Sdim typedef float float_t; 278343181Sdim typedef double double_t; 279343181Sdim typedef long double long_double_t; 280343181Sdim 281343181Sdim // Classes that inherit from Scalar can see and modify these 282343181Sdim Scalar::Type m_type; 283343181Sdim llvm::APInt m_integer; 284343181Sdim llvm::APFloat m_float; 285343181Sdim bool m_ieee_quad = false; 286343181Sdim 287343181Sdimprivate: 288343181Sdim friend const Scalar operator+(const Scalar &lhs, const Scalar &rhs); 289343181Sdim friend const Scalar operator-(const Scalar &lhs, const Scalar &rhs); 290343181Sdim friend const Scalar operator/(const Scalar &lhs, const Scalar &rhs); 291343181Sdim friend const Scalar operator*(const Scalar &lhs, const Scalar &rhs); 292343181Sdim friend const Scalar operator&(const Scalar &lhs, const Scalar &rhs); 293343181Sdim friend const Scalar operator|(const Scalar &lhs, const Scalar &rhs); 294343181Sdim friend const Scalar operator%(const Scalar &lhs, const Scalar &rhs); 295343181Sdim friend const Scalar operator^(const Scalar &lhs, const Scalar &rhs); 296343181Sdim friend const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); 297343181Sdim friend const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); 298343181Sdim friend bool operator==(const Scalar &lhs, const Scalar &rhs); 299343181Sdim friend bool operator!=(const Scalar &lhs, const Scalar &rhs); 300343181Sdim friend bool operator<(const Scalar &lhs, const Scalar &rhs); 301343181Sdim friend bool operator<=(const Scalar &lhs, const Scalar &rhs); 302343181Sdim friend bool operator>(const Scalar &lhs, const Scalar &rhs); 303343181Sdim friend bool operator>=(const Scalar &lhs, const Scalar &rhs); 304343181Sdim}; 305343181Sdim 306343181Sdim// Split out the operators into a format where the compiler will be able to 307343181Sdim// implicitly convert numbers into Scalar objects. 308343181Sdim// 309343181Sdim// This allows code like: 310343181Sdim// Scalar two(2); 311343181Sdim// Scalar four = two * 2; 312343181Sdim// Scalar eight = 2 * four; // This would cause an error if the 313343181Sdim// // operator* was implemented as a 314343181Sdim// // member function. 315343181Sdim// SEE: 316343181Sdim// Item 19 of "Effective C++ Second Edition" by Scott Meyers 317343181Sdim// Differentiate among members functions, non-member functions, and 318343181Sdim// friend functions 319343181Sdimconst Scalar operator+(const Scalar &lhs, const Scalar &rhs); 320343181Sdimconst Scalar operator-(const Scalar &lhs, const Scalar &rhs); 321343181Sdimconst Scalar operator/(const Scalar &lhs, const Scalar &rhs); 322343181Sdimconst Scalar operator*(const Scalar &lhs, const Scalar &rhs); 323343181Sdimconst Scalar operator&(const Scalar &lhs, const Scalar &rhs); 324343181Sdimconst Scalar operator|(const Scalar &lhs, const Scalar &rhs); 325343181Sdimconst Scalar operator%(const Scalar &lhs, const Scalar &rhs); 326343181Sdimconst Scalar operator^(const Scalar &lhs, const Scalar &rhs); 327343181Sdimconst Scalar operator<<(const Scalar &lhs, const Scalar &rhs); 328343181Sdimconst Scalar operator>>(const Scalar &lhs, const Scalar &rhs); 329343181Sdimbool operator==(const Scalar &lhs, const Scalar &rhs); 330343181Sdimbool operator!=(const Scalar &lhs, const Scalar &rhs); 331343181Sdimbool operator<(const Scalar &lhs, const Scalar &rhs); 332343181Sdimbool operator<=(const Scalar &lhs, const Scalar &rhs); 333343181Sdimbool operator>(const Scalar &lhs, const Scalar &rhs); 334343181Sdimbool operator>=(const Scalar &lhs, const Scalar &rhs); 335343181Sdim 336353358Sdimllvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scalar &scalar); 337353358Sdim 338343181Sdim} // namespace lldb_private 339343181Sdim 340343181Sdim#endif // LLDB_UTILITY_SCALAR_H 341