448 lines
11 KiB
C++
448 lines
11 KiB
C++
/*
|
|
* 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__
|