/* * 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 */ #ifndef __HSAIL_CODE_HH__ #define __HSAIL_CODE_HH__ #include #include #include #include #include #include "arch/gpu_decoder.hh" #include "arch/hsail/Brig.h" #include "base/addr_range_map.hh" #include "base/intmath.hh" #include "config/the_gpu_isa.hh" #include "gpu-compute/hsa_code.hh" #include "gpu-compute/hsa_kernel_info.hh" #include "gpu-compute/misc.hh" class BrigObject; class GPUStaticInst; inline int popcount(uint64_t src, int sz) { int cnt = 0; for (int i = 0; i < sz; ++i) { if (src & 1) ++cnt; src >>= 1; } return cnt; } inline int firstbit(uint64_t src, int sz) { int i; for (i = 0; i < sz; ++i) { if (src & 1) break; src >>= 1; } return i; } inline int lastbit(uint64_t src, int sz) { int i0 = -1; for (int i = 0; i < sz; ++i) { if (src & 1) i0 = i; src >>= 1; } return i0; } inline int signbit(uint64_t src, int sz) { int i0 = -1; if (src & (1 << (sz - 1))) { for (int i = 0; i < sz - 1; ++i) { if (!(src & 1)) i0 = i; src >>= 1; } } else { for (int i = 0; i < sz - 1; ++i) { if (src & 1) i0 = i; src >>= 1; } } return i0; } inline uint64_t bitrev(uint64_t src, int sz) { uint64_t r = 0; for (int i = 0; i < sz; ++i) { r <<= 1; if (src & 1) r |= 1; src >>= 1; } return r; } inline uint64_t mul_hi(uint32_t a, uint32_t b) { return ((uint64_t)a * (uint64_t)b) >> 32; } inline uint64_t mul_hi(int32_t a, int32_t b) { return ((int64_t)a * (int64_t)b) >> 32; } inline uint64_t mul_hi(uint64_t a, uint64_t b) { return ((uint64_t)a * (uint64_t)b) >> 32; } inline uint64_t mul_hi(int64_t a, int64_t b) { return ((int64_t)a * (int64_t)b) >> 32; } inline uint64_t mul_hi(double a, double b) { return 0; } class Label { public: std::string name; int value; Label() : value(-1) { } bool defined() { return value != -1; } void checkName(std::string &_name) { if (name.empty()) { name = _name; } else { assert(name == _name); } } void define(std::string &_name, int _value) { assert(!defined()); assert(_value != -1); value = _value; checkName(_name); } int get() { assert(defined()); return value; } }; class LabelMap { std::map map; public: LabelMap() { } void addLabel(const Brig::BrigDirectiveLabel *lbl, int inst_index, const BrigObject *obj); Label *refLabel(const Brig::BrigDirectiveLabel *lbl, const BrigObject *obj); }; const int NumSegments = Brig::BRIG_SEGMENT_AMD_GCN; extern const char *segmentNames[]; class StorageElement { public: std::string name; uint64_t offset; uint64_t size; const Brig::BrigDirectiveVariable *brigSymbol; StorageElement(const char *_name, uint64_t _offset, int _size, const Brig::BrigDirectiveVariable *sym) : name(_name), offset(_offset), size(_size), brigSymbol(sym) { } }; class StorageSpace { typedef std::map DirVarToSE_map; std::list elements; AddrRangeMap elements_by_addr; DirVarToSE_map elements_by_brigptr; uint64_t nextOffset; public: StorageSpace(Brig::BrigSegment _class) : nextOffset(0) { } StorageElement *addSymbol(const Brig::BrigDirectiveVariable *sym, const BrigObject *obj); StorageElement* findSymbol(std::string name); StorageElement* findSymbol(uint64_t addr); StorageElement* findSymbol(const Brig::BrigDirectiveVariable *brigptr); int getSize() { return nextOffset; } void resetOffset() { nextOffset = 0; } }; class StorageMap { StorageMap *outerScopeMap; StorageSpace *space[NumSegments]; public: StorageMap(StorageMap *outerScope = nullptr); StorageElement *addSymbol(const Brig::BrigDirectiveVariable *sym, const BrigObject *obj); StorageElement* findSymbol(Brig::BrigSegment segment, std::string name); StorageElement* findSymbol(Brig::BrigSegment segment, uint64_t addr); StorageElement* findSymbol(Brig::BrigSegment segment, const Brig::BrigDirectiveVariable *brigptr); // overloaded version to avoid casting StorageElement* findSymbol(Brig::BrigSegment8_t segment, std::string name) { return findSymbol((Brig::BrigSegment)segment, name); } int getSize(Brig::BrigSegment segment); void resetOffset(Brig::BrigSegment segment); }; typedef enum { BT_DEFAULT, BT_B8, BT_U8, BT_U16, BT_U32, BT_U64, BT_S8, BT_S16, BT_S32, BT_S64, BT_F16, BT_F32, BT_F64, BT_NULL } base_type_e; /* @class HsailCode * the HsailCode class is used to store information * about HSA kernels stored in the BRIG format. it holds * all information about a kernel, function, or variable * symbol and provides methods for accessing that * information. */ class HsailCode final : public HsaCode { public: TheGpuISA::Decoder decoder; StorageMap *storageMap; LabelMap labelMap; uint32_t kernarg_start; uint32_t kernarg_end; int32_t private_size; int32_t readonly_size; // We track the maximum register index used for each register // class when we load the code so we can size the register files // appropriately (i.e., one more than the max index). uint32_t max_creg; // maximum c-register index uint32_t max_sreg; // maximum s-register index uint32_t max_dreg; // maximum d-register index HsailCode(const std::string &name_str, const Brig::BrigDirectiveExecutable *code_dir, const BrigObject *obj, StorageMap *objStorageMap); // this version is used to create a placeholder when // we encounter a kernel-related directive before the // kernel itself HsailCode(const std::string &name_str); void init(const Brig::BrigDirectiveExecutable *code_dir, const BrigObject *obj, StorageMap *objStorageMap); void generateHsaKernelInfo(HsaKernelInfo *hsaKernelInfo) const { hsaKernelInfo->sRegCount = max_sreg + 1; hsaKernelInfo->dRegCount = max_dreg + 1; hsaKernelInfo->cRegCount = max_creg + 1; hsaKernelInfo->static_lds_size = getSize(Brig::BRIG_SEGMENT_GROUP); hsaKernelInfo->private_mem_size = roundUp(getSize(Brig::BRIG_SEGMENT_PRIVATE), 8); hsaKernelInfo->spill_mem_size = roundUp(getSize(Brig::BRIG_SEGMENT_SPILL), 8); } int getSize(MemorySegment segment) const { Brig::BrigSegment brigSeg; switch (segment) { case MemorySegment::NONE: brigSeg = Brig::BRIG_SEGMENT_NONE; break; case MemorySegment::FLAT: brigSeg = Brig::BRIG_SEGMENT_FLAT; break; case MemorySegment::GLOBAL: brigSeg = Brig::BRIG_SEGMENT_GLOBAL; break; case MemorySegment::READONLY: brigSeg = Brig::BRIG_SEGMENT_READONLY; break; case MemorySegment::KERNARG: brigSeg = Brig::BRIG_SEGMENT_KERNARG; break; case MemorySegment::GROUP: brigSeg = Brig::BRIG_SEGMENT_GROUP; break; case MemorySegment::PRIVATE: brigSeg = Brig::BRIG_SEGMENT_PRIVATE; break; case MemorySegment::SPILL: brigSeg = Brig::BRIG_SEGMENT_SPILL; break; case MemorySegment::ARG: brigSeg = Brig::BRIG_SEGMENT_ARG; break; case MemorySegment::EXTSPACE0: brigSeg = Brig::BRIG_SEGMENT_AMD_GCN; break; default: fatal("Unknown BrigSegment type.\n"); } return getSize(brigSeg); } private: int getSize(Brig::BrigSegment segment) const { if (segment == Brig::BRIG_SEGMENT_PRIVATE) { // with the code generated by new HSA compiler the assertion // does not hold anymore.. //assert(private_size != -1); return private_size; } else { return storageMap->getSize(segment); } } public: StorageElement* findSymbol(Brig::BrigSegment segment, uint64_t addr) { return storageMap->findSymbol(segment, addr); } void setPrivateSize(int32_t _private_size) { private_size = _private_size; } Label* refLabel(const Brig::BrigDirectiveLabel *lbl, const BrigObject *obj) { return labelMap.refLabel(lbl, obj); } }; #endif // __HSAIL_CODE_HH__