tests: log_call is not returning any value
[gem5.git] / src / base / bitunion.hh
1 /*
2 * Copyright (c) 2007-2008 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef __BASE_BITUNION_HH__
30 #define __BASE_BITUNION_HH__
31
32 #include <functional>
33 #include <iostream>
34 #include <type_traits>
35 #include <typeinfo>
36
37 #include "base/bitfield.hh"
38
39 // The following implements the BitUnion system of defining bitfields
40 //on top of an underlying class. This is done through the pervasive use of
41 //both named and unnamed unions which all contain the same actual storage.
42 //Since they're unioned with each other, all of these storage locations
43 //overlap. This allows all of the bitfields to manipulate the same data
44 //without having to have access to each other. More details are provided with
45 //the individual components.
46
47 //This class wraps around another which defines getter/setter functions which
48 //manipulate the underlying data. The type of the underlying data and the type
49 //of the bitfield itself are inferred from the argument types of the setter
50 //function.
51 template<class Base>
52 class BitfieldTypeImpl : public Base
53 {
54 static_assert(std::is_empty<Base>::value,
55 "Bitfield base class must be empty.");
56
57 private:
58
59 struct TypeDeducer
60 {
61 template<typename>
62 struct T;
63
64 template<typename C, typename Type1, typename Type2>
65 struct T<void (C::*)(Type1 &, Type2)>
66 {
67 typedef Type1 Storage;
68 typedef Type2 Type;
69 };
70
71 struct Wrapper : public Base
72 {
73 using Base::setter;
74 };
75
76 typedef typename T<decltype(&Wrapper::setter)>::Storage Storage;
77 typedef typename T<decltype(&Wrapper::setter)>::Type Type;
78 };
79
80 protected:
81 typedef typename TypeDeducer::Storage Storage;
82 typedef typename TypeDeducer::Type Type;
83
84 Type getter(const Storage &storage) const = delete;
85 void setter(Storage &storage, Type val) = delete;
86
87 BitfieldTypeImpl() = default;
88 BitfieldTypeImpl(const BitfieldTypeImpl &) = default;
89
90 Storage __storage;
91
92 operator Type () const
93 {
94 return Base::getter(__storage);
95 }
96
97 Type
98 operator=(const Type val)
99 {
100 Base::setter(__storage, val);
101 return val;
102 }
103
104 Type
105 operator=(BitfieldTypeImpl<Base> const & other)
106 {
107 return *this = (Type)other;
108 }
109 };
110
111 //A wrapper for the above class which allows setting and getting.
112 template<class Base>
113 class BitfieldType : public BitfieldTypeImpl<Base>
114 {
115 protected:
116 using Impl = BitfieldTypeImpl<Base>;
117 using typename Impl::Type;
118
119 public:
120 BitfieldType() = default;
121 BitfieldType(const BitfieldType &) = default;
122
123 operator Type () const { return Impl::operator Type(); }
124 Type operator=(const Type val) { return Impl::operator=(val); }
125 Type
126 operator=(BitfieldType<Base> const & other)
127 {
128 return Impl::operator=(other);
129 }
130 };
131
132 //A wrapper which only supports getting.
133 template<class Base>
134 class BitfieldROType : public BitfieldTypeImpl<Base>
135 {
136 public:
137 using Impl = BitfieldTypeImpl<Base>;
138 using typename Impl::Type;
139
140 BitfieldROType() = default;
141 BitfieldROType(const BitfieldROType &) = default;
142
143 Type operator=(BitfieldROType<Base> const &other) = delete;
144 operator Type () const { return Impl::operator Type(); }
145 };
146
147 //A wrapper which only supports setting.
148 template <class Base>
149 class BitfieldWOType : public BitfieldTypeImpl<Base>
150 {
151 protected:
152 using Impl = BitfieldTypeImpl<Base>;
153 using typename Impl::Type;
154
155 public:
156 BitfieldWOType() = default;
157 BitfieldWOType(const BitfieldWOType &) = default;
158
159 Type operator=(const Type val) { return Impl::operator=(val); }
160 Type
161 operator=(BitfieldWOType<Base> const & other)
162 {
163 return Impl::operator=(other);
164 }
165 };
166
167 //This namespace is for classes which implement the backend of the BitUnion
168 //stuff. Don't use any of these directly.
169 namespace BitfieldBackend
170 {
171 template<class Storage, int first, int last>
172 class Unsigned
173 {
174 static_assert(first >= last,
175 "Bitfield ranges must be specified as <msb, lsb>");
176
177 protected:
178 uint64_t
179 getter(const Storage &storage) const
180 {
181 return bits(storage, first, last);
182 }
183
184 void
185 setter(Storage &storage, uint64_t val)
186 {
187 replaceBits(storage, first, last, val);
188 }
189 };
190
191 template<class Storage, int first, int last>
192 class Signed
193 {
194 static_assert(first >= last,
195 "Bitfield ranges must be specified as <msb, lsb>");
196
197 protected:
198 int64_t
199 getter(const Storage &storage) const
200 {
201 return sext<first - last + 1>(bits(storage, first, last));
202 }
203
204 void
205 setter(Storage &storage, int64_t val)
206 {
207 replaceBits(storage, first, last, val);
208 }
209 };
210
211 //This class contains the basic bitfield types which are automatically
212 //available within a BitUnion. They inherit their Storage type from the
213 //containing BitUnion.
214 template<class Storage>
215 class BitfieldTypes
216 {
217 protected:
218
219 template<int first, int last=first>
220 using Bitfield = BitfieldType<Unsigned<Storage, first, last> >;
221 template<int first, int last=first>
222 using BitfieldRO =
223 BitfieldROType<Unsigned<Storage, first, last> >;
224 template<int first, int last=first>
225 using BitfieldWO =
226 BitfieldWOType<Unsigned<Storage, first, last> >;
227
228 template<int first, int last=first>
229 using SignedBitfield =
230 BitfieldType<Signed<Storage, first, last> >;
231 template<int first, int last=first>
232 using SignedBitfieldRO =
233 BitfieldROType<Signed<Storage, first, last> >;
234 template<int first, int last=first>
235 using SignedBitfieldWO =
236 BitfieldWOType<Signed<Storage, first, last> >;
237 };
238
239 //When a BitUnion is set up, an underlying class is created which holds
240 //the actual union. This class then inherits from it, and provids the
241 //implementations for various operators. Setting things up this way
242 //prevents having to redefine these functions in every different BitUnion
243 //type. More operators could be implemented in the future, as the need
244 //arises.
245 template <class Base>
246 class BitUnionOperators : public Base
247 {
248 static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
249 "BitUnion larger than its storage type.");
250
251 public:
252 BitUnionOperators(typename Base::__StorageType const &val)
253 {
254 Base::__storage = val;
255 }
256
257 BitUnionOperators(const BitUnionOperators &) = default;
258
259 BitUnionOperators() {}
260
261 operator const typename Base::__StorageType () const
262 {
263 return Base::__storage;
264 }
265
266 typename Base::__StorageType
267 operator=(typename Base::__StorageType const &val)
268 {
269 Base::__storage = val;
270 return val;
271 }
272
273 typename Base::__StorageType
274 operator=(BitUnionOperators const &other)
275 {
276 Base::__storage = other;
277 return Base::__storage;
278 }
279
280 bool
281 operator<(Base const &base) const
282 {
283 return Base::__storage < base.__storage;
284 }
285
286 bool
287 operator==(Base const &base) const
288 {
289 return Base::__storage == base.__storage;
290 }
291 };
292 }
293
294 //This macro is a backend for other macros that specialize it slightly.
295 //First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
296 //sticks the class which has the actual union in it, which
297 //BitfieldOperators above inherits from. Putting these classes in a special
298 //namespace ensures that there will be no collisions with other names as long
299 //as the BitUnion names themselves are all distinct and nothing else uses
300 //the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
301 //creates a typedef of the "type" parameter called __StorageType. This allows
302 //the type to propagate outside of the macro itself in a controlled way.
303 //Finally, the base storage is defined which BitfieldOperators will refer to
304 //in the operators it defines. This macro is intended to be followed by
305 //bitfield definitions which will end up inside it's union. As explained
306 //above, these is overlayed the __storage member in its entirety by each of the
307 //bitfields which are defined in the union, creating shared storage with no
308 //overhead.
309 #define __BitUnion(type, name) \
310 class BitfieldUnderlyingClasses##name : \
311 public BitfieldBackend::BitfieldTypes<type> \
312 { \
313 protected: \
314 typedef type __StorageType; \
315 friend BitfieldBackend::BitUnionBaseType< \
316 BitfieldBackend::BitUnionOperators< \
317 BitfieldUnderlyingClasses##name> >; \
318 friend BitfieldBackend::BitUnionBaseType< \
319 BitfieldUnderlyingClasses##name>; \
320 public: \
321 union { \
322 type __storage;
323
324 //This closes off the class and union started by the above macro. It is
325 //followed by a typedef which makes "name" refer to a BitfieldOperator
326 //class inheriting from the class and union just defined, which completes
327 //building up the type for the user.
328 #define EndBitUnion(name) \
329 }; \
330 }; \
331 typedef BitfieldBackend::BitUnionOperators< \
332 BitfieldUnderlyingClasses##name> name;
333
334 //This sets up a bitfield which has other bitfields nested inside of it. The
335 //__storage member functions like the "underlying storage" of the top level
336 //BitUnion. Like everything else, it overlays with the top level storage, so
337 //making it a regular bitfield type makes the entire thing function as a
338 //regular bitfield when referred to by itself.
339 #define __SubBitUnion(name, fieldType, ...) \
340 class \
341 { \
342 public: \
343 union { \
344 fieldType<__VA_ARGS__> __storage;
345
346 //This closes off the union created above and gives it a name. Unlike the top
347 //level BitUnion, we're interested in creating an object instead of a type.
348 //The operators are defined in the macro itself instead of a class for
349 //technical reasons. If someone determines a way to move them to one, please
350 //do so.
351 #define EndSubBitUnion(name) \
352 }; \
353 inline operator __StorageType () const \
354 { return __storage; } \
355 \
356 inline __StorageType operator = (const __StorageType & _storage) \
357 { return __storage = _storage;} \
358 } name;
359
360 //Regular bitfields
361 //These define macros for read/write regular bitfield based subbitfields.
362 #define SubBitUnion(name, first, last) \
363 __SubBitUnion(name, Bitfield, first, last)
364
365 //Regular bitfields
366 //These define macros for read/write regular bitfield based subbitfields.
367 #define SignedSubBitUnion(name, first, last) \
368 __SubBitUnion(name, SignedBitfield, first, last)
369
370 //Use this to define an arbitrary type overlayed with bitfields.
371 #define BitUnion(type, name) __BitUnion(type, name)
372
373 //Use this to define conveniently sized values overlayed with bitfields.
374 #define BitUnion64(name) __BitUnion(uint64_t, name)
375 #define BitUnion32(name) __BitUnion(uint32_t, name)
376 #define BitUnion16(name) __BitUnion(uint16_t, name)
377 #define BitUnion8(name) __BitUnion(uint8_t, name)
378
379
380 //These templates make it possible to define other templates related to
381 //BitUnions without having to refer to internal typedefs or the BitfieldBackend
382 //namespace.
383
384 //To build a template specialization which works for all BitUnions, accept a
385 //template argument T, and then use BitUnionType<T> as an argument in the
386 //template. To refer to the basic type the BitUnion wraps, use
387 //BitUnionBaseType<T>.
388
389 //For example:
390 //template <typename T>
391 //void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
392
393 //Also, BitUnionBaseType can be used on a BitUnion type directly.
394
395 template <typename T>
396 using BitUnionType = BitfieldBackend::BitUnionOperators<T>;
397
398 namespace BitfieldBackend
399 {
400 template<typename T>
401 struct BitUnionBaseType
402 {
403 typedef typename BitUnionType<T>::__StorageType Type;
404 };
405
406 template<typename T>
407 struct BitUnionBaseType<BitUnionType<T> >
408 {
409 typedef typename BitUnionType<T>::__StorageType Type;
410 };
411 }
412
413 template <typename T>
414 using BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type;
415
416
417 //An STL style hash structure for hashing BitUnions based on their base type.
418 namespace std
419 {
420 template <typename T>
421 struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> >
422 {
423 size_t
424 operator() (const BitUnionType<T> &val) const
425 {
426 return hash<BitUnionBaseType<T> >::operator()(val);
427 }
428 };
429 }
430
431
432 namespace BitfieldBackend
433 {
434
435 template<typename T>
436 static inline std::ostream &
437 bitfieldBackendPrinter(std::ostream &os, const T &t)
438 {
439 os << t;
440 return os;
441 }
442
443 //Since BitUnions are generally numerical values and not character codes,
444 //these specializations attempt to ensure that they get cast to integers
445 //of the appropriate type before printing.
446 template <>
447 inline std::ostream &
448 bitfieldBackendPrinter(std::ostream &os, const char &t)
449 {
450 os << (int)t;
451 return os;
452 }
453
454 template <>
455 inline std::ostream &
456 bitfieldBackendPrinter(std::ostream &os, const unsigned char &t)
457 {
458 os << (unsigned int)t;
459 return os;
460 }
461 }
462
463 //A default << operator which casts a bitunion to its underlying type and
464 //passes it to BitfieldBackend::bitfieldBackendPrinter.
465 template <typename T>
466 std::ostream &
467 operator << (std::ostream &os, const BitUnionType<T> &bu)
468 {
469 return BitfieldBackend::bitfieldBackendPrinter(
470 os, (BitUnionBaseType<T>)bu);
471 }
472
473 #endif // __BASE_BITUNION_HH__