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_type(e_void), 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) {} 74 75 bool SignExtend(uint32_t bit_pos); 76 77 bool ExtractBitfield(uint32_t bit_size, uint32_t bit_offset); 78 79 bool SetBit(uint32_t bit); 80 81 bool ClearBit(uint32_t bit); 82 83 /// Store the binary representation of this value into the given storage. 84 /// Exactly GetByteSize() bytes will be stored, and the buffer must be large 85 /// enough to hold this data. 86 void GetBytes(llvm::MutableArrayRef<uint8_t> storage) const; 87 88 size_t GetByteSize() const; 89 90 bool GetData(DataExtractor &data, size_t limit_byte_size = UINT32_MAX) const; 91 92 size_t GetAsMemoryData(void *dst, size_t dst_len, 93 lldb::ByteOrder dst_byte_order, Status &error) const; 94 95 bool IsZero() const; 96 Clear()97 void Clear() { 98 m_type = e_void; 99 m_integer.clearAllBits(); 100 } 101 GetTypeAsCString()102 const char *GetTypeAsCString() const { return GetValueTypeAsCString(m_type); } 103 104 void GetValue(Stream *s, bool show_type) const; 105 IsValid()106 bool IsValid() const { return (m_type >= e_int) && (m_type <= e_float); } 107 108 /// Convert to an integer with \p bits and the given signedness. 109 void TruncOrExtendTo(uint16_t bits, bool sign); 110 111 bool IntegralPromote(uint16_t bits, bool sign); 112 bool FloatPromote(const llvm::fltSemantics &semantics); 113 114 bool IsSigned() const; 115 bool MakeSigned(); 116 117 bool MakeUnsigned(); 118 119 static const char *GetValueTypeAsCString(Scalar::Type value_type); 120 121 // All operators can benefits from the implicit conversions that will happen 122 // automagically by the compiler, so no temporary objects will need to be 123 // created. As a result, we currently don't need a variety of overloaded set 124 // value accessors. 125 Scalar &operator+=(Scalar rhs); 126 Scalar &operator<<=(const Scalar &rhs); // Shift left 127 Scalar &operator>>=(const Scalar &rhs); // Shift right (arithmetic) 128 Scalar &operator&=(const Scalar &rhs); 129 130 // Shifts the current value to the right without maintaining the current sign 131 // of the value (if it is signed). 132 bool ShiftRightLogical(const Scalar &rhs); // Returns true on success 133 134 // Takes the absolute value of the current value if it is signed, else the 135 // value remains unchanged. Returns false if the contained value has a void 136 // type. 137 bool AbsoluteValue(); // Returns true on success 138 // Negates the current value (even for unsigned values). Returns false if the 139 // contained value has a void type. 140 bool UnaryNegate(); // Returns true on success 141 // Inverts all bits in the current value as long as it isn't void or a 142 // float/double/long double type. Returns false if the contained value has a 143 // void/float/double/long double type, else the value is inverted and true is 144 // returned. 145 bool OnesComplement(); // Returns true on success 146 147 // Access the type of the current value. GetType()148 Scalar::Type GetType() const { return m_type; } 149 150 // Returns a casted value of the current contained data without modifying the 151 // current value. FAIL_VALUE will be returned if the type of the value is 152 // void or invalid. 153 int SInt(int fail_value = 0) const; 154 155 unsigned char UChar(unsigned char fail_value = 0) const; 156 157 signed char SChar(signed char fail_value = 0) const; 158 159 unsigned short UShort(unsigned short fail_value = 0) const; 160 161 short SShort(short fail_value = 0) const; 162 163 unsigned int UInt(unsigned int fail_value = 0) const; 164 165 long SLong(long fail_value = 0) const; 166 167 unsigned long ULong(unsigned long fail_value = 0) const; 168 169 long long SLongLong(long long fail_value = 0) const; 170 171 unsigned long long ULongLong(unsigned long long fail_value = 0) const; 172 173 llvm::APInt SInt128(const llvm::APInt &fail_value) const; 174 175 llvm::APInt UInt128(const llvm::APInt &fail_value) const; 176 177 float Float(float fail_value = 0.0f) const; 178 179 double Double(double fail_value = 0.0) const; 180 181 long double LongDouble(long double fail_value = 0.0) const; 182 183 Status SetValueFromCString(const char *s, lldb::Encoding encoding, 184 size_t byte_size); 185 186 Status SetValueFromData(const DataExtractor &data, lldb::Encoding encoding, 187 size_t byte_size); 188 189 protected: 190 Scalar::Type m_type; 191 llvm::APSInt m_integer; 192 llvm::APFloat m_float; 193 194 template <typename T> T GetAs(T fail_value) const; 195 196 static Type PromoteToMaxType(Scalar &lhs, Scalar &rhs); 197 198 using PromotionKey = std::tuple<Type, unsigned, bool>; 199 PromotionKey GetPromoKey() const; 200 201 static PromotionKey GetFloatPromoKey(const llvm::fltSemantics &semantics); 202 203 private: 204 friend const Scalar operator+(const Scalar &lhs, const Scalar &rhs); 205 friend const Scalar operator-(Scalar lhs, Scalar rhs); 206 friend const Scalar operator/(Scalar lhs, Scalar rhs); 207 friend const Scalar operator*(Scalar lhs, Scalar rhs); 208 friend const Scalar operator&(Scalar lhs, Scalar rhs); 209 friend const Scalar operator|(Scalar lhs, Scalar rhs); 210 friend const Scalar operator%(Scalar lhs, Scalar rhs); 211 friend const Scalar operator^(Scalar lhs, Scalar rhs); 212 friend const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); 213 friend const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); 214 friend bool operator==(Scalar lhs, Scalar rhs); 215 friend bool operator!=(const Scalar &lhs, const Scalar &rhs); 216 friend bool operator<(Scalar lhs, Scalar rhs); 217 friend bool operator<=(const Scalar &lhs, const Scalar &rhs); 218 friend bool operator>(const Scalar &lhs, const Scalar &rhs); 219 friend bool operator>=(const Scalar &lhs, const Scalar &rhs); 220 }; 221 222 // Split out the operators into a format where the compiler will be able to 223 // implicitly convert numbers into Scalar objects. 224 // 225 // This allows code like: 226 // Scalar two(2); 227 // Scalar four = two * 2; 228 // Scalar eight = 2 * four; // This would cause an error if the 229 // // operator* was implemented as a 230 // // member function. 231 // SEE: 232 // Item 19 of "Effective C++ Second Edition" by Scott Meyers 233 // Differentiate among members functions, non-member functions, and 234 // friend functions 235 const Scalar operator+(const Scalar &lhs, const Scalar &rhs); 236 const Scalar operator-(Scalar lhs, Scalar rhs); 237 const Scalar operator/(Scalar lhs, Scalar rhs); 238 const Scalar operator*(Scalar lhs, Scalar rhs); 239 const Scalar operator&(Scalar lhs, Scalar rhs); 240 const Scalar operator|(Scalar lhs, Scalar rhs); 241 const Scalar operator%(Scalar lhs, Scalar rhs); 242 const Scalar operator^(Scalar lhs, Scalar rhs); 243 const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); 244 const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); 245 bool operator==(Scalar lhs, Scalar rhs); 246 bool operator!=(const Scalar &lhs, const Scalar &rhs); 247 bool operator<(Scalar lhs, Scalar rhs); 248 bool operator<=(const Scalar &lhs, const Scalar &rhs); 249 bool operator>(const Scalar &lhs, const Scalar &rhs); 250 bool operator>=(const Scalar &lhs, const Scalar &rhs); 251 252 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Scalar &scalar); 253 254 } // namespace lldb_private 255 256 #endif // LLDB_UTILITY_SCALAR_H 257