| /* |
| * 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 <fcntl.h> |
| #include <sys/mman.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdlib> |
| |
| #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<std::function<HsaObject*(const std::string&, int, uint8_t*)>> |
| 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<const BrigDirectiveExecutable*>(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<const BrigDirectiveExecutable*>(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<const BrigDirectiveVariable*>(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<const BrigDirectiveLabel*>(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<const BrigDirectiveComment*>(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<const BrigDirectiveModule*>(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; |
| } |