blob: 991946197fc51104ddbf46260d413c1ea7ec8d07 [file] [log] [blame]
/*
* 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;
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__