summaryrefslogtreecommitdiff
path: root/src/arch/hsail/operand.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/hsail/operand.hh')
-rw-r--r--src/arch/hsail/operand.hh768
1 files changed, 768 insertions, 0 deletions
diff --git a/src/arch/hsail/operand.hh b/src/arch/hsail/operand.hh
new file mode 100644
index 000000000..e3d275b10
--- /dev/null
+++ b/src/arch/hsail/operand.hh
@@ -0,0 +1,768 @@
+/*
+ * 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 <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
+{
+ 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()
+ {
+ assert(sizeof(OperandType) <= sizeof(T));
+
+ return *(OperandType*)&bits;
+ }
+
+ // 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>();
+ }
+};
+
+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)));
+
+ return true;
+ }
+ break;
+
+ case Brig::BRIG_KIND_OPERAND_WAVESIZE:
+ bits = VSZ;
+ return true;
+
+ default:
+ 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) {
+ 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) {
+ 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>() :
+ 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, uint64_t *addrVec) = 0;
+ virtual uint64_t calcLane(Wavefront *w, int lane=0) = 0;
+
+ uint64_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, uint64_t *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;
+
+ offset = (uint64_t(op->offset.hi) << 32) | uint64_t(op->offset.lo);
+ reg.init(op->reg, obj);
+
+ if (reg.regFileChar == 's') {
+ reg.regOperandSize = sizeof(uint32_t);
+ registerType = Enums::RT_VECTOR;
+ }
+ else if (reg.regFileChar == 'd') {
+ 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, uint64_t *addrVec)
+{
+ Addr address = calcUniformBase();
+
+ for (int lane = 0; lane < VSZ; ++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, uint64_t *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, uint64_t *addrVec)
+{
+ uint64_t address = calcUniformBase();
+
+ for (int lane = 0; lane < VSZ; ++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__