blob: 3132a425acd15283f9117b67acbc0fe2eab22d73 [file] [log] [blame]
/*
* Copyright (c) 2012-2015 Advanced Micro Devices, Inc.
* All rights reserved.
*
* For use for simulation and test purposes only
*
* 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.
*
* Author: Steve Reinhardt
*/
#ifndef __ARCH_HSAIL_INSTS_DECL_HH__
#define __ARCH_HSAIL_INSTS_DECL_HH__
#include <cmath>
#include "arch/hsail/insts/gpu_static_inst.hh"
#include "arch/hsail/operand.hh"
#include "debug/HSAIL.hh"
#include "gpu-compute/gpu_dyn_inst.hh"
#include "gpu-compute/shader.hh"
namespace HsailISA
{
template<typename _DestOperand, typename _SrcOperand>
class HsailOperandType
{
public:
typedef _DestOperand DestOperand;
typedef _SrcOperand SrcOperand;
};
typedef HsailOperandType<CRegOperand, CRegOrImmOperand> CRegOperandType;
typedef HsailOperandType<SRegOperand, SRegOrImmOperand> SRegOperandType;
typedef HsailOperandType<DRegOperand, DRegOrImmOperand> DRegOperandType;
// The IsBits parameter serves only to disambiguate tbhe B* types from
// the U* types, which otherwise would be identical (and
// indistinguishable).
template<typename _OperandType, typename _CType, Enums::MemType _memType,
vgpr_type _vgprType, int IsBits=0>
class HsailDataType
{
public:
typedef _OperandType OperandType;
typedef _CType CType;
static const Enums::MemType memType = _memType;
static const vgpr_type vgprType = _vgprType;
static const char *label;
};
typedef HsailDataType<CRegOperandType, bool, Enums::M_U8, VT_32, 1> B1;
typedef HsailDataType<SRegOperandType, uint8_t, Enums::M_U8, VT_32, 1> B8;
typedef HsailDataType<SRegOperandType, uint16_t,
Enums::M_U16, VT_32, 1> B16;
typedef HsailDataType<SRegOperandType, uint32_t,
Enums::M_U32, VT_32, 1> B32;
typedef HsailDataType<DRegOperandType, uint64_t,
Enums::M_U64, VT_64, 1> B64;
typedef HsailDataType<SRegOperandType, int8_t, Enums::M_S8, VT_32> S8;
typedef HsailDataType<SRegOperandType, int16_t, Enums::M_S16, VT_32> S16;
typedef HsailDataType<SRegOperandType, int32_t, Enums::M_S32, VT_32> S32;
typedef HsailDataType<DRegOperandType, int64_t, Enums::M_S64, VT_64> S64;
typedef HsailDataType<SRegOperandType, uint8_t, Enums::M_U8, VT_32> U8;
typedef HsailDataType<SRegOperandType, uint16_t, Enums::M_U16, VT_32> U16;
typedef HsailDataType<SRegOperandType, uint32_t, Enums::M_U32, VT_32> U32;
typedef HsailDataType<DRegOperandType, uint64_t, Enums::M_U64, VT_64> U64;
typedef HsailDataType<SRegOperandType, float, Enums::M_F32, VT_32> F32;
typedef HsailDataType<DRegOperandType, double, Enums::M_F64, VT_64> F64;
template<typename DestOperandType, typename SrcOperandType,
int NumSrcOperands>
class CommonInstBase : public HsailGPUStaticInst
{
protected:
typename DestOperandType::DestOperand dest;
typename SrcOperandType::SrcOperand src[NumSrcOperands];
void
generateDisassembly()
{
disassembly = csprintf("%s%s %s", opcode, opcode_suffix(),
dest.disassemble());
for (int i = 0; i < NumSrcOperands; ++i) {
disassembly += ",";
disassembly += src[i].disassemble();
}
}
virtual std::string opcode_suffix() = 0;
public:
CommonInstBase(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *opcode)
: HsailGPUStaticInst(obj, opcode)
{
setFlag(ALU);
unsigned op_offs = obj->getOperandPtr(ib->operands, 0);
dest.init(op_offs, obj);
for (int i = 0; i < NumSrcOperands; ++i) {
op_offs = obj->getOperandPtr(ib->operands, i + 1);
src[i].init(op_offs, obj);
}
}
bool isVectorRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex < NumSrcOperands)
return src[operandIndex].isVectorRegister();
else
return dest.isVectorRegister();
}
bool isCondRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex < NumSrcOperands)
return src[operandIndex].isCondRegister();
else
return dest.isCondRegister();
}
bool isScalarRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex < NumSrcOperands)
return src[operandIndex].isScalarRegister();
else
return dest.isScalarRegister();
}
bool isSrcOperand(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex < NumSrcOperands)
return true;
return false;
}
bool isDstOperand(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex >= NumSrcOperands)
return true;
return false;
}
int getOperandSize(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex < NumSrcOperands)
return src[operandIndex].opSize();
else
return dest.opSize();
}
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst)
{
assert(operandIndex >= 0 && operandIndex < getNumOperands());
if (operandIndex < NumSrcOperands)
return src[operandIndex].regIndex();
else
return dest.regIndex();
}
int numSrcRegOperands() {
int operands = 0;
for (int i = 0; i < NumSrcOperands; i++) {
if (src[i].isVectorRegister()) {
operands++;
}
}
return operands;
}
int numDstRegOperands() { return dest.isVectorRegister(); }
int getNumOperands() { return NumSrcOperands + 1; }
};
template<typename DataType, int NumSrcOperands>
class ArithInst : public CommonInstBase<typename DataType::OperandType,
typename DataType::OperandType,
NumSrcOperands>
{
public:
std::string opcode_suffix() { return csprintf("_%s", DataType::label); }
ArithInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *opcode)
: CommonInstBase<typename DataType::OperandType,
typename DataType::OperandType,
NumSrcOperands>(ib, obj, opcode)
{
}
};
template<typename DestOperandType, typename Src0OperandType,
typename Src1OperandType, typename Src2OperandType>
class ThreeNonUniformSourceInstBase : public HsailGPUStaticInst
{
protected:
typename DestOperandType::DestOperand dest;
typename Src0OperandType::SrcOperand src0;
typename Src1OperandType::SrcOperand src1;
typename Src2OperandType::SrcOperand src2;
void
generateDisassembly()
{
disassembly = csprintf("%s %s,%s,%s,%s", opcode, dest.disassemble(),
src0.disassemble(), src1.disassemble(),
src2.disassemble());
}
public:
ThreeNonUniformSourceInstBase(const Brig::BrigInstBase *ib,
const BrigObject *obj,
const char *opcode)
: HsailGPUStaticInst(obj, opcode)
{
setFlag(ALU);
unsigned op_offs = obj->getOperandPtr(ib->operands, 0);
dest.init(op_offs, obj);
op_offs = obj->getOperandPtr(ib->operands, 1);
src0.init(op_offs, obj);
op_offs = obj->getOperandPtr(ib->operands, 2);
src1.init(op_offs, obj);
op_offs = obj->getOperandPtr(ib->operands, 3);
src2.init(op_offs, obj);
}
bool isVectorRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.isVectorRegister();
else if (operandIndex == 1)
return src1.isVectorRegister();
else if (operandIndex == 2)
return src2.isVectorRegister();
else
return dest.isVectorRegister();
}
bool isCondRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.isCondRegister();
else if (operandIndex == 1)
return src1.isCondRegister();
else if (operandIndex == 2)
return src2.isCondRegister();
else
return dest.isCondRegister();
}
bool isScalarRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.isScalarRegister();
else if (operandIndex == 1)
return src1.isScalarRegister();
else if (operandIndex == 2)
return src2.isScalarRegister();
else
return dest.isScalarRegister();
}
bool isSrcOperand(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex < 3)
return true;
else
return false;
}
bool isDstOperand(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex >= 3)
return true;
else
return false;
}
int getOperandSize(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.opSize();
else if (operandIndex == 1)
return src1.opSize();
else if (operandIndex == 2)
return src2.opSize();
else
return dest.opSize();
}
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst)
{
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.regIndex();
else if (operandIndex == 1)
return src1.regIndex();
else if (operandIndex == 2)
return src2.regIndex();
else
return dest.regIndex();
}
int numSrcRegOperands() {
int operands = 0;
if (src0.isVectorRegister()) {
operands++;
}
if (src1.isVectorRegister()) {
operands++;
}
if (src2.isVectorRegister()) {
operands++;
}
return operands;
}
int numDstRegOperands() { return dest.isVectorRegister(); }
int getNumOperands() { return 4; }
};
template<typename DestDataType, typename Src0DataType,
typename Src1DataType, typename Src2DataType>
class ThreeNonUniformSourceInst :
public ThreeNonUniformSourceInstBase<typename DestDataType::OperandType,
typename Src0DataType::OperandType,
typename Src1DataType::OperandType,
typename Src2DataType::OperandType>
{
public:
typedef typename DestDataType::CType DestCType;
typedef typename Src0DataType::CType Src0CType;
typedef typename Src1DataType::CType Src1CType;
typedef typename Src2DataType::CType Src2CType;
ThreeNonUniformSourceInst(const Brig::BrigInstBase *ib,
const BrigObject *obj, const char *opcode)
: ThreeNonUniformSourceInstBase<typename DestDataType::OperandType,
typename Src0DataType::OperandType,
typename Src1DataType::OperandType,
typename Src2DataType::OperandType>(ib,
obj, opcode)
{
}
};
template<typename DataType>
class CmovInst : public ThreeNonUniformSourceInst<DataType, B1,
DataType, DataType>
{
public:
CmovInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *opcode)
: ThreeNonUniformSourceInst<DataType, B1, DataType,
DataType>(ib, obj, opcode)
{
}
};
template<typename DataType>
class ExtractInsertInst : public ThreeNonUniformSourceInst<DataType,
DataType, U32,
U32>
{
public:
ExtractInsertInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *opcode)
: ThreeNonUniformSourceInst<DataType, DataType, U32,
U32>(ib, obj, opcode)
{
}
};
template<typename DestOperandType, typename Src0OperandType,
typename Src1OperandType>
class TwoNonUniformSourceInstBase : public HsailGPUStaticInst
{
protected:
typename DestOperandType::DestOperand dest;
typename Src0OperandType::SrcOperand src0;
typename Src1OperandType::SrcOperand src1;
void
generateDisassembly()
{
disassembly = csprintf("%s %s,%s,%s", opcode, dest.disassemble(),
src0.disassemble(), src1.disassemble());
}
public:
TwoNonUniformSourceInstBase(const Brig::BrigInstBase *ib,
const BrigObject *obj, const char *opcode)
: HsailGPUStaticInst(obj, opcode)
{
setFlag(ALU);
unsigned op_offs = obj->getOperandPtr(ib->operands, 0);
dest.init(op_offs, obj);
op_offs = obj->getOperandPtr(ib->operands, 1);
src0.init(op_offs, obj);
op_offs = obj->getOperandPtr(ib->operands, 2);
src1.init(op_offs, obj);
}
bool isVectorRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.isVectorRegister();
else if (operandIndex == 1)
return src1.isVectorRegister();
else
return dest.isVectorRegister();
}
bool isCondRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.isCondRegister();
else if (operandIndex == 1)
return src1.isCondRegister();
else
return dest.isCondRegister();
}
bool isScalarRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.isScalarRegister();
else if (operandIndex == 1)
return src1.isScalarRegister();
else
return dest.isScalarRegister();
}
bool isSrcOperand(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex < 2)
return true;
else
return false;
}
bool isDstOperand(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (operandIndex >= 2)
return true;
else
return false;
}
int getOperandSize(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.opSize();
else if (operandIndex == 1)
return src1.opSize();
else
return dest.opSize();
}
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst)
{
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
if (!operandIndex)
return src0.regIndex();
else if (operandIndex == 1)
return src1.regIndex();
else
return dest.regIndex();
}
int numSrcRegOperands() {
int operands = 0;
if (src0.isVectorRegister()) {
operands++;
}
if (src1.isVectorRegister()) {
operands++;
}
return operands;
}
int numDstRegOperands() { return dest.isVectorRegister(); }
int getNumOperands() { return 3; }
};
template<typename DestDataType, typename Src0DataType,
typename Src1DataType>
class TwoNonUniformSourceInst :
public TwoNonUniformSourceInstBase<typename DestDataType::OperandType,
typename Src0DataType::OperandType,
typename Src1DataType::OperandType>
{
public:
typedef typename DestDataType::CType DestCType;
typedef typename Src0DataType::CType Src0CType;
typedef typename Src1DataType::CType Src1CType;
TwoNonUniformSourceInst(const Brig::BrigInstBase *ib,
const BrigObject *obj, const char *opcode)
: TwoNonUniformSourceInstBase<typename DestDataType::OperandType,
typename Src0DataType::OperandType,
typename Src1DataType::OperandType>(ib,
obj, opcode)
{
}
};
// helper function for ClassInst
template<typename T>
bool
fpclassify(T src0, uint32_t src1)
{
int fpclass = std::fpclassify(src0);
if ((src1 & 0x3) && (fpclass == FP_NAN)) {
return true;
}
if (src0 <= -0.0) {
if ((src1 & 0x4) && fpclass == FP_INFINITE)
return true;
if ((src1 & 0x8) && fpclass == FP_NORMAL)
return true;
if ((src1 & 0x10) && fpclass == FP_SUBNORMAL)
return true;
if ((src1 & 0x20) && fpclass == FP_ZERO)
return true;
} else {
if ((src1 & 0x40) && fpclass == FP_ZERO)
return true;
if ((src1 & 0x80) && fpclass == FP_SUBNORMAL)
return true;
if ((src1 & 0x100) && fpclass == FP_NORMAL)
return true;
if ((src1 & 0x200) && fpclass == FP_INFINITE)
return true;
}
return false;
}
template<typename DataType>
class ClassInst : public TwoNonUniformSourceInst<B1, DataType, U32>
{
public:
ClassInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *opcode)
: TwoNonUniformSourceInst<B1, DataType, U32>(ib, obj, opcode)
{
}
};
template<typename DataType>
class ShiftInst : public TwoNonUniformSourceInst<DataType, DataType, U32>
{
public:
ShiftInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *opcode)
: TwoNonUniformSourceInst<DataType, DataType, U32>(ib, obj, opcode)
{
}
};
// helper function for CmpInst
template<typename T>
bool
compare(T src0, T src1, Brig::BrigCompareOperation cmpOp)
{
using namespace Brig;
switch (cmpOp) {
case BRIG_COMPARE_EQ:
case BRIG_COMPARE_EQU:
case BRIG_COMPARE_SEQ:
case BRIG_COMPARE_SEQU:
return (src0 == src1);
case BRIG_COMPARE_NE:
case BRIG_COMPARE_NEU:
case BRIG_COMPARE_SNE:
case BRIG_COMPARE_SNEU:
return (src0 != src1);
case BRIG_COMPARE_LT:
case BRIG_COMPARE_LTU:
case BRIG_COMPARE_SLT:
case BRIG_COMPARE_SLTU:
return (src0 < src1);
case BRIG_COMPARE_LE:
case BRIG_COMPARE_LEU:
case BRIG_COMPARE_SLE:
case BRIG_COMPARE_SLEU:
return (src0 <= src1);
case BRIG_COMPARE_GT:
case BRIG_COMPARE_GTU:
case BRIG_COMPARE_SGT:
case BRIG_COMPARE_SGTU:
return (src0 > src1);
case BRIG_COMPARE_GE:
case BRIG_COMPARE_GEU:
case BRIG_COMPARE_SGE:
case BRIG_COMPARE_SGEU:
return (src0 >= src1);
case BRIG_COMPARE_NUM:
case BRIG_COMPARE_SNUM:
return (src0 == src0) || (src1 == src1);
case BRIG_COMPARE_NAN:
case BRIG_COMPARE_SNAN:
return (src0 != src0) || (src1 != src1);
default:
fatal("Bad cmpOp value %d\n", (int)cmpOp);
}
}
template<typename T>
int32_t
firstbit(T src0)
{
if (!src0)
return -1;
//handle positive and negative numbers
T tmp = ((int64_t)src0 < 0) ? (~src0) : (src0);
//the starting pos is MSB
int pos = 8 * sizeof(T) - 1;
int cnt = 0;
//search the first bit set to 1
while (!(tmp & (1 << pos))) {
++cnt;
--pos;
}
return cnt;
}
const char* cmpOpToString(Brig::BrigCompareOperation cmpOp);
template<typename DestOperandType, typename SrcOperandType>
class CmpInstBase : public CommonInstBase<DestOperandType, SrcOperandType,
2>
{
protected:
Brig::BrigCompareOperation cmpOp;
public:
CmpInstBase(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *_opcode)
: CommonInstBase<DestOperandType, SrcOperandType, 2>(ib, obj,
_opcode)
{
assert(ib->base.kind == Brig::BRIG_KIND_INST_CMP);
Brig::BrigInstCmp *i = (Brig::BrigInstCmp*)ib;
cmpOp = (Brig::BrigCompareOperation)i->compare;
}
};
template<typename DestDataType, typename SrcDataType>
class CmpInst : public CmpInstBase<typename DestDataType::OperandType,
typename SrcDataType::OperandType>
{
public:
std::string
opcode_suffix()
{
return csprintf("_%s_%s_%s", cmpOpToString(this->cmpOp),
DestDataType::label, SrcDataType::label);
}
CmpInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *_opcode)
: CmpInstBase<typename DestDataType::OperandType,
typename SrcDataType::OperandType>(ib, obj, _opcode)
{
}
};
template<typename DestDataType, typename SrcDataType>
class CvtInst : public CommonInstBase<typename DestDataType::OperandType,
typename SrcDataType::OperandType, 1>
{
public:
std::string opcode_suffix()
{
return csprintf("_%s_%s", DestDataType::label, SrcDataType::label);
}
CvtInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *_opcode)
: CommonInstBase<typename DestDataType::OperandType,
typename SrcDataType::OperandType,
1>(ib, obj, _opcode)
{
}
};
template<typename DestDataType, typename SrcDataType>
class PopcountInst :
public CommonInstBase<typename DestDataType::OperandType,
typename SrcDataType::OperandType, 1>
{
public:
std::string opcode_suffix()
{
return csprintf("_%s_%s", DestDataType::label, SrcDataType::label);
}
PopcountInst(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *_opcode)
: CommonInstBase<typename DestDataType::OperandType,
typename SrcDataType::OperandType,
1>(ib, obj, _opcode)
{
}
};
class Stub : public HsailGPUStaticInst
{
public:
Stub(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *_opcode)
: HsailGPUStaticInst(obj, _opcode)
{
}
void generateDisassembly() override
{
disassembly = csprintf("%s", opcode);
}
bool isVectorRegister(int operandIndex) override { return false; }
bool isCondRegister(int operandIndex) override { return false; }
bool isScalarRegister(int operandIndex) override { return false; }
bool isSrcOperand(int operandIndex) override { return false; }
bool isDstOperand(int operandIndex) override { return false; }
int getOperandSize(int operandIndex) override { return 0; }
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst) override
{
return -1;
}
int numSrcRegOperands() override { return 0; }
int numDstRegOperands() override { return 0; }
int getNumOperands() override { return 0; }
};
class SpecialInstNoSrcNoDest : public HsailGPUStaticInst
{
public:
SpecialInstNoSrcNoDest(const Brig::BrigInstBase *ib,
const BrigObject *obj, const char *_opcode)
: HsailGPUStaticInst(obj, _opcode)
{
}
bool isVectorRegister(int operandIndex) override { return false; }
bool isCondRegister(int operandIndex) override { return false; }
bool isScalarRegister(int operandIndex) override { return false; }
bool isSrcOperand(int operandIndex) override { return false; }
bool isDstOperand(int operandIndex) override { return false; }
int getOperandSize(int operandIndex) override { return 0; }
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst) override
{
return -1;
}
int numSrcRegOperands() override { return 0; }
int numDstRegOperands() override { return 0; }
int getNumOperands() override { return 0; }
};
template<typename DestOperandType>
class SpecialInstNoSrcBase : public HsailGPUStaticInst
{
protected:
typename DestOperandType::DestOperand dest;
void generateDisassembly()
{
disassembly = csprintf("%s %s", opcode, dest.disassemble());
}
public:
SpecialInstNoSrcBase(const Brig::BrigInstBase *ib,
const BrigObject *obj, const char *_opcode)
: HsailGPUStaticInst(obj, _opcode)
{
unsigned op_offs = obj->getOperandPtr(ib->operands, 0);
dest.init(op_offs, obj);
}
bool isVectorRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.isVectorRegister();
}
bool isCondRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.isCondRegister();
}
bool isScalarRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.isScalarRegister();
}
bool isSrcOperand(int operandIndex) { return false; }
bool isDstOperand(int operandIndex) { return true; }
int getOperandSize(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.opSize();
}
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst)
{
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.regIndex();
}
int numSrcRegOperands() { return 0; }
int numDstRegOperands() { return dest.isVectorRegister(); }
int getNumOperands() { return 1; }
};
template<typename DestDataType>
class SpecialInstNoSrc :
public SpecialInstNoSrcBase<typename DestDataType::OperandType>
{
public:
typedef typename DestDataType::CType DestCType;
SpecialInstNoSrc(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *_opcode)
: SpecialInstNoSrcBase<typename DestDataType::OperandType>(ib, obj,
_opcode)
{
}
};
template<typename DestOperandType>
class SpecialInst1SrcBase : public HsailGPUStaticInst
{
protected:
typedef int SrcCType; // used in execute() template
typename DestOperandType::DestOperand dest;
ImmOperand<SrcCType> src0;
void
generateDisassembly()
{
disassembly = csprintf("%s %s,%s", opcode, dest.disassemble(),
src0.disassemble());
}
public:
SpecialInst1SrcBase(const Brig::BrigInstBase *ib,
const BrigObject *obj, const char *_opcode)
: HsailGPUStaticInst(obj, _opcode)
{
setFlag(ALU);
unsigned op_offs = obj->getOperandPtr(ib->operands, 0);
dest.init(op_offs, obj);
op_offs = obj->getOperandPtr(ib->operands, 1);
src0.init(op_offs, obj);
}
bool isVectorRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.isVectorRegister();
}
bool isCondRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.isCondRegister();
}
bool isScalarRegister(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.isScalarRegister();
}
bool isSrcOperand(int operandIndex) { return false; }
bool isDstOperand(int operandIndex) { return true; }
int getOperandSize(int operandIndex) {
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.opSize();
}
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst)
{
assert((operandIndex >= 0) && (operandIndex < getNumOperands()));
return dest.regIndex();
}
int numSrcRegOperands() { return 0; }
int numDstRegOperands() { return dest.isVectorRegister(); }
int getNumOperands() { return 1; }
};
template<typename DestDataType>
class SpecialInst1Src :
public SpecialInst1SrcBase<typename DestDataType::OperandType>
{
public:
typedef typename DestDataType::CType DestCType;
SpecialInst1Src(const Brig::BrigInstBase *ib, const BrigObject *obj,
const char *_opcode)
: SpecialInst1SrcBase<typename DestDataType::OperandType>(ib, obj,
_opcode)
{
}
};
class Ret : public SpecialInstNoSrcNoDest
{
public:
typedef SpecialInstNoSrcNoDest Base;
Ret(const Brig::BrigInstBase *ib, const BrigObject *obj)
: Base(ib, obj, "ret")
{
setFlag(GPUStaticInst::Return);
}
void execute(GPUDynInstPtr gpuDynInst);
};
class Barrier : public SpecialInstNoSrcNoDest
{
public:
typedef SpecialInstNoSrcNoDest Base;
uint8_t width;
Barrier(const Brig::BrigInstBase *ib, const BrigObject *obj)
: Base(ib, obj, "barrier")
{
setFlag(GPUStaticInst::MemBarrier);
assert(ib->base.kind == Brig::BRIG_KIND_INST_BR);
width = (uint8_t)((Brig::BrigInstBr*)ib)->width;
}
void execute(GPUDynInstPtr gpuDynInst);
};
class MemFence : public SpecialInstNoSrcNoDest
{
public:
typedef SpecialInstNoSrcNoDest Base;
Brig::BrigMemoryOrder memFenceMemOrder;
Brig::BrigMemoryScope memFenceScopeSegGroup;
Brig::BrigMemoryScope memFenceScopeSegGlobal;
Brig::BrigMemoryScope memFenceScopeSegImage;
MemFence(const Brig::BrigInstBase *ib, const BrigObject *obj)
: Base(ib, obj, "memfence")
{
assert(ib->base.kind == Brig::BRIG_KIND_INST_MEM_FENCE);
memFenceScopeSegGlobal = (Brig::BrigMemoryScope)
((Brig::BrigInstMemFence*)ib)->globalSegmentMemoryScope;
memFenceScopeSegGroup = (Brig::BrigMemoryScope)
((Brig::BrigInstMemFence*)ib)->groupSegmentMemoryScope;
memFenceScopeSegImage = (Brig::BrigMemoryScope)
((Brig::BrigInstMemFence*)ib)->imageSegmentMemoryScope;
memFenceMemOrder = (Brig::BrigMemoryOrder)
((Brig::BrigInstMemFence*)ib)->memoryOrder;
setFlag(MemoryRef);
setFlag(GPUStaticInst::MemFence);
switch (memFenceMemOrder) {
case Brig::BRIG_MEMORY_ORDER_NONE:
setFlag(NoOrder);
break;
case Brig::BRIG_MEMORY_ORDER_RELAXED:
setFlag(RelaxedOrder);
break;
case Brig::BRIG_MEMORY_ORDER_SC_ACQUIRE:
setFlag(Acquire);
break;
case Brig::BRIG_MEMORY_ORDER_SC_RELEASE:
setFlag(Release);
break;
case Brig::BRIG_MEMORY_ORDER_SC_ACQUIRE_RELEASE:
setFlag(AcquireRelease);
break;
default:
fatal("MemInst has bad BrigMemoryOrder\n");
}
// set inst flags based on scopes
if (memFenceScopeSegGlobal != Brig::BRIG_MEMORY_SCOPE_NONE &&
memFenceScopeSegGroup != Brig::BRIG_MEMORY_SCOPE_NONE) {
setFlag(GPUStaticInst::GlobalSegment);
/**
* A memory fence that has scope for
* both segments will use the global
* segment, and be executed in the
* global memory pipeline, therefore,
* we set the segment to match the
* global scope only
*/
switch (memFenceScopeSegGlobal) {
case Brig::BRIG_MEMORY_SCOPE_NONE:
setFlag(NoScope);
break;
case Brig::BRIG_MEMORY_SCOPE_WORKITEM:
setFlag(WorkitemScope);
break;
case Brig::BRIG_MEMORY_SCOPE_WORKGROUP:
setFlag(WorkgroupScope);
break;
case Brig::BRIG_MEMORY_SCOPE_AGENT:
setFlag(DeviceScope);
break;
case Brig::BRIG_MEMORY_SCOPE_SYSTEM:
setFlag(SystemScope);
break;
default:
fatal("MemFence has bad global scope type\n");
}
} else if (memFenceScopeSegGlobal != Brig::BRIG_MEMORY_SCOPE_NONE) {
setFlag(GPUStaticInst::GlobalSegment);
switch (memFenceScopeSegGlobal) {
case Brig::BRIG_MEMORY_SCOPE_NONE:
setFlag(NoScope);
break;
case Brig::BRIG_MEMORY_SCOPE_WORKITEM:
setFlag(WorkitemScope);
break;
case Brig::BRIG_MEMORY_SCOPE_WORKGROUP:
setFlag(WorkgroupScope);
break;
case Brig::BRIG_MEMORY_SCOPE_AGENT:
setFlag(DeviceScope);
break;
case Brig::BRIG_MEMORY_SCOPE_SYSTEM:
setFlag(SystemScope);
break;
default:
fatal("MemFence has bad global scope type\n");
}
} else if (memFenceScopeSegGroup != Brig::BRIG_MEMORY_SCOPE_NONE) {
setFlag(GPUStaticInst::GroupSegment);
switch (memFenceScopeSegGroup) {
case Brig::BRIG_MEMORY_SCOPE_NONE:
setFlag(NoScope);
break;
case Brig::BRIG_MEMORY_SCOPE_WORKITEM:
setFlag(WorkitemScope);
break;
case Brig::BRIG_MEMORY_SCOPE_WORKGROUP:
setFlag(WorkgroupScope);
break;
case Brig::BRIG_MEMORY_SCOPE_AGENT:
setFlag(DeviceScope);
break;
case Brig::BRIG_MEMORY_SCOPE_SYSTEM:
setFlag(SystemScope);
break;
default:
fatal("MemFence has bad group scope type\n");
}
} else {
fatal("MemFence constructor: bad scope specifiers\n");
}
}
void
initiateAcc(GPUDynInstPtr gpuDynInst)
{
Wavefront *wave = gpuDynInst->wavefront();
wave->computeUnit->injectGlobalMemFence(gpuDynInst);
}
void
execute(GPUDynInstPtr gpuDynInst)
{
Wavefront *w = gpuDynInst->wavefront();
// 2 cases:
// * memfence to a sequentially consistent memory (e.g., LDS).
// These can be handled as no-ops.
// * memfence to a relaxed consistency cache (e.g., Hermes, Viper,
// etc.). We send a packet, tagged with the memory order and
// scope, and let the GPU coalescer handle it.
if (isGlobalSeg()) {
gpuDynInst->simdId = w->simdId;
gpuDynInst->wfSlotId = w->wfSlotId;
gpuDynInst->wfDynId = w->wfDynId;
gpuDynInst->kern_id = w->kernId;
gpuDynInst->cu_id = w->computeUnit->cu_id;
gpuDynInst->useContinuation = false;
GlobalMemPipeline* gmp = &(w->computeUnit->globalMemoryPipe);
gmp->issueRequest(gpuDynInst);
w->wrGmReqsInPipe--;
w->rdGmReqsInPipe--;
w->memReqsInPipe--;
w->outstandingReqs++;
} else if (isGroupSeg()) {
// no-op
} else {
fatal("MemFence execute: bad op type\n");
}
}
};
class Call : public HsailGPUStaticInst
{
public:
// private helper functions
void calcAddr(Wavefront* w, GPUDynInstPtr m);
void
generateDisassembly()
{
if (dest.disassemble() == "") {
disassembly = csprintf("%s %s (%s)", opcode, src0.disassemble(),
src1.disassemble());
} else {
disassembly = csprintf("%s %s (%s) (%s)", opcode,
src0.disassemble(), dest.disassemble(),
src1.disassemble());
}
}
bool
isPseudoOp()
{
std::string func_name = src0.disassemble();
if (func_name.find("__gem5_hsail_op") != std::string::npos) {
return true;
}
return false;
}
// member variables
ListOperand dest;
FunctionRefOperand src0;
ListOperand src1;
HsailCode *func_ptr;
// exec function for pseudo instructions mapped on top of call opcode
void execPseudoInst(Wavefront *w, GPUDynInstPtr gpuDynInst);
// user-defined pseudo instructions
void MagicPrintLane(Wavefront *w);
void MagicPrintLane64(Wavefront *w);
void MagicPrintWF32(Wavefront *w);
void MagicPrintWF64(Wavefront *w);
void MagicPrintWFFloat(Wavefront *w);
void MagicSimBreak(Wavefront *w);
void MagicPrefixSum(Wavefront *w);
void MagicReduction(Wavefront *w);
void MagicMaskLower(Wavefront *w);
void MagicMaskUpper(Wavefront *w);
void MagicJoinWFBar(Wavefront *w);
void MagicWaitWFBar(Wavefront *w);
void MagicPanic(Wavefront *w);
void MagicAtomicNRAddGlobalU32Reg(Wavefront *w,
GPUDynInstPtr gpuDynInst);
void MagicAtomicNRAddGroupU32Reg(Wavefront *w,
GPUDynInstPtr gpuDynInst);
void MagicLoadGlobalU32Reg(Wavefront *w, GPUDynInstPtr gpuDynInst);
void MagicXactCasLd(Wavefront *w);
void MagicMostSigThread(Wavefront *w);
void MagicMostSigBroadcast(Wavefront *w);
void MagicPrintWF32ID(Wavefront *w);
void MagicPrintWFID64(Wavefront *w);
Call(const Brig::BrigInstBase *ib, const BrigObject *obj)
: HsailGPUStaticInst(obj, "call")
{
setFlag(ALU);
unsigned op_offs = obj->getOperandPtr(ib->operands, 0);
dest.init(op_offs, obj);
op_offs = obj->getOperandPtr(ib->operands, 1);
src0.init(op_offs, obj);
func_ptr = nullptr;
std::string func_name = src0.disassemble();
if (!isPseudoOp()) {
func_ptr = dynamic_cast<HsailCode*>(obj->
getFunction(func_name));
if (!func_ptr)
fatal("call::exec cannot find function: %s\n", func_name);
}
op_offs = obj->getOperandPtr(ib->operands, 2);
src1.init(op_offs, obj);
}
bool isVectorRegister(int operandIndex) { return false; }
bool isCondRegister(int operandIndex) { return false; }
bool isScalarRegister(int operandIndex) { return false; }
bool isSrcOperand(int operandIndex) { return false; }
bool isDstOperand(int operandIndex) { return false; }
int getOperandSize(int operandIndex) { return 0; }
int
getRegisterIndex(int operandIndex, GPUDynInstPtr gpuDynInst)
{
return -1;
}
void
execute(GPUDynInstPtr gpuDynInst)
{
Wavefront *w = gpuDynInst->wavefront();
std::string func_name = src0.disassemble();
if (isPseudoOp()) {
execPseudoInst(w, gpuDynInst);
} else {
fatal("Native HSAIL functions are not yet implemented: %s\n",
func_name);
}
}
int numSrcRegOperands() { return 0; }
int numDstRegOperands() { return 0; }
int getNumOperands() { return 2; }
};
template<typename T> T heynot(T arg) { return ~arg; }
template<> inline bool heynot<bool>(bool arg) { return !arg; }
/* Explicitly declare template static member variables to avoid
* warnings in some clang versions
*/
template<> const char *B1::label;
template<> const char *B8::label;
template<> const char *B16::label;
template<> const char *B32::label;
template<> const char *B64::label;
template<> const char *S8::label;
template<> const char *S16::label;
template<> const char *S32::label;
template<> const char *S64::label;
template<> const char *U8::label;
template<> const char *U16::label;
template<> const char *U32::label;
template<> const char *U64::label;
template<> const char *F32::label;
template<> const char *F64::label;
} // namespace HsailISA
#endif // __ARCH_HSAIL_INSTS_DECL_HH__