blob: 2145ee38a56a39892ae6e91152b88a7c757734fa [file] [log] [blame]
/*
* Copyright (c) 2015-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.
*/
#include "arch/amdgpu/vega/gpu_registers.hh"
namespace gem5
{
namespace VegaISA
{
std::string
opSelectorToRegSym(int idx, int numRegs)
{
std::string reg_sym;
// we have an SGPR
if (idx <= REG_SGPR_MAX) {
if (numRegs > 1)
reg_sym = "s[" + std::to_string(idx) + ":" +
std::to_string(idx + numRegs - 1) + "]";
else
reg_sym = "s" + std::to_string(idx);
return reg_sym;
} else if (idx >= REG_VGPR_MIN && idx <= REG_VGPR_MAX) {
if (numRegs > 1)
reg_sym = "v[" + std::to_string(idx - REG_VGPR_MIN) + ":" +
std::to_string(idx - REG_VGPR_MIN + numRegs - 1) + "]";
else
reg_sym = "v" + std::to_string(idx - REG_VGPR_MIN);
return reg_sym;
} else if (idx >= REG_INT_CONST_POS_MIN &&
idx <= REG_INT_CONST_POS_MAX) {
reg_sym = std::to_string(idx - REG_INT_CONST_POS_MIN + 1);
return reg_sym;
} else if (idx >= REG_INT_CONST_NEG_MIN &&
idx <= REG_INT_CONST_NEG_MAX) {
int inline_val = -1 - (idx - REG_INT_CONST_NEG_MIN);
reg_sym = std::to_string(inline_val);
return reg_sym;
}
switch (idx) {
case REG_FLAT_SCRATCH_LO:
reg_sym = "flat_scratch_lo";
break;
case REG_FLAT_SCRATCH_HI:
reg_sym = "flat_scratch_hi";
break;
case REG_VCC_LO:
reg_sym = "vcc";
break;
case REG_M0:
reg_sym = "m0";
break;
case REG_EXEC_LO:
reg_sym = "exec";
break;
case REG_ZERO:
reg_sym = "0";
break;
case REG_POS_HALF:
reg_sym = "0.5";
break;
case REG_NEG_HALF:
reg_sym = "-0.5";
break;
case REG_POS_ONE:
reg_sym = "1";
break;
case REG_NEG_ONE:
reg_sym = "-1";
break;
case REG_POS_TWO:
reg_sym = "2";
break;
case REG_NEG_TWO:
reg_sym = "-2";
break;
case REG_POS_FOUR:
reg_sym = "4";
break;
case REG_NEG_FOUR:
reg_sym = "-4";
break;
default:
fatal("VEGA ISA instruction has unknown register index %u\n", idx);
break;
}
return reg_sym;
}
int
opSelectorToRegIdx(int idx, int numScalarRegs)
{
int regIdx = -1;
if (idx <= REG_SGPR_MAX) {
regIdx = idx;
} else if (idx >= REG_VGPR_MIN && idx <= REG_VGPR_MAX) {
regIdx = idx - REG_VGPR_MIN;
} else if (idx == REG_VCC_LO) {
/**
* the VCC register occupies the two highest numbered
* SRF entries. VCC is typically indexed by specifying
* VCC_LO (simply called VCC) in the instruction encoding
* and reading it as a 64b value so we only return the
* index to the lower half of the VCC register.
*
* VCC_LO = s[NUM_SGPRS - 2]
* VCC_HI = s[NUM_SGPRS - 1]
*
*/
regIdx = numScalarRegs - 2;
} else if (idx == REG_VCC_HI) {
regIdx = numScalarRegs - 1;
} else if (idx == REG_FLAT_SCRATCH_LO) {
/**
* the FLAT_SCRATCH register occupies the two SRF entries
* just below VCC. FLAT_SCRATCH is typically indexed by
* specifying FLAT_SCRATCH_LO (simply called FLAT_SCRATCH)
* in the instruction encoding and reading it as a 64b value
* so we only return the index to the lower half of the
* FLAT_SCRATCH register.
*
* FLAT_SCRATCH_LO = s[NUM_SGPRS - 4]
* FLAT_SCRATCH_HI = s[NUM_SGPRS - 3]
*
*/
regIdx = numScalarRegs - 4;
} else if (idx == REG_FLAT_SCRATCH_HI) {
regIdx = numScalarRegs - 3;
} else if (idx == REG_EXEC_LO || idx == REG_EXEC_HI) {
/**
* If the operand is the EXEC mask we just return the op
* selector value indicating it is the EXEC mask, which is
* not part of any RF. Higher-level calls will understand
* that this resolves to a special system register, not an
* index into an RF.
*/
return idx;
}
return regIdx;
}
bool
isPosConstVal(int opIdx)
{
bool is_pos_const_val = (opIdx >= REG_INT_CONST_POS_MIN
&& opIdx <= REG_INT_CONST_POS_MAX);
return is_pos_const_val;
}
bool
isNegConstVal(int opIdx)
{
bool is_neg_const_val = (opIdx >= REG_INT_CONST_NEG_MIN
&& opIdx <= REG_INT_CONST_NEG_MAX);
return is_neg_const_val;
}
bool
isConstVal(int opIdx)
{
bool is_const_val = isPosConstVal(opIdx) || isNegConstVal(opIdx);
return is_const_val;
}
bool
isLiteral(int opIdx)
{
return opIdx == REG_SRC_LITERAL;
}
bool
isExecMask(int opIdx)
{
return opIdx == REG_EXEC_LO || opIdx == REG_EXEC_HI;
}
bool
isVccReg(int opIdx)
{
return opIdx == REG_VCC_LO || opIdx == REG_VCC_HI;
}
bool
isFlatScratchReg(int opIdx)
{
return opIdx == REG_FLAT_SCRATCH_LO || opIdx == REG_FLAT_SCRATCH_HI;
}
bool
isScalarReg(int opIdx)
{
// FLAT_SCRATCH and VCC are stored in an SGPR pair
if (opIdx <= REG_SGPR_MAX || opIdx == REG_FLAT_SCRATCH_LO ||
opIdx == REG_FLAT_SCRATCH_HI || opIdx == REG_VCC_LO ||
opIdx == REG_VCC_HI) {
return true;
}
return false;
}
bool
isVectorReg(int opIdx)
{
if (opIdx >= REG_VGPR_MIN && opIdx <= REG_VGPR_MAX)
return true;
return false;
}
} // namespace VegaISA
} // namespace gem5