summaryrefslogtreecommitdiff
path: root/src/arch/hsail/operand.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/hsail/operand.cc')
-rw-r--r--src/arch/hsail/operand.cc449
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;
+}