brig_object.cc revision 11308
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, Anthony Gutierrez
34 */
35
36#include "gpu-compute/brig_object.hh"
37
38#include <fcntl.h>
39#include <sys/mman.h>
40#include <sys/types.h>
41#include <unistd.h>
42
43#include <cassert>
44#include <cstddef>
45#include <cstdlib>
46
47#include "arch/hsail/Brig.h"
48#include "base/misc.hh"
49#include "base/trace.hh"
50#include "debug/BRIG.hh"
51#include "debug/HSAILObject.hh"
52#include "debug/HSALoader.hh"
53
54using namespace Brig;
55
56std::vector<std::function<HsaObject*(const std::string&, int, uint8_t*)>>
57    HsaObject::tryFileFuncs = { BrigObject::tryFile };
58
59extern int getBrigDataTypeBytes(BrigType16_t t);
60
61const char *BrigObject::sectionNames[] =
62{
63    "hsa_data",
64    "hsa_code",
65    "hsa_operand",
66    ".shstrtab"
67};
68
69const char *segmentNames[] =
70{
71    "none",
72    "flat",
73    "global",
74    "readonly",
75    "kernarg",
76    "group",
77    "private",
78    "spill",
79    "args"
80};
81
82const uint8_t*
83BrigObject::getSectionOffset(enum SectionIndex sec, int offs) const
84{
85    // allow offs == size for dummy end pointers
86    assert(offs <= sectionInfo[sec].size);
87
88    return sectionInfo[sec].ptr + offs;
89}
90
91const char*
92BrigObject::getString(int offs) const
93{
94    return (const char*)(getSectionOffset(DataSectionIndex, offs) + 4);
95}
96
97const BrigBase*
98BrigObject::getCodeSectionEntry(int offs) const
99{
100    return (const BrigBase*)getSectionOffset(CodeSectionIndex, offs);
101}
102
103const BrigData*
104BrigObject::getBrigBaseData(int offs) const
105{
106    return (Brig::BrigData*)(getSectionOffset(DataSectionIndex, offs));
107}
108
109const uint8_t*
110BrigObject::getData(int offs) const
111{
112    return getSectionOffset(DataSectionIndex, offs);
113}
114
115const BrigOperand*
116BrigObject::getOperand(int offs) const
117{
118    return (const BrigOperand*)getSectionOffset(OperandsSectionIndex, offs);
119}
120
121unsigned
122BrigObject::getOperandPtr(int offs, int index) const
123{
124    unsigned *op_offs = (unsigned*)(getData(offs + 4 * (index + 1)));
125
126    return *op_offs;
127}
128
129const BrigInstBase*
130BrigObject::getInst(int offs) const
131{
132    return (const BrigInstBase*)getSectionOffset(CodeSectionIndex, offs);
133}
134
135HsaCode*
136BrigObject::getKernel(const std::string &name) const
137{
138    return nullptr;
139}
140
141HsaCode*
142BrigObject::getFunction(const std::string &name) const
143{
144    for (int i = 0; i < functions.size(); ++i) {
145        if (functions[i]->name() == name) {
146            return functions[i];
147        }
148    }
149
150    return nullptr;
151}
152
153void
154BrigObject::processDirectives(const BrigBase *dirPtr, const BrigBase *endPtr,
155                              StorageMap *storageMap)
156{
157    while (dirPtr < endPtr) {
158        if (!dirPtr->byteCount) {
159            fatal("Bad directive size 0\n");
160        }
161
162        // calculate next pointer now so we can override it if needed
163        const BrigBase *nextDirPtr = brigNext(dirPtr);
164
165        DPRINTF(HSAILObject, "Code section entry kind: #%x, byte count: %d\n",
166                dirPtr->kind, dirPtr->byteCount);
167
168        switch (dirPtr->kind) {
169          case BRIG_KIND_DIRECTIVE_FUNCTION:
170            {
171                const BrigDirectiveExecutable *p M5_VAR_USED =
172                    reinterpret_cast<const BrigDirectiveExecutable*>(dirPtr);
173
174                DPRINTF(HSAILObject,"DIRECTIVE_FUNCTION: %s offset: "
175                        "%d next: %d\n", getString(p->name),
176                        p->firstCodeBlockEntry, p->nextModuleEntry);
177
178                if (p->firstCodeBlockEntry != p->nextModuleEntry) {
179                    panic("Function calls are not fully supported yet!!: %s\n",
180                          getString(p->name));
181
182                    const char *name = getString(p->name);
183
184                    HsailCode *code_obj = nullptr;
185
186                    for (int i = 0; i < functions.size(); ++i) {
187                        if (functions[i]->name() == name) {
188                            code_obj = functions[i];
189                            break;
190                        }
191                    }
192
193                    if (!code_obj) {
194                        // create new local storage map for kernel-local symbols
195                        code_obj = new HsailCode(name, p, this,
196                                                 new StorageMap(storageMap));
197                        functions.push_back(code_obj);
198                    } else {
199                        panic("Multiple definition of Function!!: %s\n",
200                              getString(p->name));
201                    }
202
203                }
204                nextDirPtr = getCodeSectionEntry(p->nextModuleEntry);
205            }
206            break;
207
208          case BRIG_KIND_DIRECTIVE_KERNEL:
209            {
210                const BrigDirectiveExecutable *p =
211                    reinterpret_cast<const BrigDirectiveExecutable*>(dirPtr);
212
213                DPRINTF(HSAILObject,"DIRECTIVE_KERNEL: %s offset: %d count: "
214                        "next: %d\n", getString(p->name),
215                        p->firstCodeBlockEntry, p->nextModuleEntry);
216
217                const char *name = getString(p->name);
218
219                if (name[0] == '&')
220                    name++;
221
222                std::string str = name;
223                char *temp;
224                int len = str.length();
225
226                if (str[len - 1] >= 'a' && str[len - 1] <= 'z') {
227                    temp = new char[str.size() + 1];
228                    std::copy(str.begin(), str.end() , temp);
229                    temp[str.size()] = '\0';
230                } else {
231                    temp = new char[str.size()];
232                    std::copy(str.begin(), str.end() - 1 , temp);
233                    temp[str.size() - 1 ] = '\0';
234                }
235
236                std::string kernel_name = temp;
237                delete[] temp;
238
239                HsailCode *code_obj = nullptr;
240
241                for (const auto &kernel : kernels) {
242                    if (kernel->name() == kernel_name) {
243                        code_obj = kernel;
244                        break;
245                    }
246                }
247
248                if (!code_obj) {
249                    // create new local storage map for kernel-local symbols
250                    code_obj = new HsailCode(kernel_name, p, this,
251                                             new StorageMap(storageMap));
252
253                    kernels.push_back(code_obj);
254                }
255
256                nextDirPtr = getCodeSectionEntry(p->nextModuleEntry);
257            }
258            break;
259
260          case BRIG_KIND_DIRECTIVE_VARIABLE:
261            {
262                const BrigDirectiveVariable *p =
263                    reinterpret_cast<const BrigDirectiveVariable*>(dirPtr);
264
265                uint64_t readonlySize_old =
266                    storageMap->getSize(BRIG_SEGMENT_READONLY);
267
268                StorageElement* se = storageMap->addSymbol(p, this);
269
270                DPRINTF(HSAILObject, "DIRECTIVE_VARIABLE, symbol %s\n",
271                        getString(p->name));
272
273                if (p->segment == BRIG_SEGMENT_READONLY) {
274                    // readonly memory has initialization data
275                    uint8_t* readonlyData_old = readonlyData;
276
277                    readonlyData =
278                        new uint8_t[storageMap->getSize(BRIG_SEGMENT_READONLY)];
279
280                    if (p->init) {
281                        if ((p->type == BRIG_TYPE_ROIMG) ||
282                            (p->type == BRIG_TYPE_WOIMG) ||
283                            (p->type == BRIG_TYPE_SAMP) ||
284                            (p->type == BRIG_TYPE_SIG32) ||
285                            (p->type == BRIG_TYPE_SIG64)) {
286                            panic("Read only data type not supported: %s\n",
287                                  getString(p->name));
288                        }
289
290                        const BrigOperand *brigOp = getOperand(p->init);
291                        assert(brigOp->kind ==
292                               BRIG_KIND_OPERAND_CONSTANT_BYTES);
293
294                        const Brig::BrigData *operand_data M5_VAR_USED =
295                            getBrigBaseData(((BrigOperandConstantBytes*)
296                                            brigOp)->bytes);
297
298                        assert((operand_data->byteCount / 4) > 0);
299
300                        uint8_t *symbol_data =
301                            (uint8_t*)getData(((BrigOperandConstantBytes*)
302                                              brigOp)->bytes + 4);
303
304                        // copy the old data and add the new data
305                        if (readonlySize_old > 0) {
306                            memcpy(readonlyData, readonlyData_old,
307                                   readonlySize_old);
308                        }
309
310                        memcpy(readonlyData + se->offset, symbol_data,
311                               se->size);
312
313                        delete[] readonlyData_old;
314                   }
315                }
316            }
317            break;
318
319          case BRIG_KIND_DIRECTIVE_LABEL:
320            {
321              const BrigDirectiveLabel M5_VAR_USED *p =
322                    reinterpret_cast<const BrigDirectiveLabel*>(dirPtr);
323
324              panic("Label directives cannot be at the module level: %s\n",
325                    getString(p->name));
326
327            }
328            break;
329
330          case BRIG_KIND_DIRECTIVE_COMMENT:
331            {
332              const BrigDirectiveComment M5_VAR_USED *p =
333                  reinterpret_cast<const BrigDirectiveComment*>(dirPtr);
334
335              DPRINTF(HSAILObject, "DIRECTIVE_COMMENT: %s\n",
336                      getString(p->name));
337            }
338            break;
339
340          case BRIG_KIND_DIRECTIVE_LOC:
341            {
342                DPRINTF(HSAILObject, "BRIG_DIRECTIVE_LOC\n");
343            }
344            break;
345
346          case BRIG_KIND_DIRECTIVE_MODULE:
347            {
348                const BrigDirectiveModule M5_VAR_USED *p =
349                    reinterpret_cast<const BrigDirectiveModule*>(dirPtr);
350
351                DPRINTF(HSAILObject, "BRIG_DIRECTIVE_MODULE: %s\n",
352                        getString(p->name));
353            }
354            break;
355
356          case BRIG_KIND_DIRECTIVE_CONTROL:
357            {
358                DPRINTF(HSAILObject, "DIRECTIVE_CONTROL\n");
359            }
360            break;
361
362          case BRIG_KIND_DIRECTIVE_PRAGMA:
363            {
364                DPRINTF(HSAILObject, "DIRECTIVE_PRAGMA\n");
365            }
366            break;
367
368          case BRIG_KIND_DIRECTIVE_EXTENSION:
369            {
370                DPRINTF(HSAILObject, "DIRECTIVE_EXTENSION\n");
371            }
372            break;
373
374          case BRIG_KIND_DIRECTIVE_ARG_BLOCK_START:
375            {
376                DPRINTF(HSAILObject, "DIRECTIVE_ARG_BLOCK_START\n");
377            }
378            break;
379
380          case BRIG_KIND_DIRECTIVE_ARG_BLOCK_END:
381            {
382                DPRINTF(HSAILObject, "DIRECTIVE_ARG_BLOCK_END\n");
383            }
384            break;
385          default:
386            if (dirPtr->kind >= BRIG_KIND_INST_BEGIN &&
387                dirPtr->kind <= BRIG_KIND_INST_END)
388                break;
389
390            if (dirPtr->kind >= BRIG_KIND_OPERAND_BEGIN &&
391                dirPtr->kind <= BRIG_KIND_OPERAND_END)
392                break;
393
394            warn("Unknown Brig directive kind: %d\n", dirPtr->kind);
395            break;
396        }
397
398        dirPtr = nextDirPtr;
399    }
400}
401
402HsaObject*
403BrigObject::tryFile(const std::string &fname, int len, uint8_t *fileData)
404{
405    const char *brig_ident = "HSA BRIG";
406
407    if (memcmp(brig_ident, fileData, MODULE_IDENTIFICATION_LENGTH))
408        return nullptr;
409
410    return new BrigObject(fname, len, fileData);
411}
412
413BrigObject::BrigObject(const std::string &fname, int len, uint8_t *fileData)
414    : HsaObject(fname), storageMap(new StorageMap())
415{
416    const char *brig_ident = "HSA BRIG";
417    BrigModuleHeader *mod_hdr = (BrigModuleHeader*)fileData;
418
419    fatal_if(memcmp(brig_ident, mod_hdr, MODULE_IDENTIFICATION_LENGTH),
420             "%s is not a BRIG file\n", fname);
421
422    if (mod_hdr->brigMajor != BRIG_VERSION_BRIG_MAJOR ||
423        mod_hdr->brigMinor != BRIG_VERSION_BRIG_MINOR) {
424        fatal("%s: BRIG version mismatch, %d.%d != %d.%d\n",
425              fname, mod_hdr->brigMajor, mod_hdr->brigMinor,
426              BRIG_VERSION_BRIG_MAJOR, BRIG_VERSION_BRIG_MINOR);
427    }
428
429    fatal_if(mod_hdr->sectionCount != NumSectionIndices, "%s: BRIG section "
430             "count (%d) != expected value (%d)\n", fname,
431             mod_hdr->sectionCount, NumSectionIndices);
432
433    for (int i = 0; i < NumSectionIndices; ++i) {
434        sectionInfo[i].ptr = nullptr;
435    }
436
437    uint64_t *sec_idx_table = (uint64_t*)(fileData + mod_hdr->sectionIndex);
438    for (int sec_idx = 0; sec_idx < mod_hdr->sectionCount; ++sec_idx) {
439        uint8_t *sec_hdr_byte_ptr = fileData + sec_idx_table[sec_idx];
440        BrigSectionHeader *sec_hdr = (BrigSectionHeader*)sec_hdr_byte_ptr;
441
442        // It doesn't look like cprintf supports string precision values,
443        // but if this breaks, the right answer is to fix that
444        DPRINTF(HSAILObject, "found section %.*s\n", sec_hdr->nameLength,
445                sec_hdr->name);
446
447        sectionInfo[sec_idx].ptr = new uint8_t[sec_hdr->byteCount];
448        memcpy(sectionInfo[sec_idx].ptr, sec_hdr_byte_ptr, sec_hdr->byteCount);
449        sectionInfo[sec_idx].size = sec_hdr->byteCount;
450    }
451
452    BrigSectionHeader *code_hdr =
453        (BrigSectionHeader*)sectionInfo[CodeSectionIndex].ptr;
454
455    DPRINTF(HSAILObject, "Code section hdr, count: %d, hdr count: %d, "
456            "name len: %d\n", code_hdr->byteCount, code_hdr->headerByteCount,
457            code_hdr->nameLength);
458
459    // start at offset 4 to skip initial null entry (see Brig spec)
460    processDirectives(getCodeSectionEntry(code_hdr->headerByteCount),
461                      getCodeSectionEntry(sectionInfo[CodeSectionIndex].size),
462                      storageMap);
463
464    delete[] fileData;
465
466    DPRINTF(HSALoader, "BRIG object %s loaded.\n", fname);
467}
468
469BrigObject::~BrigObject()
470{
471    for (int i = 0; i < NumSectionIndices; ++i)
472        if (sectionInfo[i].ptr)
473            delete[] sectionInfo[i].ptr;
474}
475