38708f369b
it's possible for the offset provided to an HSAIL mem inst to be a negative value, however the variable we use to hold the offset is an unsigned type. this can lead to excessively large offset values when the offset is negative, which will almost certainly cause the access to go out of bounds.
797 lines
22 KiB
C++
797 lines
22 KiB
C++
/*
|
|
* 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_OPERAND_HH__
|
|
#define __ARCH_HSAIL_OPERAND_HH__
|
|
|
|
/**
|
|
* @file operand.hh
|
|
*
|
|
* Defines classes encapsulating HSAIL instruction operands.
|
|
*/
|
|
|
|
#include <limits>
|
|
#include <string>
|
|
|
|
#include "arch/hsail/Brig.h"
|
|
#include "base/trace.hh"
|
|
#include "base/types.hh"
|
|
#include "debug/GPUReg.hh"
|
|
#include "enums/RegisterType.hh"
|
|
#include "gpu-compute/brig_object.hh"
|
|
#include "gpu-compute/compute_unit.hh"
|
|
#include "gpu-compute/hsail_code.hh"
|
|
#include "gpu-compute/shader.hh"
|
|
#include "gpu-compute/vector_register_file.hh"
|
|
#include "gpu-compute/wavefront.hh"
|
|
|
|
class Label;
|
|
class StorageElement;
|
|
|
|
class BaseOperand
|
|
{
|
|
public:
|
|
Enums::RegisterType registerType;
|
|
uint32_t regOperandSize;
|
|
BaseOperand() { registerType = Enums::RT_NONE; regOperandSize = 0; }
|
|
bool isVectorRegister() { return registerType == Enums::RT_VECTOR; }
|
|
bool isScalarRegister() { return registerType == Enums::RT_SCALAR; }
|
|
bool isCondRegister() { return registerType == Enums::RT_CONDITION; }
|
|
unsigned int regIndex() { return 0; }
|
|
uint32_t opSize() { return regOperandSize; }
|
|
virtual ~BaseOperand() { }
|
|
};
|
|
|
|
class BrigRegOperandInfo
|
|
{
|
|
public:
|
|
Brig::BrigKind16_t kind;
|
|
Brig::BrigType type;
|
|
Brig::BrigRegisterKind regKind;
|
|
|
|
BrigRegOperandInfo(Brig::BrigKind16_t _kind,
|
|
Brig::BrigRegisterKind _regKind)
|
|
: kind(_kind), regKind(_regKind)
|
|
{
|
|
}
|
|
|
|
BrigRegOperandInfo(Brig::BrigKind16_t _kind, Brig::BrigType _type)
|
|
: kind(_kind), type(_type)
|
|
{
|
|
}
|
|
|
|
BrigRegOperandInfo() : kind(Brig::BRIG_KIND_OPERAND_CONSTANT_BYTES),
|
|
type(Brig::BRIG_TYPE_NONE)
|
|
{
|
|
}
|
|
};
|
|
|
|
BrigRegOperandInfo findRegDataType(unsigned opOffset, const BrigObject *obj);
|
|
|
|
class BaseRegOperand : public BaseOperand
|
|
{
|
|
public:
|
|
unsigned regIdx;
|
|
char regFileChar;
|
|
|
|
bool init(unsigned opOffset, const BrigObject *obj,
|
|
unsigned &maxRegIdx, char _regFileChar);
|
|
|
|
bool init_from_vect(unsigned opOffset, const BrigObject *obj, int at,
|
|
unsigned &maxRegIdx, char _regFileChar);
|
|
|
|
void initWithStrOffset(unsigned strOffset, const BrigObject *obj,
|
|
unsigned &maxRegIdx, char _regFileChar);
|
|
unsigned int regIndex() { return regIdx; }
|
|
};
|
|
|
|
class SRegOperand : public BaseRegOperand
|
|
{
|
|
public:
|
|
static unsigned maxRegIdx;
|
|
|
|
bool
|
|
init(unsigned opOffset, const BrigObject *obj)
|
|
{
|
|
regOperandSize = sizeof(uint32_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
|
|
return BaseRegOperand::init(opOffset, obj, maxRegIdx, 's');
|
|
}
|
|
|
|
bool
|
|
init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
|
|
{
|
|
regOperandSize = sizeof(uint32_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
|
|
return BaseRegOperand::init_from_vect(opOffset, obj, at, maxRegIdx,
|
|
's');
|
|
}
|
|
|
|
void
|
|
initWithStrOffset(unsigned strOffset, const BrigObject *obj)
|
|
{
|
|
regOperandSize = sizeof(uint32_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
|
|
return BaseRegOperand::initWithStrOffset(strOffset, obj, maxRegIdx,
|
|
's');
|
|
}
|
|
|
|
template<typename OperandType>
|
|
OperandType
|
|
get(Wavefront *w, int lane)
|
|
{
|
|
assert(sizeof(OperandType) <= sizeof(uint32_t));
|
|
assert(regIdx < w->maxSpVgprs);
|
|
// if OperandType is smaller than 32-bit, we truncate the value
|
|
OperandType ret;
|
|
uint32_t vgprIdx;
|
|
|
|
switch (sizeof(OperandType)) {
|
|
case 1: // 1 byte operand
|
|
vgprIdx = w->remap(regIdx, 1, 1);
|
|
ret = (w->computeUnit->vrf[w->simdId]->
|
|
read<uint32_t>(vgprIdx, lane)) & 0xff;
|
|
break;
|
|
case 2: // 2 byte operand
|
|
vgprIdx = w->remap(regIdx, 2, 1);
|
|
ret = (w->computeUnit->vrf[w->simdId]->
|
|
read<uint32_t>(vgprIdx, lane)) & 0xffff;
|
|
break;
|
|
case 4: // 4 byte operand
|
|
vgprIdx = w->remap(regIdx,sizeof(OperandType), 1);
|
|
ret = w->computeUnit->vrf[w->simdId]->
|
|
read<OperandType>(vgprIdx, lane);
|
|
break;
|
|
default:
|
|
panic("Bad OperandType\n");
|
|
break;
|
|
}
|
|
|
|
return (OperandType)ret;
|
|
}
|
|
|
|
// special get method for compatibility with LabelOperand
|
|
uint32_t
|
|
getTarget(Wavefront *w, int lane)
|
|
{
|
|
return get<uint32_t>(w, lane);
|
|
}
|
|
|
|
template<typename OperandType>
|
|
void set(Wavefront *w, int lane, OperandType &val);
|
|
std::string disassemble();
|
|
};
|
|
|
|
template<typename OperandType>
|
|
void
|
|
SRegOperand::set(Wavefront *w, int lane, OperandType &val)
|
|
{
|
|
DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $s%d <- %d\n",
|
|
w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx, val);
|
|
|
|
assert(sizeof(OperandType) == sizeof(uint32_t));
|
|
assert(regIdx < w->maxSpVgprs);
|
|
uint32_t vgprIdx = w->remap(regIdx, sizeof(OperandType), 1);
|
|
w->computeUnit->vrf[w->simdId]->write<OperandType>(vgprIdx,val,lane);
|
|
}
|
|
|
|
template<>
|
|
inline void
|
|
SRegOperand::set(Wavefront *w, int lane, uint64_t &val)
|
|
{
|
|
DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $s%d <- %d\n",
|
|
w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx, val);
|
|
|
|
assert(regIdx < w->maxSpVgprs);
|
|
uint32_t vgprIdx = w->remap(regIdx, sizeof(uint32_t), 1);
|
|
w->computeUnit->vrf[w->simdId]->write<uint32_t>(vgprIdx, val, lane);
|
|
}
|
|
|
|
class DRegOperand : public BaseRegOperand
|
|
{
|
|
public:
|
|
static unsigned maxRegIdx;
|
|
|
|
bool
|
|
init(unsigned opOffset, const BrigObject *obj)
|
|
{
|
|
regOperandSize = sizeof(uint64_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
|
|
return BaseRegOperand::init(opOffset, obj, maxRegIdx, 'd');
|
|
}
|
|
|
|
bool
|
|
init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
|
|
{
|
|
regOperandSize = sizeof(uint64_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
|
|
return BaseRegOperand::init_from_vect(opOffset, obj, at, maxRegIdx,
|
|
'd');
|
|
}
|
|
|
|
void
|
|
initWithStrOffset(unsigned strOffset, const BrigObject *obj)
|
|
{
|
|
regOperandSize = sizeof(uint64_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
|
|
return BaseRegOperand::initWithStrOffset(strOffset, obj, maxRegIdx,
|
|
'd');
|
|
}
|
|
|
|
template<typename OperandType>
|
|
OperandType
|
|
get(Wavefront *w, int lane)
|
|
{
|
|
assert(sizeof(OperandType) <= sizeof(uint64_t));
|
|
// TODO: this check is valid only for HSAIL
|
|
assert(regIdx < w->maxDpVgprs);
|
|
uint32_t vgprIdx = w->remap(regIdx, sizeof(OperandType), 1);
|
|
|
|
return w->computeUnit->vrf[w->simdId]->read<OperandType>(vgprIdx,lane);
|
|
}
|
|
|
|
template<typename OperandType>
|
|
void
|
|
set(Wavefront *w, int lane, OperandType &val)
|
|
{
|
|
DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $d%d <- %d\n",
|
|
w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx,
|
|
val);
|
|
|
|
assert(sizeof(OperandType) <= sizeof(uint64_t));
|
|
// TODO: this check is valid only for HSAIL
|
|
assert(regIdx < w->maxDpVgprs);
|
|
uint32_t vgprIdx = w->remap(regIdx, sizeof(OperandType), 1);
|
|
w->computeUnit->vrf[w->simdId]->write<OperandType>(vgprIdx,val,lane);
|
|
}
|
|
|
|
std::string disassemble();
|
|
};
|
|
|
|
class CRegOperand : public BaseRegOperand
|
|
{
|
|
public:
|
|
static unsigned maxRegIdx;
|
|
|
|
bool
|
|
init(unsigned opOffset, const BrigObject *obj)
|
|
{
|
|
regOperandSize = sizeof(uint8_t);
|
|
registerType = Enums::RT_CONDITION;
|
|
|
|
return BaseRegOperand::init(opOffset, obj, maxRegIdx, 'c');
|
|
}
|
|
|
|
bool
|
|
init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
|
|
{
|
|
regOperandSize = sizeof(uint8_t);
|
|
registerType = Enums::RT_CONDITION;
|
|
|
|
return BaseRegOperand::init_from_vect(opOffset, obj, at, maxRegIdx,
|
|
'c');
|
|
}
|
|
|
|
void
|
|
initWithStrOffset(unsigned strOffset, const BrigObject *obj)
|
|
{
|
|
regOperandSize = sizeof(uint8_t);
|
|
registerType = Enums::RT_CONDITION;
|
|
|
|
return BaseRegOperand::initWithStrOffset(strOffset, obj, maxRegIdx,
|
|
'c');
|
|
}
|
|
|
|
template<typename OperandType>
|
|
OperandType
|
|
get(Wavefront *w, int lane)
|
|
{
|
|
assert(regIdx < w->condRegState->numRegs());
|
|
|
|
return w->condRegState->read<OperandType>((int)regIdx, lane);
|
|
}
|
|
|
|
template<typename OperandType>
|
|
void
|
|
set(Wavefront *w, int lane, OperandType &val)
|
|
{
|
|
DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $c%d <- %d\n",
|
|
w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx,
|
|
val);
|
|
|
|
assert(regIdx < w->condRegState->numRegs());
|
|
w->condRegState->write<OperandType>(regIdx,lane,val);
|
|
}
|
|
|
|
std::string disassemble();
|
|
};
|
|
|
|
template<typename T>
|
|
class ImmOperand : public BaseOperand
|
|
{
|
|
private:
|
|
uint16_t kind;
|
|
public:
|
|
T bits;
|
|
|
|
bool init(unsigned opOffset, const BrigObject *obj);
|
|
bool init_from_vect(unsigned opOffset, const BrigObject *obj, int at);
|
|
std::string disassemble();
|
|
|
|
template<typename OperandType>
|
|
OperandType
|
|
get(Wavefront *w)
|
|
{
|
|
assert(sizeof(OperandType) <= sizeof(T));
|
|
panic_if(w == nullptr, "WF pointer needs to be set");
|
|
|
|
switch (kind) {
|
|
// immediate operand is WF size
|
|
case Brig::BRIG_KIND_OPERAND_WAVESIZE:
|
|
return (OperandType)w->computeUnit->wfSize();
|
|
break;
|
|
|
|
default:
|
|
return *(OperandType*)&bits;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// This version of get() takes a WF* and a lane id for
|
|
// compatibility with the register-based get() methods.
|
|
template<typename OperandType>
|
|
OperandType
|
|
get(Wavefront *w, int lane)
|
|
{
|
|
return get<OperandType>(w);
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
bool
|
|
ImmOperand<T>::init(unsigned opOffset, const BrigObject *obj)
|
|
{
|
|
const Brig::BrigOperand *brigOp = obj->getOperand(opOffset);
|
|
|
|
switch (brigOp->kind) {
|
|
// this is immediate operand
|
|
case Brig::BRIG_KIND_OPERAND_CONSTANT_BYTES:
|
|
{
|
|
DPRINTF(GPUReg, "sizeof(T): %lu, byteCount: %d\n", sizeof(T),
|
|
brigOp->byteCount);
|
|
|
|
auto cbptr = (Brig::BrigOperandConstantBytes*)brigOp;
|
|
|
|
bits = *((T*)(obj->getData(cbptr->bytes + 4)));
|
|
kind = brigOp->kind;
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case Brig::BRIG_KIND_OPERAND_WAVESIZE:
|
|
kind = brigOp->kind;
|
|
bits = std::numeric_limits<unsigned long long>::digits;
|
|
return true;
|
|
|
|
default:
|
|
kind = Brig::BRIG_KIND_NONE;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
bool
|
|
ImmOperand<T>::init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
|
|
{
|
|
const Brig::BrigOperand *brigOp = obj->getOperand(opOffset);
|
|
|
|
if (brigOp->kind != Brig::BRIG_KIND_OPERAND_OPERAND_LIST) {
|
|
kind = Brig::BRIG_KIND_NONE;
|
|
return false;
|
|
}
|
|
|
|
|
|
const Brig::BrigOperandOperandList *brigVecOp =
|
|
(const Brig::BrigOperandOperandList *)brigOp;
|
|
|
|
unsigned *data_offset =
|
|
(unsigned *)obj->getData(brigVecOp->elements + 4 * (at + 1));
|
|
|
|
const Brig::BrigOperand *p =
|
|
(const Brig::BrigOperand *)obj->getOperand(*data_offset);
|
|
|
|
if (p->kind != Brig::BRIG_KIND_OPERAND_CONSTANT_BYTES) {
|
|
kind = Brig::BRIG_KIND_NONE;
|
|
return false;
|
|
}
|
|
|
|
return init(*data_offset, obj);
|
|
}
|
|
template<typename T>
|
|
std::string
|
|
ImmOperand<T>::disassemble()
|
|
{
|
|
return csprintf("0x%08x", bits);
|
|
}
|
|
|
|
template<typename RegOperand, typename T>
|
|
class RegOrImmOperand : public BaseOperand
|
|
{
|
|
private:
|
|
bool is_imm;
|
|
|
|
public:
|
|
void setImm(const bool value) { is_imm = value; }
|
|
|
|
ImmOperand<T> imm_op;
|
|
RegOperand reg_op;
|
|
|
|
RegOrImmOperand() { is_imm = false; }
|
|
void init(unsigned opOffset, const BrigObject *obj);
|
|
void init_from_vect(unsigned opOffset, const BrigObject *obj, int at);
|
|
std::string disassemble();
|
|
|
|
template<typename OperandType>
|
|
OperandType
|
|
get(Wavefront *w, int lane)
|
|
{
|
|
return is_imm ? imm_op.template get<OperandType>(w) :
|
|
reg_op.template get<OperandType>(w, lane);
|
|
}
|
|
|
|
uint32_t
|
|
opSize()
|
|
{
|
|
if (!is_imm) {
|
|
return reg_op.opSize();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
isVectorRegister()
|
|
{
|
|
if (!is_imm) {
|
|
return reg_op.registerType == Enums::RT_VECTOR;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
isCondRegister()
|
|
{
|
|
if (!is_imm) {
|
|
return reg_op.registerType == Enums::RT_CONDITION;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
isScalarRegister()
|
|
{
|
|
if (!is_imm) {
|
|
return reg_op.registerType == Enums::RT_SCALAR;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
unsigned int
|
|
regIndex()
|
|
{
|
|
if (!is_imm) {
|
|
return reg_op.regIndex();
|
|
}
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
template<typename RegOperand, typename T>
|
|
void
|
|
RegOrImmOperand<RegOperand, T>::init(unsigned opOffset, const BrigObject *obj)
|
|
{
|
|
is_imm = false;
|
|
|
|
if (reg_op.init(opOffset, obj)) {
|
|
return;
|
|
}
|
|
|
|
if (imm_op.init(opOffset, obj)) {
|
|
is_imm = true;
|
|
return;
|
|
}
|
|
|
|
fatal("RegOrImmOperand::init(): bad operand kind %d\n",
|
|
obj->getOperand(opOffset)->kind);
|
|
}
|
|
|
|
template<typename RegOperand, typename T>
|
|
void
|
|
RegOrImmOperand<RegOperand, T>::init_from_vect(unsigned opOffset,
|
|
const BrigObject *obj, int at)
|
|
{
|
|
if (reg_op.init_from_vect(opOffset, obj, at)) {
|
|
is_imm = false;
|
|
|
|
return;
|
|
}
|
|
|
|
if (imm_op.init_from_vect(opOffset, obj, at)) {
|
|
is_imm = true;
|
|
|
|
return;
|
|
}
|
|
|
|
fatal("RegOrImmOperand::init(): bad operand kind %d\n",
|
|
obj->getOperand(opOffset)->kind);
|
|
}
|
|
|
|
template<typename RegOperand, typename T>
|
|
std::string
|
|
RegOrImmOperand<RegOperand, T>::disassemble()
|
|
{
|
|
return is_imm ? imm_op.disassemble() : reg_op.disassemble();
|
|
}
|
|
|
|
typedef RegOrImmOperand<SRegOperand, uint32_t> SRegOrImmOperand;
|
|
typedef RegOrImmOperand<DRegOperand, uint64_t> DRegOrImmOperand;
|
|
typedef RegOrImmOperand<CRegOperand, bool> CRegOrImmOperand;
|
|
|
|
class AddrOperandBase : public BaseOperand
|
|
{
|
|
protected:
|
|
// helper function for init()
|
|
void parseAddr(const Brig::BrigOperandAddress *op, const BrigObject *obj);
|
|
|
|
// helper function for disassemble()
|
|
std::string disassemble(std::string reg_disassembly);
|
|
uint64_t calcUniformBase();
|
|
|
|
public:
|
|
virtual void calcVector(Wavefront *w, std::vector<Addr> &addrVec) = 0;
|
|
virtual uint64_t calcLane(Wavefront *w, int lane=0) = 0;
|
|
|
|
int64_t offset;
|
|
const char *name = nullptr;
|
|
StorageElement *storageElement;
|
|
};
|
|
|
|
template<typename RegOperandType>
|
|
class RegAddrOperand : public AddrOperandBase
|
|
{
|
|
public:
|
|
RegOperandType reg;
|
|
void init(unsigned opOffset, const BrigObject *obj);
|
|
uint64_t calcUniform();
|
|
void calcVector(Wavefront *w, std::vector<Addr> &addrVec);
|
|
uint64_t calcLane(Wavefront *w, int lane=0);
|
|
uint32_t opSize() { return reg.opSize(); }
|
|
bool isVectorRegister() { return reg.registerType == Enums::RT_VECTOR; }
|
|
bool isCondRegister() { return reg.registerType == Enums::RT_CONDITION; }
|
|
bool isScalarRegister() { return reg.registerType == Enums::RT_SCALAR; }
|
|
unsigned int regIndex() { return reg.regIndex(); }
|
|
std::string disassemble();
|
|
};
|
|
|
|
template<typename RegOperandType>
|
|
void
|
|
RegAddrOperand<RegOperandType>::init(unsigned opOffset, const BrigObject *obj)
|
|
{
|
|
using namespace Brig;
|
|
|
|
const BrigOperand *baseOp = obj->getOperand(opOffset);
|
|
|
|
switch (baseOp->kind) {
|
|
case BRIG_KIND_OPERAND_ADDRESS:
|
|
{
|
|
const BrigOperandAddress *op = (BrigOperandAddress*)baseOp;
|
|
storageElement = nullptr;
|
|
|
|
reg.init(op->reg, obj);
|
|
|
|
if (reg.regFileChar == 's') {
|
|
// if the address expression is 32b, then the hi
|
|
// bits of the offset must be set to 0 in the BRIG
|
|
assert(!op->offset.hi);
|
|
/**
|
|
* the offset field of an HSAIL instruction may be negative
|
|
* so here we cast the raw bits we get from the BRIG file to
|
|
* a signed type to avoid address calculation errors
|
|
*/
|
|
offset = (int32_t)(op->offset.lo);
|
|
reg.regOperandSize = sizeof(uint32_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
}
|
|
else if (reg.regFileChar == 'd') {
|
|
offset = (int64_t)(((uint64_t)(op->offset.hi) << 32)
|
|
| (uint64_t)(op->offset.lo));
|
|
reg.regOperandSize = sizeof(uint64_t);
|
|
registerType = Enums::RT_VECTOR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fatal("RegAddrOperand: bad operand kind %d\n", baseOp->kind);
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<typename RegOperandType>
|
|
uint64_t
|
|
RegAddrOperand<RegOperandType>::calcUniform()
|
|
{
|
|
fatal("can't do calcUniform() on register-based address\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
template<typename RegOperandType>
|
|
void
|
|
RegAddrOperand<RegOperandType>::calcVector(Wavefront *w,
|
|
std::vector<Addr> &addrVec)
|
|
{
|
|
Addr address = calcUniformBase();
|
|
|
|
for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) {
|
|
if (w->execMask(lane)) {
|
|
if (reg.regFileChar == 's') {
|
|
addrVec[lane] = address + reg.template get<uint32_t>(w, lane);
|
|
} else {
|
|
addrVec[lane] = address + reg.template get<Addr>(w, lane);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename RegOperandType>
|
|
uint64_t
|
|
RegAddrOperand<RegOperandType>::calcLane(Wavefront *w, int lane)
|
|
{
|
|
Addr address = calcUniformBase();
|
|
|
|
return address + reg.template get<Addr>(w, lane);
|
|
}
|
|
|
|
template<typename RegOperandType>
|
|
std::string
|
|
RegAddrOperand<RegOperandType>::disassemble()
|
|
{
|
|
return AddrOperandBase::disassemble(reg.disassemble());
|
|
}
|
|
|
|
typedef RegAddrOperand<SRegOperand> SRegAddrOperand;
|
|
typedef RegAddrOperand<DRegOperand> DRegAddrOperand;
|
|
|
|
class NoRegAddrOperand : public AddrOperandBase
|
|
{
|
|
public:
|
|
void init(unsigned opOffset, const BrigObject *obj);
|
|
uint64_t calcUniform();
|
|
void calcVector(Wavefront *w, std::vector<Addr> &addrVec);
|
|
uint64_t calcLane(Wavefront *w, int lane=0);
|
|
std::string disassemble();
|
|
};
|
|
|
|
inline uint64_t
|
|
NoRegAddrOperand::calcUniform()
|
|
{
|
|
return AddrOperandBase::calcUniformBase();
|
|
}
|
|
|
|
inline uint64_t
|
|
NoRegAddrOperand::calcLane(Wavefront *w, int lane)
|
|
{
|
|
return calcUniform();
|
|
}
|
|
|
|
inline void
|
|
NoRegAddrOperand::calcVector(Wavefront *w, std::vector<Addr> &addrVec)
|
|
{
|
|
uint64_t address = calcUniformBase();
|
|
|
|
for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane)
|
|
addrVec[lane] = address;
|
|
}
|
|
|
|
class LabelOperand : public BaseOperand
|
|
{
|
|
public:
|
|
Label *label;
|
|
|
|
void init(unsigned opOffset, const BrigObject *obj);
|
|
std::string disassemble();
|
|
|
|
// special get method for compatibility with SRegOperand
|
|
uint32_t getTarget(Wavefront *w, int lane);
|
|
|
|
};
|
|
|
|
class ListOperand : public BaseOperand
|
|
{
|
|
public:
|
|
int elementCount;
|
|
std::vector<StorageElement*> callArgs;
|
|
|
|
int
|
|
getSrcOperand(int idx)
|
|
{
|
|
DPRINTF(GPUReg, "getSrcOperand, idx: %d, sz_args: %d\n", idx,
|
|
callArgs.size());
|
|
|
|
return callArgs.at(idx)->offset;
|
|
}
|
|
|
|
void init(unsigned opOffset, const BrigObject *obj);
|
|
|
|
std::string disassemble();
|
|
|
|
template<typename OperandType>
|
|
OperandType
|
|
get(Wavefront *w, int lane, int arg_idx)
|
|
{
|
|
return w->readCallArgMem<OperandType>(lane, getSrcOperand(arg_idx));
|
|
}
|
|
|
|
template<typename OperandType>
|
|
void
|
|
set(Wavefront *w, int lane, OperandType val)
|
|
{
|
|
w->writeCallArgMem<OperandType>(lane, getSrcOperand(0), val);
|
|
DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: arg[%d] <- %d\n",
|
|
w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane,
|
|
getSrcOperand(0), val);
|
|
}
|
|
};
|
|
|
|
class FunctionRefOperand : public BaseOperand
|
|
{
|
|
public:
|
|
const char *func_name;
|
|
|
|
void init(unsigned opOffset, const BrigObject *obj);
|
|
std::string disassemble();
|
|
};
|
|
|
|
#endif // __ARCH_HSAIL_OPERAND_HH__
|