| /* |
| * 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__ |