1/*
2 * Copyright (c) 2012-2015 Advanced Micro Devices, Inc.
3 * All rights reserved.
4 *
5 * For use for simulation and test purposes only
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Author: Steve Reinhardt
34 */
35
36#ifndef __HSAIL_CODE_HH__
37#define __HSAIL_CODE_HH__
38
39#include <cassert>
40#include <list>
41#include <map>
42#include <string>
43#include <vector>
44
45#include "arch/gpu_decoder.hh"
46#include "arch/hsail/Brig.h"
47#include "base/addr_range_map.hh"
48#include "base/intmath.hh"
49#include "config/the_gpu_isa.hh"
50#include "gpu-compute/hsa_code.hh"
51#include "gpu-compute/hsa_kernel_info.hh"
52#include "gpu-compute/misc.hh"
53
54class BrigObject;
55class GPUStaticInst;
56
57inline int
58popcount(uint64_t src, int sz)
59{
60    int cnt = 0;
61
62    for (int i = 0; i < sz; ++i) {
63        if (src & 1)
64            ++cnt;
65        src >>= 1;
66    }
67
68    return cnt;
69}
70
71inline int
72firstbit(uint64_t src, int sz)
73{
74    int i;
75
76    for (i = 0; i < sz; ++i) {
77        if (src & 1)
78            break;
79        src >>= 1;
80    }
81
82    return i;
83}
84
85inline int
86lastbit(uint64_t src, int sz)
87{
88    int i0 = -1;
89
90    for (int i = 0; i < sz; ++i) {
91        if (src & 1)
92            i0 = i;
93        src >>= 1;
94    }
95
96    return i0;
97}
98
99inline int
100signbit(uint64_t src, int sz)
101{
102    int i0 = -1;
103
104    if (src & (1 << (sz - 1))) {
105        for (int i = 0; i < sz - 1; ++i) {
106            if (!(src & 1))
107                i0 = i;
108            src >>= 1;
109        }
110    } else {
111        for (int i = 0; i < sz - 1; ++i) {
112            if (src & 1)
113                i0 = i;
114            src >>= 1;
115        }
116    }
117
118    return i0;
119}
120
121inline uint64_t
122bitrev(uint64_t src, int sz)
123{
124    uint64_t r = 0;
125
126    for (int i = 0; i < sz; ++i) {
127        r <<= 1;
128        if (src & 1)
129            r |= 1;
130        src >>= 1;
131    }
132
133    return r;
134}
135
136inline uint64_t
137mul_hi(uint32_t a, uint32_t b)
138{
139    return ((uint64_t)a * (uint64_t)b) >> 32;
140}
141
142inline uint64_t
143mul_hi(int32_t a, int32_t b)
144{
145    return ((int64_t)a * (int64_t)b) >> 32;
146}
147
148inline uint64_t
149mul_hi(uint64_t a, uint64_t b)
150{
151    return ((uint64_t)a * (uint64_t)b) >> 32;
152}
153
154inline uint64_t
155mul_hi(int64_t a, int64_t b)
156{
157    return ((int64_t)a * (int64_t)b) >> 32;
158}
159
160inline uint64_t
161mul_hi(double a, double b)
162{
163    return 0;
164}
165
166class Label
167{
168  public:
169    std::string name;
170    int value;
171
172    Label() : value(-1)
173    {
174    }
175
176    bool defined() { return value != -1; }
177
178    void
179    checkName(std::string &_name)
180    {
181        if (name.empty()) {
182            name = _name;
183        } else {
184            assert(name == _name);
185        }
186    }
187
188    void
189    define(std::string &_name, int _value)
190    {
191        assert(!defined());
192        assert(_value != -1);
193        value = _value;
194        checkName(_name);
195    }
196
197    int
198    get()
199    {
200        assert(defined());
201        return value;
202    }
203};
204
205class LabelMap
206{
207    std::map<std::string, Label> map;
208
209  public:
210    LabelMap() { }
211
212    void addLabel(const Brig::BrigDirectiveLabel *lbl, int inst_index,
213                  const BrigObject *obj);
214
215    Label *refLabel(const Brig::BrigDirectiveLabel *lbl,
216                    const BrigObject *obj);
217};
218
219const int NumSegments = Brig::BRIG_SEGMENT_AMD_GCN;
220
221extern const char *segmentNames[];
222
223class StorageElement
224{
225  public:
226    std::string name;
227    uint64_t offset;
228
229    uint64_t size;
230    const Brig::BrigDirectiveVariable *brigSymbol;
231    StorageElement(const char *_name, uint64_t _offset, int _size,
232                   const Brig::BrigDirectiveVariable *sym)
233        : name(_name), offset(_offset), size(_size), brigSymbol(sym)
234    {
235    }
236};
237
238class StorageSpace
239{
240    typedef std::map<const Brig::BrigDirectiveVariable*, StorageElement*>
241            DirVarToSE_map;
242
243    std::list<StorageElement*> elements;
244    AddrRangeMap<StorageElement*> elements_by_addr;
245    DirVarToSE_map elements_by_brigptr;
246
247    uint64_t nextOffset;
248
249  public:
250    StorageSpace(Brig::BrigSegment _class) : nextOffset(0)
251    {
252    }
253
254    StorageElement *addSymbol(const Brig::BrigDirectiveVariable *sym,
255                              const BrigObject *obj);
256
257    StorageElement* findSymbol(std::string name);
258    StorageElement* findSymbol(uint64_t addr);
259    StorageElement* findSymbol(const Brig::BrigDirectiveVariable *brigptr);
260
261    int getSize() { return nextOffset; }
262    void resetOffset() { nextOffset = 0; }
263};
264
265class StorageMap
266{
267    StorageMap *outerScopeMap;
268    StorageSpace *space[NumSegments];
269
270  public:
271    StorageMap(StorageMap *outerScope = nullptr);
272
273    StorageElement *addSymbol(const Brig::BrigDirectiveVariable *sym,
274                              const BrigObject *obj);
275
276    StorageElement* findSymbol(Brig::BrigSegment segment, std::string name);
277    StorageElement* findSymbol(Brig::BrigSegment segment, uint64_t addr);
278
279    StorageElement* findSymbol(Brig::BrigSegment segment,
280                               const Brig::BrigDirectiveVariable *brigptr);
281
282    // overloaded version to avoid casting
283    StorageElement*
284    findSymbol(Brig::BrigSegment8_t segment, std::string name)
285    {
286        return findSymbol((Brig::BrigSegment)segment, name);
287    }
288
289    int getSize(Brig::BrigSegment segment);
290    void resetOffset(Brig::BrigSegment segment);
291};
292
293typedef enum
294{
295    BT_DEFAULT,
296    BT_B8,
297    BT_U8,
298    BT_U16,
299    BT_U32,
300    BT_U64,
301    BT_S8,
302    BT_S16,
303    BT_S32,
304    BT_S64,
305    BT_F16,
306    BT_F32,
307    BT_F64,
308    BT_NULL
309} base_type_e;
310
311/* @class HsailCode
312 * the HsailCode class is used to store information
313 * about HSA kernels stored in the BRIG format. it holds
314 * all information about a kernel, function, or variable
315 * symbol and provides methods for accessing that
316 * information.
317 */
318
319class HsailCode final : public HsaCode
320{
321  public:
322    TheGpuISA::Decoder decoder;
323
324    StorageMap *storageMap;
325    LabelMap labelMap;
326    uint32_t kernarg_start;
327    uint32_t kernarg_end;
328    int32_t private_size;
329
330    int32_t readonly_size;
331
332    // We track the maximum register index used for each register
333    // class when we load the code so we can size the register files
334    // appropriately (i.e., one more than the max index).
335    uint32_t max_creg;    // maximum c-register index
336    uint32_t max_sreg;    // maximum s-register index
337    uint32_t max_dreg;    // maximum d-register index
338
339    HsailCode(const std::string &name_str,
340              const Brig::BrigDirectiveExecutable *code_dir,
341              const BrigObject *obj,
342              StorageMap *objStorageMap);
343
344    // this version is used to create a placeholder when
345    // we encounter a kernel-related directive before the
346    // kernel itself
347    HsailCode(const std::string &name_str);
348
349    void init(const Brig::BrigDirectiveExecutable *code_dir,
350              const BrigObject *obj, StorageMap *objStorageMap);
351
352    void
353    generateHsaKernelInfo(HsaKernelInfo *hsaKernelInfo) const
354    {
355        hsaKernelInfo->sRegCount = max_sreg + 1;
356        hsaKernelInfo->dRegCount = max_dreg + 1;
357        hsaKernelInfo->cRegCount = max_creg + 1;
358
359        hsaKernelInfo->static_lds_size = getSize(Brig::BRIG_SEGMENT_GROUP);
360
361        hsaKernelInfo->private_mem_size =
362            roundUp(getSize(Brig::BRIG_SEGMENT_PRIVATE), 8);
363
364        hsaKernelInfo->spill_mem_size =
365            roundUp(getSize(Brig::BRIG_SEGMENT_SPILL), 8);
366    }
367
368    int
369    getSize(MemorySegment segment) const
370    {
371        Brig::BrigSegment brigSeg;
372
373        switch (segment) {
374          case MemorySegment::NONE:
375            brigSeg = Brig::BRIG_SEGMENT_NONE;
376            break;
377          case MemorySegment::FLAT:
378            brigSeg = Brig::BRIG_SEGMENT_FLAT;
379            break;
380          case MemorySegment::GLOBAL:
381            brigSeg = Brig::BRIG_SEGMENT_GLOBAL;
382            break;
383          case MemorySegment::READONLY:
384            brigSeg = Brig::BRIG_SEGMENT_READONLY;
385            break;
386          case MemorySegment::KERNARG:
387            brigSeg = Brig::BRIG_SEGMENT_KERNARG;
388            break;
389          case MemorySegment::GROUP:
390            brigSeg = Brig::BRIG_SEGMENT_GROUP;
391            break;
392          case MemorySegment::PRIVATE:
393            brigSeg = Brig::BRIG_SEGMENT_PRIVATE;
394            break;
395          case MemorySegment::SPILL:
396            brigSeg = Brig::BRIG_SEGMENT_SPILL;
397            break;
398          case MemorySegment::ARG:
399            brigSeg = Brig::BRIG_SEGMENT_ARG;
400            break;
401          case MemorySegment::EXTSPACE0:
402            brigSeg = Brig::BRIG_SEGMENT_AMD_GCN;
403            break;
404          default:
405            fatal("Unknown BrigSegment type.\n");
406        }
407
408        return getSize(brigSeg);
409    }
410
411  private:
412    int
413    getSize(Brig::BrigSegment segment) const
414    {
415        if (segment == Brig::BRIG_SEGMENT_PRIVATE) {
416            // with the code generated by new HSA compiler the assertion
417            // does not hold anymore..
418            //assert(private_size != -1);
419            return private_size;
420        } else {
421            return storageMap->getSize(segment);
422        }
423    }
424
425  public:
426    StorageElement*
427    findSymbol(Brig::BrigSegment segment, uint64_t addr)
428    {
429        return storageMap->findSymbol(segment, addr);
430    }
431
432    void
433    setPrivateSize(int32_t _private_size)
434    {
435        private_size = _private_size;
436    }
437
438    Label*
439    refLabel(const Brig::BrigDirectiveLabel *lbl, const BrigObject *obj)
440    {
441        return labelMap.refLabel(lbl, obj);
442    }
443};
444
445#endif // __HSAIL_CODE_HH__
446