1 //===-- Scalar.h ------------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_UTILITY_SCALAR_H 10 #define LLDB_UTILITY_SCALAR_H 11 12 #include "lldb/Utility/LLDBAssert.h" 13 #include "lldb/Utility/Status.h" 14 #include "lldb/lldb-enumerations.h" 15 #include "lldb/lldb-private-types.h" 16 #include "llvm/ADT/APFloat.h" 17 #include "llvm/ADT/APSInt.h" 18 #include <cstddef> 19 #include <cstdint> 20 #include <utility> 21 22 namespace lldb_private { 23 24 class DataExtractor; 25 class Stream; 26 27 #define NUM_OF_WORDS_INT128 2 28 #define BITWIDTH_INT128 128 29 30 // A class designed to hold onto values and their corresponding types. 31 // Operators are defined and Scalar objects will correctly promote their types 32 // and values before performing these operations. Type promotion currently 33 // follows the ANSI C type promotion rules. 34 class Scalar { 35 template<typename T> MakeAPSInt(T v)36 static llvm::APSInt MakeAPSInt(T v) { 37 static_assert(std::is_integral<T>::value); 38 static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); 39 return llvm::APSInt( 40 llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), 41 std::is_unsigned<T>::value); 42 } 43 44 public: 45 enum Type { 46 e_void = 0, 47 e_int, 48 e_float, 49 }; 50 51 // Constructors and Destructors Scalar()52 Scalar() : m_float(0.0f) {} Scalar(int v)53 Scalar(int v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} Scalar(unsigned int v)54 Scalar(unsigned int v) 55 : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} Scalar(long v)56 Scalar(long v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} Scalar(unsigned long v)57 Scalar(unsigned long v) 58 : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} Scalar(long long v)59 Scalar(long long v) 60 : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} Scalar(unsigned long long v)61 Scalar(unsigned long long v) 62 : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} Scalar(float v)63 Scalar(float v) : m_type(e_float), m_float(v) {} Scalar(double v)64 Scalar(double v) : m_type(e_float), m_float(v) {} Scalar(long double v)65 Scalar(long double v) : m_type(e_float), m_float(double(v)) { 66 bool ignore; 67 m_float.convert(llvm::APFloat::x87DoubleExtended(), 68 llvm::APFloat::rmNearestTiesToEven, &ignore); 69 } Scalar(llvm::APInt v)70 Scalar(llvm::APInt v) 71 : m_type(e_int), m_integer(std::move(v), false), m_float(0.0f) {} Scalar(llvm::APSInt v)72 Scalar(llvm::APSInt v) 73 : m_type(e_int), m_integer(std::move(v)), m_float(0.0f) {} Scalar(llvm::APFloat v)74 Scalar(llvm::APFloat v) : m_type(e_float), m_integer(0), m_float(v) {} 75 76 bool SignExtend(uint32_t bit_pos); 77 78 bool ExtractBitfield(uint32_t bit_size, uint32_t bit_offset); 79 80 bool SetBit(uint32_t bit); 81 82 bool ClearBit(uint32_t bit); 83 84 /// Store the binary representation of this value into the given storage. 85 /// Exactly GetByteSize() bytes will be stored, and the buffer must be large 86 /// enough to hold this data. 87 void GetBytes(llvm::MutableArrayRef<uint8_t> storage) const; 88 89 size_t GetByteSize() const; 90 91 bool GetData(DataExtractor &data, size_t limit_byte_size = UINT32_MAX) const; 92 93 size_t GetAsMemoryData(void *dst, size_t dst_len, 94 lldb::ByteOrder dst_byte_order, Status &error) const; 95 96 bool IsZero() const; 97 Clear()98 void Clear() { 99 m_type = e_void; 100 m_integer.clearAllBits(); 101 } 102 GetTypeAsCString()103 const char *GetTypeAsCString() const { return GetValueTypeAsCString(m_type); } 104 105 void GetValue(Stream &s, bool show_type) const; 106 IsValid()107 bool IsValid() const { return (m_type >= e_int) && (m_type <= e_float); } 108 109 /// Convert to an integer with \p bits and the given signedness. 110 void TruncOrExtendTo(uint16_t bits, bool sign); 111 112 bool IntegralPromote(uint16_t bits, bool sign); 113 bool FloatPromote(const llvm::fltSemantics &semantics); 114 115 bool IsSigned() const; 116 bool MakeSigned(); 117 118 bool MakeUnsigned(); 119 120 static const char *GetValueTypeAsCString(Scalar::Type value_type); 121 122 // All operators can benefits from the implicit conversions that will happen 123 // automagically by the compiler, so no temporary objects will need to be 124 // created. As a result, we currently don't need a variety of overloaded set 125 // value accessors. 126 Scalar &operator+=(Scalar rhs); 127 Scalar &operator<<=(const Scalar &rhs); // Shift left 128 Scalar &operator>>=(const Scalar &rhs); // Shift right (arithmetic) 129 Scalar &operator&=(const Scalar &rhs); 130 131 // Shifts the current value to the right without maintaining the current sign 132 // of the value (if it is signed). 133 bool ShiftRightLogical(const Scalar &rhs); // Returns true on success 134 135 // Takes the absolute value of the current value if it is signed, else the 136 // value remains unchanged. Returns false if the contained value has a void 137 // type. 138 bool AbsoluteValue(); // Returns true on success 139 // Negates the current value (even for unsigned values). Returns false if the 140 // contained value has a void type. 141 bool UnaryNegate(); // Returns true on success 142 // Inverts all bits in the current value as long as it isn't void or a 143 // float/double/long double type. Returns false if the contained value has a 144 // void/float/double/long double type, else the value is inverted and true is 145 // returned. 146 bool OnesComplement(); // Returns true on success 147 148 // Access the type of the current value. GetType()149 Scalar::Type GetType() const { return m_type; } 150 151 // Returns a casted value of the current contained data without modifying the 152 // current value. FAIL_VALUE will be returned if the type of the value is 153 // void or invalid. 154 int SInt(int fail_value = 0) const; 155 156 unsigned char UChar(unsigned char fail_value = 0) const; 157 158 signed char SChar(signed char fail_value = 0) const; 159 160 unsigned short UShort(unsigned short fail_value = 0) const; 161 162 short SShort(short fail_value = 0) const; 163 164 unsigned int UInt(unsigned int fail_value = 0) const; 165 166 long SLong(long fail_value = 0) const; 167 168 unsigned long ULong(unsigned long fail_value = 0) const; 169 170 long long SLongLong(long long fail_value = 0) const; 171 172 unsigned long long ULongLong(unsigned long long fail_value = 0) const; 173 174 llvm::APInt SInt128(const llvm::APInt &fail_value) const; 175 176 llvm::APInt UInt128(const llvm::APInt &fail_value) const; 177 178 float Float(float fail_value = 0.0f) const; 179 180 double Double(double fail_value = 0.0) const; 181 182 long double LongDouble(long double fail_value = 0.0) const; 183 GetAPSInt()184 llvm::APSInt GetAPSInt() const { return m_integer; } 185 GetAPFloat()186 llvm::APFloat GetAPFloat() const { return m_float; } 187 188 Status SetValueFromCString(const char *s, lldb::Encoding encoding, 189 size_t byte_size); 190 191 Status SetValueFromData(const DataExtractor &data, lldb::Encoding encoding, 192 size_t byte_size); 193 194 llvm::APFloat CreateAPFloatFromAPSInt(lldb::BasicType basic_type); 195 196 llvm::APFloat CreateAPFloatFromAPFloat(lldb::BasicType basic_type); 197 198 protected: 199 Scalar::Type m_type = e_void; 200 llvm::APSInt m_integer; 201 llvm::APFloat m_float; 202 203 template <typename T> T GetAs(T fail_value) const; 204 205 static Type PromoteToMaxType(Scalar &lhs, Scalar &rhs); 206 207 using PromotionKey = std::tuple<Type, unsigned, bool>; 208 PromotionKey GetPromoKey() const; 209 210 static PromotionKey GetFloatPromoKey(const llvm::fltSemantics &semantics); 211 212 private: 213 friend const Scalar operator+(const Scalar &lhs, const Scalar &rhs); 214 friend const Scalar operator-(Scalar lhs, Scalar rhs); 215 friend const Scalar operator/(Scalar lhs, Scalar rhs); 216 friend const Scalar operator*(Scalar lhs, Scalar rhs); 217 friend const Scalar operator&(Scalar lhs, Scalar rhs); 218 friend const Scalar operator|(Scalar lhs, Scalar rhs); 219 friend const Scalar operator%(Scalar lhs, Scalar rhs); 220 friend const Scalar operator^(Scalar lhs, Scalar rhs); 221 friend const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); 222 friend const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); 223 friend bool operator==(Scalar lhs, Scalar rhs); 224 friend bool operator!=(const Scalar &lhs, const Scalar &rhs); 225 friend bool operator<(Scalar lhs, Scalar rhs); 226 friend bool operator<=(const Scalar &lhs, const Scalar &rhs); 227 friend bool operator>(const Scalar &lhs, const Scalar &rhs); 228 friend bool operator>=(const Scalar &lhs, const Scalar &rhs); 229 }; 230 231 // Split out the operators into a format where the compiler will be able to 232 // implicitly convert numbers into Scalar objects. 233 // 234 // This allows code like: 235 // Scalar two(2); 236 // Scalar four = two * 2; 237 // Scalar eight = 2 * four; // This would cause an error if the 238 // // operator* was implemented as a 239 // // member function. 240 // SEE: 241 // Item 19 of "Effective C++ Second Edition" by Scott Meyers 242 // Differentiate among members functions, non-member functions, and 243 // friend functions 244 const Scalar operator+(const Scalar &lhs, const Scalar &rhs); 245 const Scalar operator-(Scalar lhs, Scalar rhs); 246 const Scalar operator/(Scalar lhs, Scalar rhs); 247 const Scalar operator*(Scalar lhs, Scalar rhs); 248 const Scalar operator&(Scalar lhs, Scalar rhs); 249 const Scalar operator|(Scalar lhs, Scalar rhs); 250 const Scalar operator%(Scalar lhs, Scalar rhs); 251 const Scalar operator^(Scalar lhs, Scalar rhs); 252 const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); 253 const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); 254 bool operator==(Scalar lhs, Scalar rhs); 255 bool operator!=(const Scalar &lhs, const Scalar &rhs); 256 bool operator<(Scalar lhs, Scalar rhs); 257 bool operator<=(const Scalar &lhs, const Scalar &rhs); 258 bool operator>(const Scalar &lhs, const Scalar &rhs); 259 bool operator>=(const Scalar &lhs, const Scalar &rhs); 260 261 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scalar &scalar); 262 263 } // namespace lldb_private 264 265 #endif // LLDB_UTILITY_SCALAR_H 266