ROSE  0.11.51.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);
160  void setOffsetWidth(size_t offset, size_t nBits);
161 
165  bool isEmpty() const {
166  return 0 == nBits();
167  }
168 
172  bool isValid() const {
173  return nBits() != 0;
174  }
175 
179  uint32_t raw() const {
180  return data_;
181  }
182  void raw(uint32_t r) {
183  data_ = r;
184  }
187  // The following trickery is to have something like "explicit operator bool" before C++11
188 private:
189  typedef void(RegisterDescriptor::*unspecified_bool)() const;
190  void this_type_does_not_support_comparisons() const {}
191 public:
192  operator unspecified_bool() const {
193  return isEmpty() ? 0 : &RegisterDescriptor::this_type_does_not_support_comparisons;
194  }
195 
201  bool operator<(RegisterDescriptor other) const {
202  return data_ < other.data_;
203  }
204 
209  bool operator==(RegisterDescriptor other) const {
210  return data_ == other.data_;
211  }
212 
217  bool operator!=(RegisterDescriptor other) const {
218  return data_ != other.data_;
219  }
220 
224  unsigned hash() const {
225  return data_;
226  }
227 
229  void print(std::ostream &o) const {
230  o <<"{" <<majorNumber() <<"," <<minorNumber() <<"," <<offset() <<"," <<nBits() <<"}";
231  }
232 
234  std::string toString() const;
235 
236  friend std::ostream& operator<<(std::ostream&, RegisterDescriptor);
237 
239  // Old interface (not deprecated yet, just implemented in terms of the new interface)
241 
242  unsigned get_major() const {
243  return majorNumber();
244  }
245  bool is_valid() const {
246  return !isEmpty();
247  }
248  RegisterDescriptor &set_major(unsigned majr) {
249  majorNumber(majr);
250  return *this;
251  }
252  unsigned get_minor() const {
253  return minorNumber();
254  }
255  RegisterDescriptor &set_minor(unsigned minr) {
256  this->minorNumber(minr);
257  return *this;
258  }
259  unsigned get_offset() const {
260  return offset();
261  }
262  RegisterDescriptor &set_offset(unsigned offset) {
263  this->offset(offset);
264  return *this;
265  }
266  unsigned get_nbits() const {
267  return nBits();
268  }
269  RegisterDescriptor &set_nbits(unsigned nbits) {
270  this->nBits(nbits);
271  return *this;
272  }
273 };
274 
275 } // namespace
276 } // namespace
277 
278 #endif
279 #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.
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.
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.