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