ROSE  0.11.2.0
RegisterDescriptor.h
1 #ifndef Rose_BinaryAnalysis_RegisterDescriptor_H
2 #define Rose_BinaryAnalysis_RegisterDescriptor_H
3 
4 #include <rosePublicConfig.h>
5 #ifdef ROSE_BUILD_BINARY_ANALYSIS_SUPPORT
6 
7 #include <boost/serialization/access.hpp>
8 
9 namespace Rose {
10 namespace 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
55 private:
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 
64 public:
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 
87  unsigned majorNumber() const {
88  return data_ >> 28; // bits 28-31 (4 bits)
89  }
90  void majorNumber(unsigned);
99  unsigned minorNumber() const {
100  return (data_ >> 18) & 0x3ff; // bits 18-27 (10 bits)
101  }
102  void minorNumber(unsigned);
115  inline size_t offset() const {
116  if ((data_ & OFFSET_WIDTH_MASK) == EMPTY_PATTERN)
117  return 0;
118  unsigned offsetField = (data_ >> 9) & 0x1ff; // bits 9-17 (9 bits)
119  unsigned widthField = data_ & 0x1ff; // bits 0-8 (9 bits)
120  if (offsetField + widthField == 512)
121  return offsetField;
122  return offsetField;
123  }
124  void offset(size_t);
134  inline size_t nBits() const {
135  if ((data_ & OFFSET_WIDTH_MASK) == EMPTY_PATTERN)
136  return 0;
137  unsigned offsetField = (data_ >> 9) & 0x1ff; // bits 9-17 (9 bits)
138  unsigned widthField = data_ & 0x1ff; // bits 0-8 (9 bits)
139  if (offsetField + widthField == 512)
140  return 0;
141  return widthField + 1;
142  }
143  void nBits(size_t);
154  void setOffsetWidth(size_t offset, size_t nBits);
155 
159  bool isEmpty() const {
160  return 0 == nBits();
161  }
162 
166  bool isValid() const {
167  return nBits() != 0;
168  }
169 
170  // The following trickery is to have something like "explicit operator bool" before C++11
171 private:
172  typedef void(RegisterDescriptor::*unspecified_bool)() const;
173  void this_type_does_not_support_comparisons() const {}
174 public:
175  operator unspecified_bool() const {
176  return isEmpty() ? 0 : &RegisterDescriptor::this_type_does_not_support_comparisons;
177  }
178 
184  bool operator<(RegisterDescriptor other) const {
185  return data_ < other.data_;
186  }
187 
192  bool operator==(RegisterDescriptor other) const {
193  return data_ == other.data_;
194  }
195 
200  bool operator!=(RegisterDescriptor other) const {
201  return data_ != other.data_;
202  }
203 
207  unsigned hash() const {
208  return data_;
209  }
210 
212  void print(std::ostream &o) const {
213  o <<"{" <<majorNumber() <<"," <<minorNumber() <<"," <<offset() <<"," <<nBits() <<"}";
214  }
215 
216  friend std::ostream& operator<<(std::ostream&, RegisterDescriptor);
217 
219  // Old interface (not deprecated yet, just implemented in terms of the new interface)
221 
222  unsigned get_major() const {
223  return majorNumber();
224  }
225  bool is_valid() const {
226  return !isEmpty();
227  }
228  RegisterDescriptor &set_major(unsigned majr) {
229  majorNumber(majr);
230  return *this;
231  }
232  unsigned get_minor() const {
233  return minorNumber();
234  }
235  RegisterDescriptor &set_minor(unsigned minr) {
236  this->minorNumber(minr);
237  return *this;
238  }
239  unsigned get_offset() const {
240  return offset();
241  }
242  RegisterDescriptor &set_offset(unsigned offset) {
243  this->offset(offset);
244  return *this;
245  }
246  unsigned get_nbits() const {
247  return nBits();
248  }
249  RegisterDescriptor &set_nbits(unsigned nbits) {
250  this->nBits(nbits);
251  return *this;
252  }
253 };
254 
255 } // namespace
256 } // namespace
257 
258 #endif
259 #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.
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.
size_t offset() const
Property: Offset to least-significant bit.
bool isValid() const
Predicate returns true if width is non-zero.
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.