ROSE 0.11.145.147
RegisterDescriptor.h
1#ifndef ROSE_BinaryAnalysis_RegisterDescriptor_H
2#define ROSE_BinaryAnalysis_RegisterDescriptor_H
3#include <featureTests.h>
4#ifdef ROSE_ENABLE_BINARY_ANALYSIS
5
6#include <Sawyer/Interval.h>
7#include <boost/serialization/access.hpp>
8
9namespace Rose {
10namespace BinaryAnalysis {
11
29 // The major, minor, offset, and size are packed together into this single data member.
30 //
31 // + The major number is the high order four bits at position 28-31 (inclusive) with bit #0 being the LSB.
32 // + The minor number is the 10 bits at position 18-27.
33 // + The offset is the 9 bits at position 9-17, but see note below and offset in [0,511].
34 // + The width-1 is the 9 bits at position 0-8, but see note below and width in [1,512].
35 //
36 // We need to be able to store a width of zero in order to distinguish between valid descriptors and invalid (default
37 // constructed) descriptors, but there aren't enough bits in the width field by itself to do that. We also need to be able
38 // to store and retrive the full range of major, minor, and offset values for zero-width descriptors. To accomplish that,
39 // we use the invarant that the offset+width of a valid descriptor cannot exceed 512 bits. Therefore, if the width field
40 // plus offset field equals 512 then the actual offset is as specified in the range [1,511] and the actual offset is zero;
41 // and if the offset field is 2 and the width field is 511 (the EMPTY_PATTERN constant) then the actual offset and actual
42 // width are both zero.
43 //
44 // There are still unused bit combinations that we could use to extend the ranges of any of the four fields. For instance,
45 // we don't necessarily need to align the fields on bit boundaries. We could use the fact that registers of size R bits need
46 // (R+1)*R/2 values to represent all combinations of offset and size, although this requires integer division to retrieve
47 // the values.
48 uint32_t data_;
49
50 // This pattern represents major=0, minor=0, offset=0, width=0 (offset field = 2, width field = 511)
51 static const uint32_t EMPTY_PATTERN = 0x000005ff; // EMPTY_PATTERN & ~OFFSET_WIDTH_MASK == 0
52 static const uint32_t OFFSET_WIDTH_MASK = 0x0003ffff; // 9-bit offset and 9-bit width
53
54#ifdef ROSE_HAVE_BOOST_SERIALIZATION_LIB
55private:
56 friend class boost::serialization::access;
57
58 template<class S>
59 void serialize(S &s, const unsigned /*version*/) {
60 s & BOOST_SERIALIZATION_NVP(data_);
61 }
62#endif
63
64public:
69 : data_(EMPTY_PATTERN) {}
70
75 RegisterDescriptor(unsigned majr, unsigned minr, size_t offset, size_t width)
76 : data_(0) {
77 majorNumber(majr);
78 minorNumber(minr);
79 setOffsetWidth(offset, width);
80 }
81
83 static RegisterDescriptor fromRaw(uint32_t raw) {
84 RegisterDescriptor retval;
85 retval.data_ = raw;
86 return retval;
87 }
88
94 unsigned majorNumber() const {
95 return data_ >> 28; // bits 28-31 (4 bits)
96 }
97 void majorNumber(unsigned);
106 unsigned minorNumber() const {
107 return (data_ >> 18) & 0x3ff; // bits 18-27 (10 bits)
108 }
109 void minorNumber(unsigned);
122 inline size_t offset() const {
123 if ((data_ & OFFSET_WIDTH_MASK) == EMPTY_PATTERN)
124 return 0;
125 unsigned offsetField = (data_ >> 9) & 0x1ff; // bits 9-17 (9 bits)
126 unsigned widthField = data_ & 0x1ff; // bits 0-8 (9 bits)
127 if (offsetField + widthField == 512)
128 return offsetField;
129 return offsetField;
130 }
131 void offset(size_t);
141 inline size_t nBits() const {
142 if ((data_ & OFFSET_WIDTH_MASK) == EMPTY_PATTERN)
143 return 0;
144 unsigned offsetField = (data_ >> 9) & 0x1ff; // bits 9-17 (9 bits)
145 unsigned widthField = data_ & 0x1ff; // bits 0-8 (9 bits)
146 if (offsetField + widthField == 512)
147 return 0;
148 return widthField + 1;
149 }
150 void nBits(size_t);
158 if (const size_t n = nBits()) {
160 } else {
161 return {};
162 }
163 }
164
173 void setOffsetWidth(size_t offset, size_t nBits);
174
178 bool isEmpty() const {
179 return 0 == nBits();
180 }
181
185 bool isValid() const {
186 return nBits() != 0;
187 }
188
192 uint32_t raw() const {
193 return data_;
194 }
195 void raw(uint32_t r) {
196 data_ = r;
197 }
200 // The following trickery is to have something like "explicit operator bool" before C++11
201private:
202 typedef void(RegisterDescriptor::*unspecified_bool)() const;
203 void this_type_does_not_support_comparisons() const {}
204public:
205 operator unspecified_bool() const {
206 return isEmpty() ? 0 : &RegisterDescriptor::this_type_does_not_support_comparisons;
207 }
208
214 bool operator<(RegisterDescriptor other) const {
215 return data_ < other.data_;
216 }
217
222 bool operator==(RegisterDescriptor other) const {
223 return data_ == other.data_;
224 }
225
230 bool operator!=(RegisterDescriptor other) const {
231 return data_ != other.data_;
232 }
233
240
243
247 unsigned hash() const {
248 return data_;
249 }
250
252 void print(std::ostream &o) const {
253 o <<"{" <<majorNumber() <<"," <<minorNumber() <<"," <<offset() <<"," <<nBits() <<"}";
254 }
255
257 std::string toString() const;
258
259 friend std::ostream& operator<<(std::ostream&, RegisterDescriptor);
260
262 // Old interface (not deprecated yet, just implemented in terms of the new interface)
264
265 unsigned get_major() const {
266 return majorNumber();
267 }
268 bool is_valid() const {
269 return !isEmpty();
270 }
271 RegisterDescriptor &set_major(unsigned majr) {
272 majorNumber(majr);
273 return *this;
274 }
275 unsigned get_minor() const {
276 return minorNumber();
277 }
278 RegisterDescriptor &set_minor(unsigned minr) {
279 this->minorNumber(minr);
280 return *this;
281 }
282 unsigned get_offset() const {
283 return offset();
284 }
285 RegisterDescriptor &set_offset(unsigned offset) {
286 this->offset(offset);
287 return *this;
288 }
289 unsigned get_nbits() const {
290 return nBits();
291 }
292 RegisterDescriptor &set_nbits(unsigned nbits) {
293 this->nBits(nbits);
294 return *this;
295 }
296};
297
298} // namespace
299} // namespace
300
301#endif
302#endif
Describes (part of) a physical CPU register.
bool operator<(RegisterDescriptor other) const
Compare two descriptors.
void raw(uint32_t r)
The raw value of the descriptor.
static RegisterDescriptor fromRaw(uint32_t raw)
Construct a descriptor from a raw value.
void offset(size_t)
Property: Offset to least-significant bit.
bool operator==(RegisterDescriptor other) const
Check descriptors for equality.
void nBits(size_t)
Property: Size in bits.
void majorNumber(unsigned)
Property: Major number.
bool operator!=(RegisterDescriptor other) const
Check descriptors for inequality.
RegisterDescriptor(unsigned majr, unsigned minr, size_t offset, size_t width)
Construct a descriptor from its constituent parts.
RegisterDescriptor()
Create an empty register descriptor.
RegisterDescriptor operator&(RegisterDescriptor other) const
Compute the intersection of two regiter descriptors.
std::string toString() const
Show the properties as a string.
size_t offset() const
Property: Offset to least-significant bit.
void print(std::ostream &o) const
Print all properties.
bool isSubsetOf(RegisterDescriptor other) const
True if this descriptor is a subset of the specified descriptor.
void setOffsetWidth(size_t offset, size_t nBits)
Set offset and size at the same time.
unsigned minorNumber() const
Property: Minor number.
uint32_t raw() const
The raw value of the descriptor.
Sawyer::Container::Interval< size_t > bits() const
Bit range.
bool isEmpty() const
Predicate returns true if the width is zero.
bool isValid() const
Predicate returns true if width is non-zero.
void minorNumber(unsigned)
Property: Minor number.
unsigned majorNumber() const
Property: Major number.
size_t nBits() const
Property: Size in bits.
Range of values delimited by endpoints.
Definition Interval.h:31
static Interval baseSize(T lo, T size)
Construct an interval from one endpoint and a size.
Definition Interval.h:173
The ROSE library.