/* * 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, Anthony Gutierrez */ #include "gpu-compute/brig_object.hh" #include #include #include #include #include #include #include #include "arch/hsail/Brig.h" #include "base/logging.hh" #include "base/trace.hh" #include "debug/BRIG.hh" #include "debug/HSAILObject.hh" #include "debug/HSALoader.hh" using namespace Brig; std::vector> HsaObject::tryFileFuncs = { BrigObject::tryFile }; extern int getBrigDataTypeBytes(BrigType16_t t); const char *BrigObject::sectionNames[] = { "hsa_data", "hsa_code", "hsa_operand", ".shstrtab" }; const char *segmentNames[] = { "none", "flat", "global", "readonly", "kernarg", "group", "private", "spill", "args" }; const uint8_t* BrigObject::getSectionOffset(enum SectionIndex sec, int offs) const { // allow offs == size for dummy end pointers assert(offs <= sectionInfo[sec].size); return sectionInfo[sec].ptr + offs; } const char* BrigObject::getString(int offs) const { return (const char*)(getSectionOffset(DataSectionIndex, offs) + 4); } const BrigBase* BrigObject::getCodeSectionEntry(int offs) const { return (const BrigBase*)getSectionOffset(CodeSectionIndex, offs); } const BrigData* BrigObject::getBrigBaseData(int offs) const { return (Brig::BrigData*)(getSectionOffset(DataSectionIndex, offs)); } const uint8_t* BrigObject::getData(int offs) const { return getSectionOffset(DataSectionIndex, offs); } const BrigOperand* BrigObject::getOperand(int offs) const { return (const BrigOperand*)getSectionOffset(OperandsSectionIndex, offs); } unsigned BrigObject::getOperandPtr(int offs, int index) const { unsigned *op_offs = (unsigned*)(getData(offs + 4 * (index + 1))); return *op_offs; } const BrigInstBase* BrigObject::getInst(int offs) const { return (const BrigInstBase*)getSectionOffset(CodeSectionIndex, offs); } HsaCode* BrigObject::getKernel(const std::string &name) const { return nullptr; } HsaCode* BrigObject::getFunction(const std::string &name) const { for (int i = 0; i < functions.size(); ++i) { if (functions[i]->name() == name) { return functions[i]; } } return nullptr; } void BrigObject::processDirectives(const BrigBase *dirPtr, const BrigBase *endPtr, StorageMap *storageMap) { while (dirPtr < endPtr) { if (!dirPtr->byteCount) { fatal("Bad directive size 0\n"); } // calculate next pointer now so we can override it if needed const BrigBase *nextDirPtr = brigNext(dirPtr); DPRINTF(HSAILObject, "Code section entry kind: #%x, byte count: %d\n", dirPtr->kind, dirPtr->byteCount); switch (dirPtr->kind) { case BRIG_KIND_DIRECTIVE_FUNCTION: { const BrigDirectiveExecutable *p M5_VAR_USED = reinterpret_cast(dirPtr); DPRINTF(HSAILObject,"DIRECTIVE_FUNCTION: %s offset: " "%d next: %d\n", getString(p->name), p->firstCodeBlockEntry, p->nextModuleEntry); if (p->firstCodeBlockEntry != p->nextModuleEntry) { // Function calls are not supported. We allow the BRIG // object file to create stubs, but the function calls will // not work properly if the application makes use of them. warn("HSA function invocations are unsupported.\n"); const char *name = getString(p->name); HsailCode *code_obj = nullptr; for (int i = 0; i < functions.size(); ++i) { if (functions[i]->name() == name) { code_obj = functions[i]; break; } } if (!code_obj) { // create new local storage map for kernel-local symbols code_obj = new HsailCode(name, p, this, new StorageMap(storageMap)); functions.push_back(code_obj); } else { panic("Multiple definition of Function!!: %s\n", getString(p->name)); } } nextDirPtr = getCodeSectionEntry(p->nextModuleEntry); } break; case BRIG_KIND_DIRECTIVE_KERNEL: { const BrigDirectiveExecutable *p = reinterpret_cast(dirPtr); DPRINTF(HSAILObject,"DIRECTIVE_KERNEL: %s offset: %d count: " "next: %d\n", getString(p->name), p->firstCodeBlockEntry, p->nextModuleEntry); const char *name = getString(p->name); if (name[0] == '&') name++; std::string str = name; char *temp; int len = str.length(); if (str[len - 1] >= 'a' && str[len - 1] <= 'z') { temp = new char[str.size() + 1]; std::copy(str.begin(), str.end() , temp); temp[str.size()] = '\0'; } else { temp = new char[str.size()]; std::copy(str.begin(), str.end() - 1 , temp); temp[str.size() - 1 ] = '\0'; } std::string kernel_name = temp; delete[] temp; HsailCode *code_obj = nullptr; for (const auto &kernel : kernels) { if (kernel->name() == kernel_name) { code_obj = kernel; break; } } if (!code_obj) { // create new local storage map for kernel-local symbols code_obj = new HsailCode(kernel_name, p, this, new StorageMap(storageMap)); kernels.push_back(code_obj); } nextDirPtr = getCodeSectionEntry(p->nextModuleEntry); } break; case BRIG_KIND_DIRECTIVE_VARIABLE: { const BrigDirectiveVariable *p = reinterpret_cast(dirPtr); uint64_t readonlySize_old = storageMap->getSize(BRIG_SEGMENT_READONLY); StorageElement* se = storageMap->addSymbol(p, this); DPRINTF(HSAILObject, "DIRECTIVE_VARIABLE, symbol %s\n", getString(p->name)); if (p->segment == BRIG_SEGMENT_READONLY) { // readonly memory has initialization data uint8_t* readonlyData_old = readonlyData; readonlyData = new uint8_t[storageMap->getSize(BRIG_SEGMENT_READONLY)]; if (p->init) { if ((p->type == BRIG_TYPE_ROIMG) || (p->type == BRIG_TYPE_WOIMG) || (p->type == BRIG_TYPE_SAMP) || (p->type == BRIG_TYPE_SIG32) || (p->type == BRIG_TYPE_SIG64)) { panic("Read only data type not supported: %s\n", getString(p->name)); } const BrigOperand *brigOp = getOperand(p->init); assert(brigOp->kind == BRIG_KIND_OPERAND_CONSTANT_BYTES); const Brig::BrigData *operand_data M5_VAR_USED = getBrigBaseData(((BrigOperandConstantBytes*) brigOp)->bytes); assert((operand_data->byteCount / 4) > 0); uint8_t *symbol_data = (uint8_t*)getData(((BrigOperandConstantBytes*) brigOp)->bytes + 4); // copy the old data and add the new data if (readonlySize_old > 0) { memcpy(readonlyData, readonlyData_old, readonlySize_old); } memcpy(readonlyData + se->offset, symbol_data, se->size); delete[] readonlyData_old; } } } break; case BRIG_KIND_DIRECTIVE_LABEL: { const BrigDirectiveLabel M5_VAR_USED *p = reinterpret_cast(dirPtr); panic("Label directives cannot be at the module level: %s\n", getString(p->name)); } break; case BRIG_KIND_DIRECTIVE_COMMENT: { const BrigDirectiveComment M5_VAR_USED *p = reinterpret_cast(dirPtr); DPRINTF(HSAILObject, "DIRECTIVE_COMMENT: %s\n", getString(p->name)); } break; case BRIG_KIND_DIRECTIVE_LOC: { DPRINTF(HSAILObject, "BRIG_DIRECTIVE_LOC\n"); } break; case BRIG_KIND_DIRECTIVE_MODULE: { const BrigDirectiveModule M5_VAR_USED *p = reinterpret_cast(dirPtr); DPRINTF(HSAILObject, "BRIG_DIRECTIVE_MODULE: %s\n", getString(p->name)); } break; case BRIG_KIND_DIRECTIVE_CONTROL: { DPRINTF(HSAILObject, "DIRECTIVE_CONTROL\n"); } break; case BRIG_KIND_DIRECTIVE_PRAGMA: { DPRINTF(HSAILObject, "DIRECTIVE_PRAGMA\n"); } break; case BRIG_KIND_DIRECTIVE_EXTENSION: { DPRINTF(HSAILObject, "DIRECTIVE_EXTENSION\n"); } break; case BRIG_KIND_DIRECTIVE_ARG_BLOCK_START: { DPRINTF(HSAILObject, "DIRECTIVE_ARG_BLOCK_START\n"); } break; case BRIG_KIND_DIRECTIVE_ARG_BLOCK_END: { DPRINTF(HSAILObject, "DIRECTIVE_ARG_BLOCK_END\n"); } break; default: if (dirPtr->kind >= BRIG_KIND_INST_BEGIN && dirPtr->kind <= BRIG_KIND_INST_END) break; if (dirPtr->kind >= BRIG_KIND_OPERAND_BEGIN && dirPtr->kind <= BRIG_KIND_OPERAND_END) break; warn("Unknown Brig directive kind: %d\n", dirPtr->kind); break; } dirPtr = nextDirPtr; } } HsaObject* BrigObject::tryFile(const std::string &fname, int len, uint8_t *fileData) { const char *brig_ident = "HSA BRIG"; if (memcmp(brig_ident, fileData, MODULE_IDENTIFICATION_LENGTH)) return nullptr; return new BrigObject(fname, len, fileData); } BrigObject::BrigObject(const std::string &fname, int len, uint8_t *fileData) : HsaObject(fname), storageMap(new StorageMap()) { const char *brig_ident = "HSA BRIG"; BrigModuleHeader *mod_hdr = (BrigModuleHeader*)fileData; fatal_if(memcmp(brig_ident, mod_hdr, MODULE_IDENTIFICATION_LENGTH), "%s is not a BRIG file\n", fname); if (mod_hdr->brigMajor != BRIG_VERSION_BRIG_MAJOR || mod_hdr->brigMinor != BRIG_VERSION_BRIG_MINOR) { fatal("%s: BRIG version mismatch, %d.%d != %d.%d\n", fname, mod_hdr->brigMajor, mod_hdr->brigMinor, BRIG_VERSION_BRIG_MAJOR, BRIG_VERSION_BRIG_MINOR); } fatal_if(mod_hdr->sectionCount != NumSectionIndices, "%s: BRIG section " "count (%d) != expected value (%d)\n", fname, mod_hdr->sectionCount, NumSectionIndices); for (int i = 0; i < NumSectionIndices; ++i) { sectionInfo[i].ptr = nullptr; } uint64_t *sec_idx_table = (uint64_t*)(fileData + mod_hdr->sectionIndex); for (int sec_idx = 0; sec_idx < mod_hdr->sectionCount; ++sec_idx) { uint8_t *sec_hdr_byte_ptr = fileData + sec_idx_table[sec_idx]; BrigSectionHeader *sec_hdr = (BrigSectionHeader*)sec_hdr_byte_ptr; // It doesn't look like cprintf supports string precision values, // but if this breaks, the right answer is to fix that DPRINTF(HSAILObject, "found section %.*s\n", sec_hdr->nameLength, sec_hdr->name); sectionInfo[sec_idx].ptr = new uint8_t[sec_hdr->byteCount]; memcpy(sectionInfo[sec_idx].ptr, sec_hdr_byte_ptr, sec_hdr->byteCount); sectionInfo[sec_idx].size = sec_hdr->byteCount; } BrigSectionHeader *code_hdr = (BrigSectionHeader*)sectionInfo[CodeSectionIndex].ptr; DPRINTF(HSAILObject, "Code section hdr, count: %d, hdr count: %d, " "name len: %d\n", code_hdr->byteCount, code_hdr->headerByteCount, code_hdr->nameLength); // start at offset 4 to skip initial null entry (see Brig spec) processDirectives(getCodeSectionEntry(code_hdr->headerByteCount), getCodeSectionEntry(sectionInfo[CodeSectionIndex].size), storageMap); delete[] fileData; DPRINTF(HSALoader, "BRIG object %s loaded.\n", fname); } BrigObject::~BrigObject() { for (int i = 0; i < NumSectionIndices; ++i) if (sectionInfo[i].ptr) delete[] sectionInfo[i].ptr; }