| /* | |
| * 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.contains(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; | |
| } |