/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Utility/Scalar.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #define NUM_OF_WORDS_INT128 2 |
28 | 0 | #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 | 3.58M | static llvm::APSInt MakeAPSInt(T v) { |
37 | 3.58M | static_assert(std::is_integral<T>::value); |
38 | 3.58M | static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); |
39 | 3.58M | return llvm::APSInt( |
40 | 3.58M | llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), |
41 | 3.58M | std::is_unsigned<T>::value); |
42 | 3.58M | } llvm::APSInt lldb_private::Scalar::MakeAPSInt<int>(int) Line | Count | Source | 36 | 135k | static llvm::APSInt MakeAPSInt(T v) { | 37 | 135k | static_assert(std::is_integral<T>::value); | 38 | 135k | static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); | 39 | 135k | return llvm::APSInt( | 40 | 135k | llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), | 41 | 135k | std::is_unsigned<T>::value); | 42 | 135k | } |
llvm::APSInt lldb_private::Scalar::MakeAPSInt<unsigned int>(unsigned int) Line | Count | Source | 36 | 47.6k | static llvm::APSInt MakeAPSInt(T v) { | 37 | 47.6k | static_assert(std::is_integral<T>::value); | 38 | 47.6k | static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); | 39 | 47.6k | return llvm::APSInt( | 40 | 47.6k | llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), | 41 | 47.6k | std::is_unsigned<T>::value); | 42 | 47.6k | } |
llvm::APSInt lldb_private::Scalar::MakeAPSInt<long>(long) Line | Count | Source | 36 | 188 | static llvm::APSInt MakeAPSInt(T v) { | 37 | 188 | static_assert(std::is_integral<T>::value); | 38 | 188 | static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); | 39 | 188 | return llvm::APSInt( | 40 | 188 | llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), | 41 | 188 | std::is_unsigned<T>::value); | 42 | 188 | } |
llvm::APSInt lldb_private::Scalar::MakeAPSInt<unsigned long>(unsigned long) Line | Count | Source | 36 | 1.55M | static llvm::APSInt MakeAPSInt(T v) { | 37 | 1.55M | static_assert(std::is_integral<T>::value); | 38 | 1.55M | static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); | 39 | 1.55M | return llvm::APSInt( | 40 | 1.55M | llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), | 41 | 1.55M | std::is_unsigned<T>::value); | 42 | 1.55M | } |
llvm::APSInt lldb_private::Scalar::MakeAPSInt<long long>(long long) Line | Count | Source | 36 | 13.0k | static llvm::APSInt MakeAPSInt(T v) { | 37 | 13.0k | static_assert(std::is_integral<T>::value); | 38 | 13.0k | static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); | 39 | 13.0k | return llvm::APSInt( | 40 | 13.0k | llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), | 41 | 13.0k | std::is_unsigned<T>::value); | 42 | 13.0k | } |
llvm::APSInt lldb_private::Scalar::MakeAPSInt<unsigned long long>(unsigned long long) Line | Count | Source | 36 | 1.83M | static llvm::APSInt MakeAPSInt(T v) { | 37 | 1.83M | static_assert(std::is_integral<T>::value); | 38 | 1.83M | static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); | 39 | 1.83M | return llvm::APSInt( | 40 | 1.83M | llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed<T>::value), | 41 | 1.83M | std::is_unsigned<T>::value); | 42 | 1.83M | } |
|
43 | | |
44 | | public: |
45 | | enum Type { |
46 | | e_void = 0, |
47 | | e_int, |
48 | | e_float, |
49 | | }; |
50 | | |
51 | | // Constructors and Destructors |
52 | 2.18M | Scalar() : m_float(0.0f) {} |
53 | 135k | Scalar(int v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
54 | | Scalar(unsigned int v) |
55 | 47.6k | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
56 | 188 | Scalar(long v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
57 | | Scalar(unsigned long v) |
58 | 1.55M | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
59 | | Scalar(long long v) |
60 | 13.0k | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
61 | | Scalar(unsigned long long v) |
62 | 1.83M | : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} |
63 | 394 | Scalar(float v) : m_type(e_float), m_float(v) {} |
64 | 419 | Scalar(double v) : m_type(e_float), m_float(v) {} |
65 | 15 | Scalar(long double v) : m_type(e_float), m_float(double(v)) { |
66 | 15 | bool ignore; |
67 | 15 | m_float.convert(llvm::APFloat::x87DoubleExtended(), |
68 | 15 | llvm::APFloat::rmNearestTiesToEven, &ignore); |
69 | 15 | } |
70 | | Scalar(llvm::APInt v) |
71 | 839k | : m_type(e_int), m_integer(std::move(v), false), m_float(0.0f) {} |
72 | | Scalar(llvm::APSInt v) |
73 | 103 | : 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 | | |
97 | 7.25k | void Clear() { |
98 | 7.25k | m_type = e_void; |
99 | 7.25k | m_integer.clearAllBits(); |
100 | 7.25k | } |
101 | | |
102 | 2 | const char *GetTypeAsCString() const { return GetValueTypeAsCString(m_type); } |
103 | | |
104 | | void GetValue(Stream *s, bool show_type) const; |
105 | | |
106 | 43.1k | 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 | 391k | 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 = 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 |