1/*
2 * Copyright (c) 2016-2019 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2013 Advanced Micro Devices, Inc.
15 * All rights reserved
16 *.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Steve Reinhardt
41 *          Nathanael Premillieu
42 *          Rekai Gonzalez
43 */
44
45#ifndef __CPU__REG_CLASS_HH__
46#define __CPU__REG_CLASS_HH__
47
48#include <cassert>
49#include <cstddef>
50
51#include "arch/generic/types.hh"
52#include "arch/registers.hh"
53#include "config/the_isa.hh"
54
55/** Enumerate the classes of registers. */
56enum RegClass {
57    IntRegClass,        ///< Integer register
58    FloatRegClass,      ///< Floating-point register
59    /** Vector Register. */
60    VecRegClass,
61    /** Vector Register Native Elem lane. */
62    VecElemClass,
63    VecPredRegClass,
64    CCRegClass,         ///< Condition-code register
65    MiscRegClass        ///< Control (misc) register
66};
67
68/** Number of register classes.
69 * This value is not part of the enum, because putting it there makes the
70 * compiler complain about unhandled cases in some switch statements.
71 */
72const int NumRegClasses = MiscRegClass + 1;
73
74/** Register ID: describe an architectural register with its class and index.
75 * This structure is used instead of just the register index to disambiguate
76 * between different classes of registers. For example, a integer register with
77 * index 3 is represented by Regid(IntRegClass, 3).
78 */
79class RegId {
80  protected:
81    static const char* regClassStrings[];
82    RegClass regClass;
83    RegIndex regIdx;
84    ElemIndex elemIdx;
85    static constexpr size_t Scale = TheISA::NumVecElemPerVecReg;
86    int numPinnedWrites;
87
88    friend struct std::hash<RegId>;
89
90  public:
91    RegId() : RegId(IntRegClass, 0) {}
92
93    RegId(RegClass reg_class, RegIndex reg_idx)
94        : RegId(reg_class, reg_idx, ILLEGAL_ELEM_INDEX) {}
95
96    explicit RegId(RegClass reg_class, RegIndex reg_idx, ElemIndex elem_idx)
97        : regClass(reg_class), regIdx(reg_idx), elemIdx(elem_idx),
98          numPinnedWrites(0) {
99        if (elemIdx == ILLEGAL_ELEM_INDEX) {
100            panic_if(regClass == VecElemClass,
101                    "Creating vector physical index w/o element index");
102        } else {
103            panic_if(regClass != VecElemClass,
104                    "Creating non-vector physical index w/ element index");
105        }
106    }
107
108    bool operator==(const RegId& that) const {
109        return regClass == that.classValue() && regIdx == that.index()
110                                             && elemIdx == that.elemIndex();
111    }
112
113    bool operator!=(const RegId& that) const {
114        return !(*this==that);
115    }
116
117    /** Order operator.
118     * The order is required to implement maps with key type RegId
119     */
120    bool operator<(const RegId& that) const {
121        return regClass < that.classValue() ||
122            (regClass == that.classValue() && (
123                   regIdx < that.index() ||
124                   (regIdx == that.index() && elemIdx < that.elemIndex())));
125    }
126
127    /**
128     * Return true if this register can be renamed
129     */
130    bool isRenameable() const
131    {
132        return regClass != MiscRegClass;
133    }
134
135    /**
136     * Check if this is the zero register.
137     * Returns true if this register is a zero register (needs to have a
138     * constant zero value throughout the execution).
139     */
140
141    inline bool isZeroReg() const
142    {
143        return ((regClass == IntRegClass && regIdx == TheISA::ZeroReg) ||
144               (THE_ISA == ALPHA_ISA && regClass == FloatRegClass &&
145                regIdx == TheISA::ZeroReg));
146    }
147
148    /** @return true if it is an integer physical register. */
149    bool isIntReg() const { return regClass == IntRegClass; }
150
151    /** @return true if it is a floating-point physical register. */
152    bool isFloatReg() const { return regClass == FloatRegClass; }
153
154    /** @Return true if it is a  condition-code physical register. */
155    bool isVecReg() const { return regClass == VecRegClass; }
156
157    /** @Return true if it is a  condition-code physical register. */
158    bool isVecElem() const { return regClass == VecElemClass; }
159
160    /** @Return true if it is a predicate physical register. */
161    bool isVecPredReg() const { return regClass == VecPredRegClass; }
162
163    /** @Return true if it is a  condition-code physical register. */
164    bool isCCReg() const { return regClass == CCRegClass; }
165
166    /** @Return true if it is a  condition-code physical register. */
167    bool isMiscReg() const { return regClass == MiscRegClass; }
168
169    /**
170     * Return true if this register can be renamed
171     */
172    bool isRenameable()
173    {
174        return regClass != MiscRegClass;
175    }
176
177    /** Index accessors */
178    /** @{ */
179    const RegIndex& index() const { return regIdx; }
180    RegIndex& index() { return regIdx; }
181
182    /** Index flattening.
183     * Required to be able to use a vector for the register mapping.
184     */
185    inline RegIndex flatIndex() const
186    {
187        switch (regClass) {
188          case IntRegClass:
189          case FloatRegClass:
190          case VecRegClass:
191          case VecPredRegClass:
192          case CCRegClass:
193          case MiscRegClass:
194            return regIdx;
195          case VecElemClass:
196            return Scale*regIdx + elemIdx;
197        }
198        panic("Trying to flatten a register without class!");
199        return -1;
200    }
201    /** @} */
202
203    /** Elem accessor */
204    const RegIndex& elemIndex() const { return elemIdx; }
205    /** Class accessor */
206    const RegClass& classValue() const { return regClass; }
207    /** Return a const char* with the register class name. */
208    const char* className() const { return regClassStrings[regClass]; }
209
210    int getNumPinnedWrites() const { return numPinnedWrites; }
211    void setNumPinnedWrites(int num_writes) { numPinnedWrites = num_writes; }
212
213    friend std::ostream&
214    operator<<(std::ostream& os, const RegId& rid) {
215        return os << rid.className() << "{" << rid.index() << "}";
216    }
217};
218
219/** Physical register index type.
220 * Although the Impl might be a better for this, but there are a few classes
221 * that need this typedef yet are not templated on the Impl.
222 */
223using PhysRegIndex = short int;
224
225/** Physical register ID.
226 * Like a register ID but physical. The inheritance is private because the
227 * only relationship between this types is functional, and it is done to
228 * prevent code replication. */
229class PhysRegId : private RegId {
230  private:
231    PhysRegIndex flatIdx;
232    int numPinnedWritesToComplete;
233    bool pinned;
234
235  public:
236    explicit PhysRegId() : RegId(IntRegClass, -1), flatIdx(-1),
237                           numPinnedWritesToComplete(0)
238    {}
239
240    /** Scalar PhysRegId constructor. */
241    explicit PhysRegId(RegClass _regClass, PhysRegIndex _regIdx,
242              PhysRegIndex _flatIdx)
243        : RegId(_regClass, _regIdx), flatIdx(_flatIdx),
244          numPinnedWritesToComplete(0), pinned(false)
245    {}
246
247    /** Vector PhysRegId constructor (w/ elemIndex). */
248    explicit PhysRegId(RegClass _regClass, PhysRegIndex _regIdx,
249              ElemIndex elem_idx, PhysRegIndex flat_idx)
250        : RegId(_regClass, _regIdx, elem_idx), flatIdx(flat_idx),
251          numPinnedWritesToComplete(0), pinned(false)
252    {}
253
254    /** Visible RegId methods */
255    /** @{ */
256    using RegId::index;
257    using RegId::classValue;
258    using RegId::isZeroReg;
259    using RegId::className;
260    using RegId::elemIndex;
261     /** @} */
262    /**
263     * Explicit forward methods, to prevent comparisons of PhysRegId with
264     * RegIds.
265     */
266    /** @{ */
267    bool operator<(const PhysRegId& that) const {
268        return RegId::operator<(that);
269    }
270
271    bool operator==(const PhysRegId& that) const {
272        return RegId::operator==(that);
273    }
274
275    bool operator!=(const PhysRegId& that) const {
276        return RegId::operator!=(that);
277    }
278    /** @} */
279
280    /** @return true if it is an integer physical register. */
281    bool isIntPhysReg() const { return isIntReg(); }
282
283    /** @return true if it is a floating-point physical register. */
284    bool isFloatPhysReg() const { return isFloatReg(); }
285
286    /** @Return true if it is a  condition-code physical register. */
287    bool isCCPhysReg() const { return isCCReg(); }
288
289    /** @Return true if it is a vector physical register. */
290    bool isVectorPhysReg() const { return isVecReg(); }
291
292    /** @Return true if it is a vector element physical register. */
293    bool isVectorPhysElem() const { return isVecElem(); }
294
295    /** @return true if it is a vector predicate physical register. */
296    bool isVecPredPhysReg() const { return isVecPredReg(); }
297
298    /** @Return true if it is a  condition-code physical register. */
299    bool isMiscPhysReg() const { return isMiscReg(); }
300
301    /**
302     * Returns true if this register is always associated to the same
303     * architectural register.
304     */
305    bool isFixedMapping() const
306    {
307        return !isRenameable();
308    }
309
310    /** Flat index accessor */
311    const PhysRegIndex& flatIndex() const { return flatIdx; }
312
313    static PhysRegId elemId(PhysRegId* vid, ElemIndex elem)
314    {
315        assert(vid->isVectorPhysReg());
316        return PhysRegId(VecElemClass, vid->index(), elem);
317    }
318
319    int getNumPinnedWrites() const { return numPinnedWrites; }
320
321    void setNumPinnedWrites(int numWrites)
322    {
323        // An instruction with a pinned destination reg can get
324        // squashed. The numPinnedWrites counter may be zero when
325        // the squash happens but we need to know if the dest reg
326        // was pinned originally in order to reset counters properly
327        // for a possible re-rename using the same physical reg (which
328        // may be required in case of a mem access order violation).
329        pinned = (numWrites != 0);
330        numPinnedWrites = numWrites;
331    }
332
333    void decrNumPinnedWrites() { --numPinnedWrites; }
334    void incrNumPinnedWrites() { ++numPinnedWrites; }
335
336    bool isPinned() const { return pinned; }
337
338    int getNumPinnedWritesToComplete() const
339    {
340        return numPinnedWritesToComplete;
341    }
342
343    void setNumPinnedWritesToComplete(int numWrites)
344    {
345        numPinnedWritesToComplete = numWrites;
346    }
347
348    void decrNumPinnedWritesToComplete() { --numPinnedWritesToComplete; }
349    void incrNumPinnedWritesToComplete() { ++numPinnedWritesToComplete; }
350};
351
352using PhysRegIdPtr = PhysRegId*;
353
354namespace std
355{
356template<>
357struct hash<RegId>
358{
359    size_t operator()(const RegId& reg_id) const
360    {
361        // Extract unique integral values for the effective fields of a RegId.
362        const size_t flat_index = static_cast<size_t>(reg_id.flatIndex());
363        const size_t class_num = static_cast<size_t>(reg_id.regClass);
364
365        const size_t shifted_class_num = class_num << (sizeof(RegIndex) << 3);
366
367        // Concatenate the class_num to the end of the flat_index, in order to
368        // maximize information retained.
369        const size_t concatenated_hash = flat_index | shifted_class_num;
370
371        // If RegIndex is larger than size_t, then class_num will not be
372        // considered by this hash function, so we may wish to perform a
373        // different operation to include that information in the hash.
374        static_assert(sizeof(RegIndex) < sizeof(size_t),
375            "sizeof(RegIndex) should be less than sizeof(size_t)");
376
377        return concatenated_hash;
378    }
379};
380}
381
382#endif // __CPU__REG_CLASS_HH__
383