reg_class.hh revision 14025
13457Sgblack@eecs.umich.edu/*
23457Sgblack@eecs.umich.edu * Copyright (c) 2016-2018 ARM Limited
33457Sgblack@eecs.umich.edu * All rights reserved
43457Sgblack@eecs.umich.edu *
53457Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
63457Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
73457Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
83457Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
93457Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
103457Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
113457Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
123457Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
133457Sgblack@eecs.umich.edu *
143457Sgblack@eecs.umich.edu * Copyright (c) 2013 Advanced Micro Devices, Inc.
153457Sgblack@eecs.umich.edu * All rights reserved
163457Sgblack@eecs.umich.edu *.
173457Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
183457Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
193457Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
203457Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
213457Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
223457Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
233457Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
243457Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
253457Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
263457Sgblack@eecs.umich.edu * this software without specific prior written permission.
273457Sgblack@eecs.umich.edu *
283457Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293457Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303457Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
315569Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
325569Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333457Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343457Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353457Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
365569Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
375569Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
385569Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
395569Snate@binkert.org *
405569Snate@binkert.org * Authors: Steve Reinhardt
415569Snate@binkert.org *          Nathanael Premillieu
425569Snate@binkert.org *          Rekai Gonzalez
435569Snate@binkert.org */
445569Snate@binkert.org
455569Snate@binkert.org#ifndef __CPU__REG_CLASS_HH__
465569Snate@binkert.org#define __CPU__REG_CLASS_HH__
475569Snate@binkert.org
485569Snate@binkert.org#include <cassert>
495569Snate@binkert.org#include <cstddef>
505569Snate@binkert.org
515569Snate@binkert.org#include "arch/generic/types.hh"
525569Snate@binkert.org#include "arch/registers.hh"
535569Snate@binkert.org#include "config/the_isa.hh"
545569Snate@binkert.org
555569Snate@binkert.org/** Enumerate the classes of registers. */
565569Snate@binkert.orgenum RegClass {
575569Snate@binkert.org    IntRegClass,        ///< Integer register
585569Snate@binkert.org    FloatRegClass,      ///< Floating-point register
595569Snate@binkert.org    /** Vector Register. */
605569Snate@binkert.org    VecRegClass,
615569Snate@binkert.org    /** Vector Register Native Elem lane. */
625569Snate@binkert.org    VecElemClass,
635569Snate@binkert.org    VecPredRegClass,
645569Snate@binkert.org    CCRegClass,         ///< Condition-code register
655569Snate@binkert.org    MiscRegClass        ///< Control (misc) register
665569Snate@binkert.org};
675569Snate@binkert.org
685569Snate@binkert.org/** Number of register classes.
695569Snate@binkert.org * This value is not part of the enum, because putting it there makes the
705569Snate@binkert.org * compiler complain about unhandled cases in some switch statements.
715569Snate@binkert.org */
725569Snate@binkert.orgconst int NumRegClasses = MiscRegClass + 1;
735569Snate@binkert.org
745569Snate@binkert.org/** Register ID: describe an architectural register with its class and index.
755569Snate@binkert.org * This structure is used instead of just the register index to disambiguate
765569Snate@binkert.org * between different classes of registers. For example, a integer register with
775569Snate@binkert.org * index 3 is represented by Regid(IntRegClass, 3).
785569Snate@binkert.org */
795569Snate@binkert.orgclass RegId {
805569Snate@binkert.org  protected:
815569Snate@binkert.org    static const char* regClassStrings[];
825569Snate@binkert.org    RegClass regClass;
835569Snate@binkert.org    RegIndex regIdx;
845569Snate@binkert.org    ElemIndex elemIdx;
855569Snate@binkert.org    static constexpr size_t Scale = TheISA::NumVecElemPerVecReg;
865569Snate@binkert.org    int numPinnedWrites;
875569Snate@binkert.org
885569Snate@binkert.org    friend struct std::hash<RegId>;
895569Snate@binkert.org
905569Snate@binkert.org  public:
915569Snate@binkert.org    RegId() : regClass(IntRegClass), regIdx(0), elemIdx(-1) {}
925569Snate@binkert.org    RegId(RegClass reg_class, RegIndex reg_idx)
935569Snate@binkert.org        : regClass(reg_class), regIdx(reg_idx), elemIdx(-1),
945569Snate@binkert.org          numPinnedWrites(0)
955569Snate@binkert.org    {
965569Snate@binkert.org        panic_if(regClass == VecElemClass,
975569Snate@binkert.org                "Creating vector physical index w/o element index");
985569Snate@binkert.org    }
995569Snate@binkert.org
1005569Snate@binkert.org    explicit RegId(RegClass reg_class, RegIndex reg_idx, ElemIndex elem_idx)
1015569Snate@binkert.org        : regClass(reg_class), regIdx(reg_idx), elemIdx(elem_idx),
1025569Snate@binkert.org          numPinnedWrites(0)
1035569Snate@binkert.org    {
1045569Snate@binkert.org        panic_if(regClass != VecElemClass,
1055569Snate@binkert.org                "Creating non-vector physical index w/ element index");
1065569Snate@binkert.org    }
1075569Snate@binkert.org
1085569Snate@binkert.org    bool operator==(const RegId& that) const {
1095569Snate@binkert.org        return regClass == that.classValue() && regIdx == that.index()
1105569Snate@binkert.org                                             && elemIdx == that.elemIndex();
1115569Snate@binkert.org    }
1125569Snate@binkert.org
1135569Snate@binkert.org    bool operator!=(const RegId& that) const {
1145569Snate@binkert.org        return !(*this==that);
1155569Snate@binkert.org    }
1165569Snate@binkert.org
1175569Snate@binkert.org    /** Order operator.
1185569Snate@binkert.org     * The order is required to implement maps with key type RegId
1195569Snate@binkert.org     */
1205569Snate@binkert.org    bool operator<(const RegId& that) const {
1215569Snate@binkert.org        return regClass < that.classValue() ||
1225569Snate@binkert.org            (regClass == that.classValue() && (
1235569Snate@binkert.org                   regIdx < that.index() ||
1245569Snate@binkert.org                   (regIdx == that.index() && elemIdx < that.elemIndex())));
1255569Snate@binkert.org    }
1265569Snate@binkert.org
1275569Snate@binkert.org    /**
1285569Snate@binkert.org     * Return true if this register can be renamed
1295569Snate@binkert.org     */
1303457Sgblack@eecs.umich.edu    bool isRenameable() const
1315569Snate@binkert.org    {
1325569Snate@binkert.org        return regClass != MiscRegClass;
1335569Snate@binkert.org    }
1343457Sgblack@eecs.umich.edu
1355569Snate@binkert.org    /**
1363457Sgblack@eecs.umich.edu     * Check if this is the zero register.
1375569Snate@binkert.org     * Returns true if this register is a zero register (needs to have a
1385569Snate@binkert.org     * constant zero value throughout the execution).
1393457Sgblack@eecs.umich.edu     */
1403457Sgblack@eecs.umich.edu
1415569Snate@binkert.org    inline bool isZeroReg() const
1425569Snate@binkert.org    {
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