blob: cdefdb99b27a307bf5cd8a94f90db73d7b3761ba [file] [log] [blame]
/*
* Copyright (c) 2019-2021 Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GPU_COMPUTE_OPERAND_INFO_HH__
#define __GPU_COMPUTE_OPERAND_INFO_HH__
#include "arch/gpu_registers.hh"
#include "base/flags.hh"
#include "config/the_gpu_isa.hh"
namespace gem5
{
class OperandInfo
{
public:
OperandInfo() = delete;
OperandInfo(int opSelectorVal, int size, bool src, bool scalar_reg,
bool vector_reg, bool imm)
: _opSelectorVal(opSelectorVal), _size(size),
_numDWords(size <= 4 ? 1 : size / 4)
{
if (src)
flags.set(SRC);
if (scalar_reg)
flags.set(SCALAR_REG);
if (vector_reg)
flags.set(VECTOR_REG);
if (imm)
flags.set(IMMEDIATE);
if (TheGpuISA::isVccReg(opSelectorVal))
flags.set(VCC);
if (TheGpuISA::isExecMask(opSelectorVal))
flags.set(EXEC);
if (TheGpuISA::isFlatScratchReg(opSelectorVal))
flags.set(FLAT);
if (TheGpuISA::isLiteral(opSelectorVal))
flags.set(LITERAL);
if (TheGpuISA::isConstVal(opSelectorVal))
flags.set(CONSTANT);
if (TheGpuISA::isPosConstVal(opSelectorVal))
flags.set(POS_CONST);
}
int numRegisters() const { return _numDWords / TheGpuISA::RegSizeDWords; }
int sizeInDWords() const { return _numDWords; }
int size() const { return _size; }
// Certain opIdx's get changed in calls to opSelectorToRegIdx
// This avoids that by returning the exact value
int rawRegisterIndex() const { return _opSelectorVal; }
int
registerIndex(int numScalarRegs) const
{
// Some regs (i.e. VSRC, VDST) are explicitly declared as vectors
// as opposed to checking if it's a vector through a function call, so
// they don't have an offset applied and can be returned immediately
if (isVectorReg() && _opSelectorVal < TheGpuISA::REG_VGPR_MIN)
return _opSelectorVal;
return TheGpuISA::opSelectorToRegIdx(_opSelectorVal, numScalarRegs);
}
bool isSrc() const { return flags.isSet(SRC); }
bool isDst() const { return !flags.isSet(SRC); }
bool isImm() const { return flags.isSet(IMMEDIATE); }
bool isScalarReg() const { return flags.isSet(SCALAR_REG); }
bool isVectorReg() const { return flags.isSet(VECTOR_REG); }
bool isVcc() const { return flags.isSet(VCC); }
bool isExec() const { return flags.isSet(EXEC); }
bool isFlatScratch() const { return flags.isSet(FLAT); }
void
setVirtToPhysMapping(std::vector<int> v, std::vector<int> p)
{
_virtIndices = v;
_physIndices = p;
assert(_virtIndices.size() == _physIndices.size());
assert(_numDWords == _physIndices.size());
}
/**
* We typically only need the first virtual register for the operand
* regardless of its size.
*/
int virtIdx(int reg_num=0) const { return _virtIndices.at(reg_num); }
int physIdx(int reg_num=0) const { return _physIndices.at(reg_num); }
const std::vector<int>&
virtIndices() const
{
return _virtIndices;
}
const std::vector<int>&
physIndices() const
{
return _physIndices;
}
std::vector<int>&
bankReadCounts() const
{
return _bankReadCounts;
}
typedef uint32_t FlagsType;
typedef gem5::Flags<FlagsType> Flags;
private:
enum : FlagsType {
// If the operand is a src or not
SRC = 0x00000001,
// If the operand is a scalar or not
SCALAR_REG = 0x00000002,
// If the operand is a vector or not
VECTOR_REG = 0x00000004,
// If the operand is an immediate or not
IMMEDIATE = 0x00000008,
// If the operand is a VCC register
VCC = 0x00000010,
// If the operand is an EXEC register
EXEC = 0x00000020,
// If the operand is a FLAT/SCRATCH register
FLAT = 0x00000040,
// If the operand is a literal
LITERAL = 0x00000080,
// If the operand is a constant value
CONSTANT = 0x00000100,
// If the constant is positive or negative
POS_CONST = 0x00000200
};
Flags flags;
/**
* Value of the operand as used in registers.cc functions
*/
const int _opSelectorVal;
/**
* Size of the operand in bytes
*/
const int _size;
/**
* Size of operand in DWords
*/
const int _numDWords;
std::vector<int> _virtIndices;
std::vector<int> _physIndices;
/**
* The number of reads this operand will make to each bank.
*/
mutable std::vector<int> _bankReadCounts;
};
} // namespace gem5
#endif // __GPU_COMPUTE_OPERAND_INFO_H__