| /* |
| * 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 <cassert> |
| #include <list> |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #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<std::string, Label> 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<const Brig::BrigDirectiveVariable*, StorageElement*> |
| DirVarToSE_map; |
| |
| std::list<StorageElement*> elements; |
| AddrRangeMap<StorageElement*> elements_by_addr; |
| DirVarToSE_map elements_by_brigptr; |
| |
| uint64_t nextOffset; |
| Brig::BrigSegment segment; |
| |
| public: |
| StorageSpace(Brig::BrigSegment _class) |
| : nextOffset(0), segment(_class) |
| { |
| } |
| |
| 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__ |