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 ; |
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> |
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 |
52 | Scalar() : m_float(0.0f) {} |
53 | Scalar(int v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
54 | Scalar(unsigned int v) |
55 | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
56 | Scalar(long v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
57 | Scalar(unsigned long v) |
58 | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
59 | Scalar(long long v) |
60 | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
61 | Scalar(unsigned long long v) |
62 | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
63 | Scalar(float v) : m_type(e_float), m_float(v) {} |
64 | Scalar(double v) : m_type(e_float), m_float(v) {} |
65 | Scalar(long double v) : m_type(e_float), m_float(double(v)) { |
66 | bool ignore; |
67 | m_float.convert(ToSemantics: llvm::APFloat::x87DoubleExtended(), |
68 | RM: llvm::APFloat::rmNearestTiesToEven, losesInfo: &ignore); |
69 | } |
70 | Scalar(llvm::APInt v) |
71 | : m_type(e_int), m_integer(std::move(v), false), m_float(0.0f) {} |
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 (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 (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 | |
97 | void Clear() { |
98 | m_type = e_void; |
99 | m_integer.clearAllBits(); |
100 | } |
101 | |
102 | const char *GetTypeAsCString() const { return GetValueTypeAsCString(value_type: m_type); } |
103 | |
104 | void GetValue(Stream &s, bool show_type) const; |
105 | |
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. |
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 (const DataExtractor &data, lldb::Encoding encoding, |
187 | size_t byte_size); |
188 | |
189 | protected: |
190 | Scalar::Type m_type = e_void; |
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 | |