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