diff options
Diffstat (limited to 'src/arch/hsail/operand.cc')
-rw-r--r-- | src/arch/hsail/operand.cc | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/src/arch/hsail/operand.cc b/src/arch/hsail/operand.cc new file mode 100644 index 000000000..d0e6c5541 --- /dev/null +++ b/src/arch/hsail/operand.cc @@ -0,0 +1,449 @@ +/* + * 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 + */ + +#include "arch/hsail/operand.hh" + +using namespace Brig; + +bool +BaseRegOperand::init(unsigned opOffset, const BrigObject *obj, + unsigned &maxRegIdx, char _regFileChar) +{ + regFileChar = _regFileChar; + const BrigOperand *brigOp = obj->getOperand(opOffset); + + if (brigOp->kind != BRIG_KIND_OPERAND_REGISTER) + return false; + + const BrigOperandRegister *brigRegOp = (const BrigOperandRegister*)brigOp; + + regIdx = brigRegOp->regNum; + + DPRINTF(GPUReg, "Operand: regNum: %d, kind: %d\n", regIdx, + brigRegOp->regKind); + + maxRegIdx = std::max(maxRegIdx, regIdx); + + return true; +} + +void +ListOperand::init(unsigned opOffset, const BrigObject *obj) +{ + const BrigOperand *brigOp = (const BrigOperand*)obj->getOperand(opOffset); + + switch (brigOp->kind) { + case BRIG_KIND_OPERAND_CODE_LIST: + { + const BrigOperandCodeList *opList = + (const BrigOperandCodeList*)brigOp; + + const Brig::BrigData *oprnd_data = + obj->getBrigBaseData(opList->elements); + + // Note: for calls Dest list of operands could be size of 0. + elementCount = oprnd_data->byteCount / 4; + + DPRINTF(GPUReg, "Operand Code List: # elements: %d\n", + elementCount); + + for (int i = 0; i < elementCount; ++i) { + unsigned *data_offset = + (unsigned*)obj->getData(opList->elements + 4 * (i + 1)); + + const BrigDirectiveVariable *p = + (const BrigDirectiveVariable*)obj-> + getCodeSectionEntry(*data_offset); + + StorageElement *se = obj->currentCode->storageMap-> + findSymbol(BRIG_SEGMENT_ARG, p); + + assert(se); + callArgs.push_back(se); + } + } + break; + default: + fatal("ListOperand: bad operand kind %d\n", brigOp->kind); + } +} + +std::string +ListOperand::disassemble() +{ + std::string res_str(""); + + for (auto it : callArgs) { + res_str += csprintf("%s ", it->name.c_str()); + } + + return res_str; +} + +void +FunctionRefOperand::init(unsigned opOffset, const BrigObject *obj) +{ + const BrigOperand *baseOp = obj->getOperand(opOffset); + + if (baseOp->kind != BRIG_KIND_OPERAND_CODE_REF) { + fatal("FunctionRefOperand: bad operand kind %d\n", baseOp->kind); + } + + const BrigOperandCodeRef *brigOp = (const BrigOperandCodeRef*)baseOp; + + const BrigDirectiveExecutable *p = + (const BrigDirectiveExecutable*)obj->getCodeSectionEntry(brigOp->ref); + + func_name = obj->getString(p->name); +} + +std::string +FunctionRefOperand::disassemble() +{ + DPRINTF(GPUReg, "Operand Func-ref name: %s\n", func_name); + + return csprintf("%s", func_name); +} + +bool +BaseRegOperand::init_from_vect(unsigned opOffset, const BrigObject *obj, + int at, unsigned &maxRegIdx, char _regFileChar) +{ + regFileChar = _regFileChar; + const BrigOperand *brigOp = obj->getOperand(opOffset); + + if (brigOp->kind != BRIG_KIND_OPERAND_OPERAND_LIST) + return false; + + + const Brig::BrigOperandOperandList *brigRegVecOp = + (const Brig::BrigOperandOperandList*)brigOp; + + unsigned *data_offset = + (unsigned*)obj->getData(brigRegVecOp->elements + 4 * (at + 1)); + + const BrigOperand *p = + (const BrigOperand*)obj->getOperand(*data_offset); + if (p->kind != BRIG_KIND_OPERAND_REGISTER) { + return false; + } + + const BrigOperandRegister *brigRegOp =(const BrigOperandRegister*)p; + + regIdx = brigRegOp->regNum; + + DPRINTF(GPUReg, "Operand: regNum: %d, kind: %d \n", regIdx, + brigRegOp->regKind); + + maxRegIdx = std::max(maxRegIdx, regIdx); + + return true; +} + +void +BaseRegOperand::initWithStrOffset(unsigned strOffset, const BrigObject *obj, + unsigned &maxRegIdx, char _regFileChar) +{ + const char *name = obj->getString(strOffset); + char *endptr; + regIdx = strtoul(name + 2, &endptr, 10); + + if (name[0] != '$' || name[1] != _regFileChar) { + fatal("register operand parse error on \"%s\"\n", name); + } + + maxRegIdx = std::max(maxRegIdx, regIdx); +} + +unsigned SRegOperand::maxRegIdx; +unsigned DRegOperand::maxRegIdx; +unsigned CRegOperand::maxRegIdx; + +std::string +SRegOperand::disassemble() +{ + return csprintf("$s%d", regIdx); +} + +std::string +DRegOperand::disassemble() +{ + return csprintf("$d%d", regIdx); +} + +std::string +CRegOperand::disassemble() +{ + return csprintf("$c%d", regIdx); +} + +BrigRegOperandInfo +findRegDataType(unsigned opOffset, const BrigObject *obj) +{ + const BrigOperand *baseOp = obj->getOperand(opOffset); + + switch (baseOp->kind) { + case BRIG_KIND_OPERAND_REGISTER: + { + const BrigOperandRegister *op = (BrigOperandRegister*)baseOp; + + return BrigRegOperandInfo((BrigKind16_t)baseOp->kind, + (BrigRegisterKind)op->regKind); + } + break; + + case BRIG_KIND_OPERAND_OPERAND_LIST: + { + const BrigOperandOperandList *op = + (BrigOperandOperandList*)baseOp; + const BrigData *data_p = (BrigData*)obj->getData(op->elements); + + + int num_operands = 0; + BrigRegisterKind reg_kind = (BrigRegisterKind)0; + for (int offset = 0; offset < data_p->byteCount; offset += 4) { + const BrigOperand *op_p = (const BrigOperand *) + obj->getOperand(((int *)data_p->bytes)[offset/4]); + + if (op_p->kind == BRIG_KIND_OPERAND_REGISTER) { + const BrigOperandRegister *brigRegOp = + (const BrigOperandRegister*)op_p; + reg_kind = (BrigRegisterKind)brigRegOp->regKind; + } else if (op_p->kind == BRIG_KIND_OPERAND_CONSTANT_BYTES) { + uint16_t num_bytes = + ((Brig::BrigOperandConstantBytes*)op_p)->base.byteCount + - sizeof(BrigBase); + if (num_bytes == sizeof(uint32_t)) { + reg_kind = BRIG_REGISTER_KIND_SINGLE; + } else if (num_bytes == sizeof(uint64_t)) { + reg_kind = BRIG_REGISTER_KIND_DOUBLE; + } else { + fatal("OperandList: bad operand size %d\n", num_bytes); + } + } else { + fatal("OperandList: bad operand kind %d\n", op_p->kind); + } + + num_operands++; + } + assert(baseOp->kind == BRIG_KIND_OPERAND_OPERAND_LIST); + + return BrigRegOperandInfo((BrigKind16_t)baseOp->kind, reg_kind); + } + break; + + case BRIG_KIND_OPERAND_ADDRESS: + { + const BrigOperandAddress *op = (BrigOperandAddress*)baseOp; + + if (!op->reg) { + BrigType type = BRIG_TYPE_NONE; + + if (op->symbol) { + const BrigDirective *dir = (BrigDirective*) + obj->getCodeSectionEntry(op->symbol); + + assert(dir->kind == BRIG_KIND_DIRECTIVE_VARIABLE); + + const BrigDirectiveVariable *sym = + (const BrigDirectiveVariable*)dir; + + type = (BrigType)sym->type; + } + return BrigRegOperandInfo(BRIG_KIND_OPERAND_ADDRESS, + (BrigType)type); + } else { + const BrigOperandAddress *b = (const BrigOperandAddress*)baseOp; + const BrigOperand *reg = obj->getOperand(b->reg); + const BrigOperandRegister *rop = (BrigOperandRegister*)reg; + + return BrigRegOperandInfo(BRIG_KIND_OPERAND_REGISTER, + (BrigRegisterKind)rop->regKind); + } + } + break; + + default: + fatal("AddrOperand: bad operand kind %d\n", baseOp->kind); + break; + } +} + +void +AddrOperandBase::parseAddr(const BrigOperandAddress *op, const BrigObject *obj) +{ + assert(op->base.kind == BRIG_KIND_OPERAND_ADDRESS); + + const BrigDirective *d = + (BrigDirective*)obj->getCodeSectionEntry(op->symbol); + + assert(d->kind == BRIG_KIND_DIRECTIVE_VARIABLE); + const BrigDirectiveVariable *sym = (BrigDirectiveVariable*)d; + name = obj->getString(sym->name); + + if (sym->segment != BRIG_SEGMENT_ARG) { + storageElement = + obj->currentCode->storageMap->findSymbol(sym->segment, name); + assert(storageElement); + offset = 0; + } else { + // sym->name does not work for BRIG_SEGMENT_ARG for the following case: + // + // void foo(int a); + // void bar(double a); + // + // foo(...) --> arg_u32 %param_p0; + // st_arg_u32 $s0, [%param_p0]; + // call &foo (%param_p0); + // bar(...) --> arg_f64 %param_p0; + // st_arg_u64 $d0, [%param_p0]; + // call &foo (%param_p0); + // + // Both functions use the same variable name (param_p0)!!! + // + // Maybe this is a bug in the compiler (I don't know). + // + // Solution: + // Use directive pointer (BrigDirectiveVariable) to differentiate 2 + // versions of param_p0. + // + // Note this solution is kind of stupid, because we are pulling stuff + // out of the brig binary via the directive pointer and putting it into + // the symbol table, but now we are indexing the symbol table by the + // brig directive pointer! It makes the symbol table sort of pointless. + // But I don't want to mess with the rest of the infrastructure, so + // let's go with this for now. + // + // When we update the compiler again, we should see if this problem goes + // away. If so, we can fold some of this functionality into the code for + // kernel arguments. If not, maybe we can index the symbol name on a + // hash of the variable AND function name + storageElement = obj->currentCode-> + storageMap->findSymbol((Brig::BrigSegment)sym->segment, sym); + + assert(storageElement); + } +} + +uint64_t +AddrOperandBase::calcUniformBase() +{ + // start with offset, will be 0 if not specified + uint64_t address = offset; + + // add in symbol value if specified + if (storageElement) { + address += storageElement->offset; + } + + return address; +} + +std::string +AddrOperandBase::disassemble(std::string reg_disassembly) +{ + std::string disasm; + + if (offset || reg_disassembly != "") { + disasm += "["; + + if (reg_disassembly != "") { + disasm += reg_disassembly; + + if (offset > 0) { + disasm += "+"; + } + } + + if (offset) { + disasm += csprintf("%d", offset); + } + + disasm += "]"; + } else if (name) { + disasm += csprintf("[%s]", name); + } + + return disasm; +} + +void +NoRegAddrOperand::init(unsigned opOffset, const BrigObject *obj) +{ + const BrigOperand *baseOp = obj->getOperand(opOffset); + + if (baseOp->kind == BRIG_KIND_OPERAND_ADDRESS) { + BrigOperandAddress *addrOp = (BrigOperandAddress*)baseOp; + parseAddr(addrOp, obj); + offset = (uint64_t(addrOp->offset.hi) << 32) | + uint64_t(addrOp->offset.lo); + } else { + fatal("NoRegAddrOperand: bad operand kind %d\n", baseOp->kind); + } + +} + +std::string +NoRegAddrOperand::disassemble() +{ + return AddrOperandBase::disassemble(std::string("")); +} + +void +LabelOperand::init(unsigned opOffset, const BrigObject *obj) +{ + const BrigOperandCodeRef *op = + (const BrigOperandCodeRef*)obj->getOperand(opOffset); + + assert(op->base.kind == BRIG_KIND_OPERAND_CODE_REF); + + const BrigDirective *dir = + (const BrigDirective*)obj->getCodeSectionEntry(op->ref); + + assert(dir->kind == BRIG_KIND_DIRECTIVE_LABEL); + label = obj->currentCode->refLabel((BrigDirectiveLabel*)dir, obj); +} + +uint32_t +LabelOperand::getTarget(Wavefront *w, int lane) +{ + return label->get(); +} + +std::string +LabelOperand::disassemble() +{ + return label->name; +} |