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#include "gpu-compute/hsail_code.hh"
37
38#include "arch/gpu_types.hh"
39#include "arch/hsail/Brig.h"
40#include "arch/hsail/operand.hh"
41#include "config/the_gpu_isa.hh"
42#include "debug/BRIG.hh"
43#include "debug/HSAILObject.hh"
44#include "gpu-compute/brig_object.hh"
45#include "gpu-compute/gpu_static_inst.hh"
46#include "gpu-compute/kernel_cfg.hh"
47
48using namespace Brig;
49
50int getBrigDataTypeBytes(BrigType16_t t);
51
52HsailCode::HsailCode(const std::string &name_str)
53    : HsaCode(name_str), private_size(-1), readonly_size(-1)
54{
55}
56
57void
58HsailCode::init(const BrigDirectiveExecutable *code_dir, const BrigObject *obj,
59                StorageMap *objStorageMap)
60{
61    storageMap = objStorageMap;
62
63    // set pointer so that decoding process can find this kernel context when
64    // needed
65    obj->currentCode = this;
66
67    if (code_dir->base.kind != BRIG_KIND_DIRECTIVE_FUNCTION &&
68        code_dir->base.kind != BRIG_KIND_DIRECTIVE_KERNEL) {
69        fatal("unexpected directive kind %d inside kernel/function init\n",
70              code_dir->base.kind);
71    }
72
73    DPRINTF(HSAILObject, "Initializing code, first code block entry is: %d\n",
74            code_dir->firstCodeBlockEntry);
75
76    // clear these static vars so we can properly track the max index
77    // for this kernel
78    SRegOperand::maxRegIdx = 0;
79    DRegOperand::maxRegIdx = 0;
80    CRegOperand::maxRegIdx = 0;
81    setPrivateSize(0);
82
83    const BrigBase *entryPtr = brigNext((BrigBase*)code_dir);
84    const BrigBase *endPtr =
85        obj->getCodeSectionEntry(code_dir->nextModuleEntry);
86
87    // the instruction's byte address (relative to the base addr
88    // of the code section)
89    int inst_addr = 0;
90    // the index that points to the instruction in the instruction
91    // array
92    int inst_idx = 0;
93    std::vector<GPUStaticInst*> instructions;
94    int funcarg_size_scope = 0;
95
96    // walk through instructions in code section and directives in
97    // directive section in parallel, processing directives that apply
98    // when we reach the relevant code point.
99    while (entryPtr < endPtr) {
100        switch (entryPtr->kind) {
101          case BRIG_KIND_DIRECTIVE_VARIABLE:
102           {
103                const BrigDirectiveVariable *sym =
104                    (const BrigDirectiveVariable*)entryPtr;
105
106                DPRINTF(HSAILObject,"Initializing code, directive is "
107                        "kind_variable, symbol is: %s\n",
108                        obj->getString(sym->name));
109
110                StorageElement *se = storageMap->addSymbol(sym, obj);
111
112                if (sym->segment == BRIG_SEGMENT_PRIVATE) {
113                    setPrivateSize(se->size);
114                } else { // spill
115                    funcarg_size_scope += se->size;
116                }
117            }
118            break;
119
120          case BRIG_KIND_DIRECTIVE_LABEL:
121            {
122                const BrigDirectiveLabel *lbl =
123                    (const BrigDirectiveLabel*)entryPtr;
124
125                DPRINTF(HSAILObject,"Initializing code, directive is "
126                        "kind_label, label is: %s \n",
127                        obj->getString(lbl->name));
128
129                labelMap.addLabel(lbl, inst_addr, obj);
130            }
131            break;
132
133          case BRIG_KIND_DIRECTIVE_PRAGMA:
134            {
135                DPRINTF(HSAILObject, "Initializing code, directive "
136                        "is kind_pragma\n");
137            }
138            break;
139
140          case BRIG_KIND_DIRECTIVE_COMMENT:
141            {
142                DPRINTF(HSAILObject, "Initializing code, directive is "
143                        "kind_comment\n");
144            }
145            break;
146
147          case BRIG_KIND_DIRECTIVE_ARG_BLOCK_START:
148            {
149                DPRINTF(HSAILObject, "Initializing code, directive is "
150                        "kind_arg_block_start\n");
151
152                storageMap->resetOffset(BRIG_SEGMENT_ARG);
153                funcarg_size_scope = 0;
154            }
155            break;
156
157          case BRIG_KIND_DIRECTIVE_ARG_BLOCK_END:
158            {
159                DPRINTF(HSAILObject, "Initializing code, directive is "
160                        "kind_arg_block_end\n");
161
162                funcarg_size = funcarg_size < funcarg_size_scope ?
163                                              funcarg_size_scope : funcarg_size;
164            }
165            break;
166
167          case BRIG_KIND_DIRECTIVE_END:
168            DPRINTF(HSAILObject, "Initializing code, dircetive is "
169                    "kind_end\n");
170
171            break;
172
173          default:
174            if (entryPtr->kind >= BRIG_KIND_INST_BEGIN &&
175                entryPtr->kind <= BRIG_KIND_INST_END) {
176
177                BrigInstBase *instPtr = (BrigInstBase*)entryPtr;
178                TheGpuISA::MachInst machInst = { instPtr, obj };
179                GPUStaticInst *iptr = decoder.decode(machInst);
180
181                if (iptr) {
182                    DPRINTF(HSAILObject, "Initializing code, processing inst "
183                            "byte addr #%d idx %d: OPCODE=%d\n", inst_addr,
184                            inst_idx, instPtr->opcode);
185
186                    TheGpuISA::RawMachInst raw_inst = decoder.saveInst(iptr);
187                    iptr->instNum(inst_idx);
188                    iptr->instAddr(inst_addr);
189                    _insts.push_back(raw_inst);
190                    instructions.push_back(iptr);
191                }
192                inst_addr += sizeof(TheGpuISA::RawMachInst);
193                ++inst_idx;
194            } else if (entryPtr->kind >= BRIG_KIND_OPERAND_BEGIN &&
195                       entryPtr->kind < BRIG_KIND_OPERAND_END) {
196                warn("unexpected operand entry in code segment\n");
197            } else {
198                // there are surely some more cases we will need to handle,
199                // but we'll deal with them as we find them.
200                fatal("unexpected directive kind %d inside kernel scope\n",
201                      entryPtr->kind);
202            }
203        }
204
205        entryPtr = brigNext(entryPtr);
206    }
207
208    // compute Control Flow Graph for current kernel
209    ControlFlowInfo::assignImmediatePostDominators(instructions);
210
211    max_sreg = SRegOperand::maxRegIdx;
212    max_dreg = DRegOperand::maxRegIdx;
213    max_creg = CRegOperand::maxRegIdx;
214
215    obj->currentCode = nullptr;
216}
217
218HsailCode::HsailCode(const std::string &name_str,
219                     const BrigDirectiveExecutable *code_dir,
220                     const BrigObject *obj, StorageMap *objStorageMap)
221    : HsaCode(name_str), private_size(-1), readonly_size(-1)
222{
223    init(code_dir, obj, objStorageMap);
224}
225
226void
227LabelMap::addLabel(const Brig::BrigDirectiveLabel *lblDir, int inst_index,
228                   const BrigObject *obj)
229{
230    std::string lbl_name = obj->getString(lblDir->name);
231    Label &lbl = map[lbl_name];
232
233    if (lbl.defined()) {
234        fatal("Attempt to redefine existing label %s\n", lbl_name);
235    }
236
237    lbl.define(lbl_name, inst_index);
238    DPRINTF(HSAILObject, "label %s = %d\n", lbl_name, inst_index);
239}
240
241Label*
242LabelMap::refLabel(const Brig::BrigDirectiveLabel *lblDir,
243                   const BrigObject *obj)
244{
245    std::string name = obj->getString(lblDir->name);
246    Label &lbl = map[name];
247    lbl.checkName(name);
248
249    return &lbl;
250}
251
252int
253getBrigDataTypeBytes(BrigType16_t t)
254{
255    switch (t) {
256      case BRIG_TYPE_S8:
257      case BRIG_TYPE_U8:
258      case BRIG_TYPE_B8:
259        return 1;
260
261      case BRIG_TYPE_S16:
262      case BRIG_TYPE_U16:
263      case BRIG_TYPE_B16:
264      case BRIG_TYPE_F16:
265        return 2;
266
267      case BRIG_TYPE_S32:
268      case BRIG_TYPE_U32:
269      case BRIG_TYPE_B32:
270      case BRIG_TYPE_F32:
271        return 4;
272
273      case BRIG_TYPE_S64:
274      case BRIG_TYPE_U64:
275      case BRIG_TYPE_B64:
276      case BRIG_TYPE_F64:
277        return 8;
278
279      case BRIG_TYPE_B1:
280
281      default:
282        fatal("unhandled symbol data type %d", t);
283        return 0;
284    }
285}
286
287StorageElement*
288StorageSpace::addSymbol(const BrigDirectiveVariable *sym,
289                        const BrigObject *obj)
290{
291    const char *sym_name = obj->getString(sym->name);
292    uint64_t size = 0;
293    uint64_t offset = 0;
294
295    if (sym->type & BRIG_TYPE_ARRAY) {
296        size = getBrigDataTypeBytes(sym->type & ~BRIG_TYPE_ARRAY);
297        size *= (((uint64_t)sym->dim.hi) << 32 | (uint64_t)sym->dim.lo);
298
299        offset = roundUp(nextOffset, getBrigDataTypeBytes(sym->type &
300                         ~BRIG_TYPE_ARRAY));
301    } else {
302        size = getBrigDataTypeBytes(sym->type);
303        offset = roundUp(nextOffset, getBrigDataTypeBytes(sym->type));
304    }
305
306    nextOffset = offset + size;
307
308    DPRINTF(HSAILObject, "Adding SYMBOL %s size %d offset %#x, init: %d\n",
309            sym_name, size, offset, sym->init);
310
311    StorageElement* se = new StorageElement(sym_name, offset, size, sym);
312    elements.push_back(se);
313    elements_by_addr.insert(AddrRange(offset, offset + size - 1), se);
314    elements_by_brigptr[sym] = se;
315
316    return se;
317}
318
319StorageElement*
320StorageSpace::findSymbol(std::string name)
321{
322    for (auto it : elements) {
323        if (it->name == name) {
324            return it;
325        }
326    }
327
328    return nullptr;
329}
330
331StorageElement*
332StorageSpace::findSymbol(uint64_t addr)
333{
334    assert(elements_by_addr.size() > 0);
335
336    auto se = elements_by_addr.contains(addr);
337
338    if (se == elements_by_addr.end()) {
339        return nullptr;
340    } else {
341        return se->second;
342    }
343}
344
345StorageElement*
346StorageSpace::findSymbol(const BrigDirectiveVariable *brigptr)
347{
348    assert(elements_by_brigptr.size() > 0);
349
350    auto se = elements_by_brigptr.find(brigptr);
351
352    if (se == elements_by_brigptr.end()) {
353        return nullptr;
354    } else {
355        return se->second;
356    }
357}
358
359StorageMap::StorageMap(StorageMap *outerScope)
360    : outerScopeMap(outerScope)
361{
362    for (int i = 0; i < NumSegments; ++i)
363        space[i] = new StorageSpace((BrigSegment)i);
364}
365
366StorageElement*
367StorageMap::addSymbol(const BrigDirectiveVariable *sym, const BrigObject *obj)
368{
369    BrigSegment8_t segment = sym->segment;
370
371    assert(segment >= Brig::BRIG_SEGMENT_FLAT);
372    assert(segment < NumSegments);
373
374    return space[segment]->addSymbol(sym, obj);
375}
376
377int
378StorageMap::getSize(Brig::BrigSegment segment)
379{
380    assert(segment > Brig::BRIG_SEGMENT_GLOBAL);
381    assert(segment < NumSegments);
382
383    if (segment != Brig::BRIG_SEGMENT_GROUP &&
384        segment != Brig::BRIG_SEGMENT_READONLY) {
385        return space[segment]->getSize();
386    } else {
387        int ret = space[segment]->getSize();
388
389        if (outerScopeMap) {
390            ret += outerScopeMap->getSize(segment);
391        }
392
393        return ret;
394    }
395}
396
397void
398StorageMap::resetOffset(Brig::BrigSegment segment)
399{
400    space[segment]->resetOffset();
401}
402
403StorageElement*
404StorageMap::findSymbol(BrigSegment segment, std::string name)
405{
406    StorageElement *se = space[segment]->findSymbol(name);
407
408    if (se)
409        return se;
410
411    if (outerScopeMap)
412        return outerScopeMap->findSymbol(segment, name);
413
414    return nullptr;
415}
416
417StorageElement*
418StorageMap::findSymbol(Brig::BrigSegment segment, uint64_t addr)
419{
420    StorageSpace *sp = space[segment];
421
422    if (!sp) {
423        // there is no memory in segment?
424        return nullptr;
425    }
426
427    StorageElement *se = sp->findSymbol(addr);
428
429    if (se)
430        return se;
431
432    if (outerScopeMap)
433        return outerScopeMap->findSymbol(segment, addr);
434
435    return nullptr;
436
437}
438
439StorageElement*
440StorageMap::findSymbol(Brig::BrigSegment segment,
441                       const BrigDirectiveVariable *brigptr)
442{
443    StorageSpace *sp = space[segment];
444
445    if (!sp) {
446        // there is no memory in segment?
447        return nullptr;
448    }
449
450    StorageElement *se = sp->findSymbol(brigptr);
451
452    if (se)
453        return se;
454
455    if (outerScopeMap)
456        return outerScopeMap->findSymbol(segment, brigptr);
457
458    return nullptr;
459
460}
461