| /* |
| * 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 "gpu-compute/hsail_code.hh" |
| |
| #include "arch/gpu_types.hh" |
| #include "arch/hsail/Brig.h" |
| #include "arch/hsail/operand.hh" |
| #include "config/the_gpu_isa.hh" |
| #include "debug/BRIG.hh" |
| #include "debug/HSAILObject.hh" |
| #include "gpu-compute/brig_object.hh" |
| #include "gpu-compute/gpu_static_inst.hh" |
| #include "gpu-compute/kernel_cfg.hh" |
| |
| using namespace Brig; |
| |
| int getBrigDataTypeBytes(BrigType16_t t); |
| |
| HsailCode::HsailCode(const std::string &name_str) |
| : HsaCode(name_str), private_size(-1), readonly_size(-1) |
| { |
| } |
| |
| void |
| HsailCode::init(const BrigDirectiveExecutable *code_dir, const BrigObject *obj, |
| StorageMap *objStorageMap) |
| { |
| storageMap = objStorageMap; |
| |
| // set pointer so that decoding process can find this kernel context when |
| // needed |
| obj->currentCode = this; |
| |
| if (code_dir->base.kind != BRIG_KIND_DIRECTIVE_FUNCTION && |
| code_dir->base.kind != BRIG_KIND_DIRECTIVE_KERNEL) { |
| fatal("unexpected directive kind %d inside kernel/function init\n", |
| code_dir->base.kind); |
| } |
| |
| DPRINTF(HSAILObject, "Initializing code, first code block entry is: %d\n", |
| code_dir->firstCodeBlockEntry); |
| |
| // clear these static vars so we can properly track the max index |
| // for this kernel |
| SRegOperand::maxRegIdx = 0; |
| DRegOperand::maxRegIdx = 0; |
| CRegOperand::maxRegIdx = 0; |
| setPrivateSize(0); |
| |
| const BrigBase *entryPtr = brigNext((BrigBase*)code_dir); |
| const BrigBase *endPtr = |
| obj->getCodeSectionEntry(code_dir->nextModuleEntry); |
| |
| // the instruction's byte address (relative to the base addr |
| // of the code section) |
| int inst_addr = 0; |
| // the index that points to the instruction in the instruction |
| // array |
| int inst_idx = 0; |
| std::vector<GPUStaticInst*> instructions; |
| int funcarg_size_scope = 0; |
| |
| // walk through instructions in code section and directives in |
| // directive section in parallel, processing directives that apply |
| // when we reach the relevant code point. |
| while (entryPtr < endPtr) { |
| switch (entryPtr->kind) { |
| case BRIG_KIND_DIRECTIVE_VARIABLE: |
| { |
| const BrigDirectiveVariable *sym = |
| (const BrigDirectiveVariable*)entryPtr; |
| |
| DPRINTF(HSAILObject,"Initializing code, directive is " |
| "kind_variable, symbol is: %s\n", |
| obj->getString(sym->name)); |
| |
| StorageElement *se = storageMap->addSymbol(sym, obj); |
| |
| if (sym->segment == BRIG_SEGMENT_PRIVATE) { |
| setPrivateSize(se->size); |
| } else { // spill |
| funcarg_size_scope += se->size; |
| } |
| } |
| break; |
| |
| case BRIG_KIND_DIRECTIVE_LABEL: |
| { |
| const BrigDirectiveLabel *lbl = |
| (const BrigDirectiveLabel*)entryPtr; |
| |
| DPRINTF(HSAILObject,"Initializing code, directive is " |
| "kind_label, label is: %s \n", |
| obj->getString(lbl->name)); |
| |
| labelMap.addLabel(lbl, inst_addr, obj); |
| } |
| break; |
| |
| case BRIG_KIND_DIRECTIVE_PRAGMA: |
| { |
| DPRINTF(HSAILObject, "Initializing code, directive " |
| "is kind_pragma\n"); |
| } |
| break; |
| |
| case BRIG_KIND_DIRECTIVE_COMMENT: |
| { |
| DPRINTF(HSAILObject, "Initializing code, directive is " |
| "kind_comment\n"); |
| } |
| break; |
| |
| case BRIG_KIND_DIRECTIVE_ARG_BLOCK_START: |
| { |
| DPRINTF(HSAILObject, "Initializing code, directive is " |
| "kind_arg_block_start\n"); |
| |
| storageMap->resetOffset(BRIG_SEGMENT_ARG); |
| funcarg_size_scope = 0; |
| } |
| break; |
| |
| case BRIG_KIND_DIRECTIVE_ARG_BLOCK_END: |
| { |
| DPRINTF(HSAILObject, "Initializing code, directive is " |
| "kind_arg_block_end\n"); |
| |
| funcarg_size = funcarg_size < funcarg_size_scope ? |
| funcarg_size_scope : funcarg_size; |
| } |
| break; |
| |
| case BRIG_KIND_DIRECTIVE_END: |
| DPRINTF(HSAILObject, "Initializing code, dircetive is " |
| "kind_end\n"); |
| |
| break; |
| |
| default: |
| if (entryPtr->kind >= BRIG_KIND_INST_BEGIN && |
| entryPtr->kind <= BRIG_KIND_INST_END) { |
| |
| BrigInstBase *instPtr = (BrigInstBase*)entryPtr; |
| TheGpuISA::MachInst machInst = { instPtr, obj }; |
| GPUStaticInst *iptr = decoder.decode(machInst); |
| |
| if (iptr) { |
| DPRINTF(HSAILObject, "Initializing code, processing inst " |
| "byte addr #%d idx %d: OPCODE=%d\n", inst_addr, |
| inst_idx, instPtr->opcode); |
| |
| TheGpuISA::RawMachInst raw_inst = decoder.saveInst(iptr); |
| iptr->instNum(inst_idx); |
| iptr->instAddr(inst_addr); |
| _insts.push_back(raw_inst); |
| instructions.push_back(iptr); |
| } |
| inst_addr += sizeof(TheGpuISA::RawMachInst); |
| ++inst_idx; |
| } else if (entryPtr->kind >= BRIG_KIND_OPERAND_BEGIN && |
| entryPtr->kind < BRIG_KIND_OPERAND_END) { |
| warn("unexpected operand entry in code segment\n"); |
| } else { |
| // there are surely some more cases we will need to handle, |
| // but we'll deal with them as we find them. |
| fatal("unexpected directive kind %d inside kernel scope\n", |
| entryPtr->kind); |
| } |
| } |
| |
| entryPtr = brigNext(entryPtr); |
| } |
| |
| // compute Control Flow Graph for current kernel |
| ControlFlowInfo::assignImmediatePostDominators(instructions); |
| |
| max_sreg = SRegOperand::maxRegIdx; |
| max_dreg = DRegOperand::maxRegIdx; |
| max_creg = CRegOperand::maxRegIdx; |
| |
| obj->currentCode = nullptr; |
| } |
| |
| HsailCode::HsailCode(const std::string &name_str, |
| const BrigDirectiveExecutable *code_dir, |
| const BrigObject *obj, StorageMap *objStorageMap) |
| : HsaCode(name_str), private_size(-1), readonly_size(-1) |
| { |
| init(code_dir, obj, objStorageMap); |
| } |
| |
| void |
| LabelMap::addLabel(const Brig::BrigDirectiveLabel *lblDir, int inst_index, |
| const BrigObject *obj) |
| { |
| std::string lbl_name = obj->getString(lblDir->name); |
| Label &lbl = map[lbl_name]; |
| |
| if (lbl.defined()) { |
| fatal("Attempt to redefine existing label %s\n", lbl_name); |
| } |
| |
| lbl.define(lbl_name, inst_index); |
| DPRINTF(HSAILObject, "label %s = %d\n", lbl_name, inst_index); |
| } |
| |
| Label* |
| LabelMap::refLabel(const Brig::BrigDirectiveLabel *lblDir, |
| const BrigObject *obj) |
| { |
| std::string name = obj->getString(lblDir->name); |
| Label &lbl = map[name]; |
| lbl.checkName(name); |
| |
| return &lbl; |
| } |
| |
| int |
| getBrigDataTypeBytes(BrigType16_t t) |
| { |
| switch (t) { |
| case BRIG_TYPE_S8: |
| case BRIG_TYPE_U8: |
| case BRIG_TYPE_B8: |
| return 1; |
| |
| case BRIG_TYPE_S16: |
| case BRIG_TYPE_U16: |
| case BRIG_TYPE_B16: |
| case BRIG_TYPE_F16: |
| return 2; |
| |
| case BRIG_TYPE_S32: |
| case BRIG_TYPE_U32: |
| case BRIG_TYPE_B32: |
| case BRIG_TYPE_F32: |
| return 4; |
| |
| case BRIG_TYPE_S64: |
| case BRIG_TYPE_U64: |
| case BRIG_TYPE_B64: |
| case BRIG_TYPE_F64: |
| return 8; |
| |
| case BRIG_TYPE_B1: |
| |
| default: |
| fatal("unhandled symbol data type %d", t); |
| return 0; |
| } |
| } |
| |
| StorageElement* |
| StorageSpace::addSymbol(const BrigDirectiveVariable *sym, |
| const BrigObject *obj) |
| { |
| const char *sym_name = obj->getString(sym->name); |
| uint64_t size = 0; |
| uint64_t offset = 0; |
| |
| if (sym->type & BRIG_TYPE_ARRAY) { |
| size = getBrigDataTypeBytes(sym->type & ~BRIG_TYPE_ARRAY); |
| size *= (((uint64_t)sym->dim.hi) << 32 | (uint64_t)sym->dim.lo); |
| |
| offset = roundUp(nextOffset, getBrigDataTypeBytes(sym->type & |
| ~BRIG_TYPE_ARRAY)); |
| } else { |
| size = getBrigDataTypeBytes(sym->type); |
| offset = roundUp(nextOffset, getBrigDataTypeBytes(sym->type)); |
| } |
| |
| nextOffset = offset + size; |
| |
| DPRINTF(HSAILObject, "Adding SYMBOL %s size %d offset %#x, init: %d\n", |
| sym_name, size, offset, sym->init); |
| |
| StorageElement* se = new StorageElement(sym_name, offset, size, sym); |
| elements.push_back(se); |
| elements_by_addr.insert(AddrRange(offset, offset + size - 1), se); |
| elements_by_brigptr[sym] = se; |
| |
| return se; |
| } |
| |
| StorageElement* |
| StorageSpace::findSymbol(std::string name) |
| { |
| for (auto it : elements) { |
| if (it->name == name) { |
| return it; |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| StorageElement* |
| StorageSpace::findSymbol(uint64_t addr) |
| { |
| assert(elements_by_addr.size() > 0); |
| |
| auto se = elements_by_addr.find(addr); |
| |
| if (se == elements_by_addr.end()) { |
| return nullptr; |
| } else { |
| return se->second; |
| } |
| } |
| |
| StorageElement* |
| StorageSpace::findSymbol(const BrigDirectiveVariable *brigptr) |
| { |
| assert(elements_by_brigptr.size() > 0); |
| |
| auto se = elements_by_brigptr.find(brigptr); |
| |
| if (se == elements_by_brigptr.end()) { |
| return nullptr; |
| } else { |
| return se->second; |
| } |
| } |
| |
| StorageMap::StorageMap(StorageMap *outerScope) |
| : outerScopeMap(outerScope) |
| { |
| for (int i = 0; i < NumSegments; ++i) |
| space[i] = new StorageSpace((BrigSegment)i); |
| } |
| |
| StorageElement* |
| StorageMap::addSymbol(const BrigDirectiveVariable *sym, const BrigObject *obj) |
| { |
| BrigSegment8_t segment = sym->segment; |
| |
| assert(segment >= Brig::BRIG_SEGMENT_FLAT); |
| assert(segment < NumSegments); |
| |
| return space[segment]->addSymbol(sym, obj); |
| } |
| |
| int |
| StorageMap::getSize(Brig::BrigSegment segment) |
| { |
| assert(segment > Brig::BRIG_SEGMENT_GLOBAL); |
| assert(segment < NumSegments); |
| |
| if (segment != Brig::BRIG_SEGMENT_GROUP && |
| segment != Brig::BRIG_SEGMENT_READONLY) { |
| return space[segment]->getSize(); |
| } else { |
| int ret = space[segment]->getSize(); |
| |
| if (outerScopeMap) { |
| ret += outerScopeMap->getSize(segment); |
| } |
| |
| return ret; |
| } |
| } |
| |
| void |
| StorageMap::resetOffset(Brig::BrigSegment segment) |
| { |
| space[segment]->resetOffset(); |
| } |
| |
| StorageElement* |
| StorageMap::findSymbol(BrigSegment segment, std::string name) |
| { |
| StorageElement *se = space[segment]->findSymbol(name); |
| |
| if (se) |
| return se; |
| |
| if (outerScopeMap) |
| return outerScopeMap->findSymbol(segment, name); |
| |
| return nullptr; |
| } |
| |
| StorageElement* |
| StorageMap::findSymbol(Brig::BrigSegment segment, uint64_t addr) |
| { |
| StorageSpace *sp = space[segment]; |
| |
| if (!sp) { |
| // there is no memory in segment? |
| return nullptr; |
| } |
| |
| StorageElement *se = sp->findSymbol(addr); |
| |
| if (se) |
| return se; |
| |
| if (outerScopeMap) |
| return outerScopeMap->findSymbol(segment, addr); |
| |
| return nullptr; |
| |
| } |
| |
| StorageElement* |
| StorageMap::findSymbol(Brig::BrigSegment segment, |
| const BrigDirectiveVariable *brigptr) |
| { |
| StorageSpace *sp = space[segment]; |
| |
| if (!sp) { |
| // there is no memory in segment? |
| return nullptr; |
| } |
| |
| StorageElement *se = sp->findSymbol(brigptr); |
| |
| if (se) |
| return se; |
| |
| if (outerScopeMap) |
| return outerScopeMap->findSymbol(segment, brigptr); |
| |
| return nullptr; |
| |
| } |