operand.cc revision 11736:c33d3607683c
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 "arch/hsail/operand.hh"
37
38using namespace Brig;
39
40bool
41BaseRegOperand::init(unsigned opOffset, const BrigObject *obj,
42                     unsigned &maxRegIdx, char _regFileChar)
43{
44    regFileChar = _regFileChar;
45    const BrigOperand *brigOp = obj->getOperand(opOffset);
46
47    if (brigOp->kind != BRIG_KIND_OPERAND_REGISTER)
48        return false;
49
50    const BrigOperandRegister *brigRegOp = (const BrigOperandRegister*)brigOp;
51
52    regIdx = brigRegOp->regNum;
53
54    DPRINTF(GPUReg, "Operand: regNum: %d, kind: %d\n", regIdx,
55            brigRegOp->regKind);
56
57    maxRegIdx = std::max(maxRegIdx, regIdx);
58
59    return true;
60}
61
62void
63ListOperand::init(unsigned opOffset, const BrigObject *obj)
64{
65    const BrigOperand *brigOp = (const BrigOperand*)obj->getOperand(opOffset);
66
67    switch (brigOp->kind) {
68      case BRIG_KIND_OPERAND_CODE_LIST:
69        {
70            const BrigOperandCodeList *opList =
71                (const BrigOperandCodeList*)brigOp;
72
73            const Brig::BrigData *oprnd_data =
74                obj->getBrigBaseData(opList->elements);
75
76            // Note: for calls Dest list of operands could be size of 0.
77            elementCount = oprnd_data->byteCount / 4;
78
79            DPRINTF(GPUReg, "Operand Code List: # elements: %d\n",
80                    elementCount);
81
82            for (int i = 0; i < elementCount; ++i) {
83                unsigned *data_offset =
84                    (unsigned*)obj->getData(opList->elements + 4 * (i + 1));
85
86                const BrigDirectiveVariable *p =
87                    (const BrigDirectiveVariable*)obj->
88                    getCodeSectionEntry(*data_offset);
89
90                StorageElement *se = obj->currentCode->storageMap->
91                    findSymbol(BRIG_SEGMENT_ARG, p);
92
93                assert(se);
94                callArgs.push_back(se);
95            }
96        }
97        break;
98      default:
99        fatal("ListOperand: bad operand kind %d\n", brigOp->kind);
100    }
101}
102
103std::string
104ListOperand::disassemble()
105{
106    std::string res_str("");
107
108    for (auto it : callArgs) {
109        res_str += csprintf("%s ", it->name.c_str());
110    }
111
112    return res_str;
113}
114
115void
116FunctionRefOperand::init(unsigned opOffset, const BrigObject *obj)
117{
118    const BrigOperand *baseOp = obj->getOperand(opOffset);
119
120    if (baseOp->kind != BRIG_KIND_OPERAND_CODE_REF) {
121        fatal("FunctionRefOperand: bad operand kind %d\n", baseOp->kind);
122    }
123
124    const BrigOperandCodeRef *brigOp = (const BrigOperandCodeRef*)baseOp;
125
126    const BrigDirectiveExecutable *p =
127        (const BrigDirectiveExecutable*)obj->getCodeSectionEntry(brigOp->ref);
128
129    func_name = obj->getString(p->name);
130}
131
132std::string
133FunctionRefOperand::disassemble()
134{
135    DPRINTF(GPUReg, "Operand Func-ref name: %s\n", func_name);
136
137    return csprintf("%s", func_name);
138}
139
140bool
141BaseRegOperand::init_from_vect(unsigned opOffset, const BrigObject *obj,
142                               int at, unsigned &maxRegIdx, char _regFileChar)
143{
144    regFileChar = _regFileChar;
145    const BrigOperand *brigOp = obj->getOperand(opOffset);
146
147    if (brigOp->kind != BRIG_KIND_OPERAND_OPERAND_LIST)
148        return false;
149
150
151    const Brig::BrigOperandOperandList *brigRegVecOp =
152         (const Brig::BrigOperandOperandList*)brigOp;
153
154    unsigned *data_offset =
155        (unsigned*)obj->getData(brigRegVecOp->elements + 4 * (at + 1));
156
157    const BrigOperand *p =
158        (const BrigOperand*)obj->getOperand(*data_offset);
159    if (p->kind != BRIG_KIND_OPERAND_REGISTER) {
160        return false;
161    }
162
163    const BrigOperandRegister *brigRegOp =(const BrigOperandRegister*)p;
164
165    regIdx = brigRegOp->regNum;
166
167    DPRINTF(GPUReg, "Operand: regNum: %d, kind: %d \n", regIdx,
168            brigRegOp->regKind);
169
170    maxRegIdx = std::max(maxRegIdx, regIdx);
171
172    return true;
173}
174
175void
176BaseRegOperand::initWithStrOffset(unsigned strOffset, const BrigObject *obj,
177                     unsigned &maxRegIdx, char _regFileChar)
178{
179    const char *name = obj->getString(strOffset);
180    char *endptr;
181    regIdx = strtoul(name + 2, &endptr, 10);
182
183    if (name[0] != '$' || name[1] != _regFileChar) {
184        fatal("register operand parse error on \"%s\"\n", name);
185    }
186
187    maxRegIdx = std::max(maxRegIdx, regIdx);
188}
189
190unsigned SRegOperand::maxRegIdx;
191unsigned DRegOperand::maxRegIdx;
192unsigned CRegOperand::maxRegIdx;
193
194std::string
195SRegOperand::disassemble()
196{
197    return csprintf("$s%d", regIdx);
198}
199
200std::string
201DRegOperand::disassemble()
202{
203    return csprintf("$d%d", regIdx);
204}
205
206std::string
207CRegOperand::disassemble()
208{
209    return csprintf("$c%d", regIdx);
210}
211
212BrigRegOperandInfo
213findRegDataType(unsigned opOffset, const BrigObject *obj)
214{
215    const BrigOperand *baseOp = obj->getOperand(opOffset);
216
217    switch (baseOp->kind) {
218      case BRIG_KIND_OPERAND_REGISTER:
219        {
220            const BrigOperandRegister *op = (BrigOperandRegister*)baseOp;
221
222            return BrigRegOperandInfo((BrigKind16_t)baseOp->kind,
223                                      (BrigRegisterKind)op->regKind);
224        }
225        break;
226
227      case BRIG_KIND_OPERAND_WAVESIZE:
228        {
229            BrigRegisterKind reg_kind = BRIG_REGISTER_KIND_DOUBLE;
230            return BrigRegOperandInfo((BrigKind16_t)baseOp->kind, reg_kind);
231        }
232
233      case BRIG_KIND_OPERAND_OPERAND_LIST:
234        {
235            const BrigOperandOperandList *op =
236               (BrigOperandOperandList*)baseOp;
237            const BrigData *data_p = (BrigData*)obj->getData(op->elements);
238
239
240            int num_operands = 0;
241            BrigRegisterKind reg_kind = (BrigRegisterKind)0;
242            for (int offset = 0; offset < data_p->byteCount; offset += 4) {
243                const BrigOperand *op_p = (const BrigOperand *)
244                   obj->getOperand(((int *)data_p->bytes)[offset/4]);
245
246                if (op_p->kind == BRIG_KIND_OPERAND_REGISTER) {
247                    const BrigOperandRegister *brigRegOp =
248                       (const BrigOperandRegister*)op_p;
249                    reg_kind = (BrigRegisterKind)brigRegOp->regKind;
250                } else if (op_p->kind == BRIG_KIND_OPERAND_CONSTANT_BYTES) {
251                    uint16_t num_bytes =
252                       ((Brig::BrigOperandConstantBytes*)op_p)->base.byteCount
253                           - sizeof(BrigBase);
254                    if (num_bytes == sizeof(uint32_t)) {
255                        reg_kind = BRIG_REGISTER_KIND_SINGLE;
256                    } else if (num_bytes == sizeof(uint64_t)) {
257                        reg_kind = BRIG_REGISTER_KIND_DOUBLE;
258                    } else {
259                        fatal("OperandList: bad operand size %d\n", num_bytes);
260                    }
261                } else if (op_p->kind == BRIG_KIND_OPERAND_WAVESIZE) {
262                    reg_kind = BRIG_REGISTER_KIND_DOUBLE;
263                } else {
264                    fatal("OperandList: bad operand kind %d\n", op_p->kind);
265                }
266
267                num_operands++;
268            }
269            assert(baseOp->kind == BRIG_KIND_OPERAND_OPERAND_LIST);
270
271            return BrigRegOperandInfo((BrigKind16_t)baseOp->kind, reg_kind);
272        }
273        break;
274
275      case BRIG_KIND_OPERAND_ADDRESS:
276        {
277            const BrigOperandAddress *op = (BrigOperandAddress*)baseOp;
278
279            if (!op->reg) {
280                BrigType type = BRIG_TYPE_NONE;
281
282                if (op->symbol) {
283                    const BrigDirective *dir = (BrigDirective*)
284                        obj->getCodeSectionEntry(op->symbol);
285
286                    assert(dir->kind == BRIG_KIND_DIRECTIVE_VARIABLE);
287
288                    const BrigDirectiveVariable *sym =
289                       (const BrigDirectiveVariable*)dir;
290
291                    type = (BrigType)sym->type;
292                }
293                return BrigRegOperandInfo(BRIG_KIND_OPERAND_ADDRESS,
294                                          (BrigType)type);
295            } else {
296                const BrigOperandAddress *b = (const BrigOperandAddress*)baseOp;
297                const BrigOperand *reg = obj->getOperand(b->reg);
298                const BrigOperandRegister *rop = (BrigOperandRegister*)reg;
299
300                return BrigRegOperandInfo(BRIG_KIND_OPERAND_REGISTER,
301                                          (BrigRegisterKind)rop->regKind);
302            }
303        }
304        break;
305
306     default:
307       fatal("AddrOperand: bad operand kind %d\n", baseOp->kind);
308       break;
309   }
310}
311
312void
313AddrOperandBase::parseAddr(const BrigOperandAddress *op, const BrigObject *obj)
314{
315    assert(op->base.kind == BRIG_KIND_OPERAND_ADDRESS);
316
317    const BrigDirective *d =
318        (BrigDirective*)obj->getCodeSectionEntry(op->symbol);
319
320    assert(d->kind == BRIG_KIND_DIRECTIVE_VARIABLE);
321    const BrigDirectiveVariable *sym = (BrigDirectiveVariable*)d;
322    name = obj->getString(sym->name);
323
324    if (sym->segment != BRIG_SEGMENT_ARG) {
325        storageElement =
326            obj->currentCode->storageMap->findSymbol(sym->segment, name);
327        assert(storageElement);
328        offset = 0;
329    } else {
330        // sym->name does not work for BRIG_SEGMENT_ARG for the following case:
331        //
332        //     void foo(int a);
333        //     void bar(double a);
334        //
335        //     foo(...) --> arg_u32 %param_p0;
336        //                  st_arg_u32 $s0, [%param_p0];
337        //                  call &foo (%param_p0);
338        //     bar(...) --> arg_f64 %param_p0;
339        //                  st_arg_u64 $d0, [%param_p0];
340        //                  call &foo (%param_p0);
341        //
342        //  Both functions use the same variable name (param_p0)!!!
343        //
344        //  Maybe this is a bug in the compiler (I don't know).
345        //
346        // Solution:
347        // Use directive pointer (BrigDirectiveVariable) to differentiate 2
348        // versions of param_p0.
349        //
350        // Note this solution is kind of stupid, because we are pulling stuff
351        // out of the brig binary via the directive pointer and putting it into
352        // the symbol table, but now we are indexing the symbol table by the
353        // brig directive pointer! It makes the symbol table sort of pointless.
354        // But I don't want to mess with the rest of the infrastructure, so
355        // let's go with this for now.
356        //
357        // When we update the compiler again, we should see if this problem goes
358        // away. If so, we can fold some of this functionality into the code for
359        // kernel arguments. If not, maybe we can index the symbol name on a
360        // hash of the variable AND function name
361        storageElement = obj->currentCode->
362                 storageMap->findSymbol((Brig::BrigSegment)sym->segment, sym);
363
364        assert(storageElement);
365    }
366}
367
368uint64_t
369AddrOperandBase::calcUniformBase()
370{
371    // start with offset, will be 0 if not specified
372    uint64_t address = offset;
373
374    // add in symbol value if specified
375    if (storageElement) {
376        address += storageElement->offset;
377    }
378
379    return address;
380}
381
382std::string
383AddrOperandBase::disassemble(std::string reg_disassembly)
384{
385    std::string disasm;
386
387    if (offset || reg_disassembly != "") {
388        disasm += "[";
389
390        if (reg_disassembly != "") {
391            disasm += reg_disassembly;
392
393            if (offset > 0) {
394                disasm += "+";
395            }
396        }
397
398        if (offset) {
399            disasm += csprintf("%d", offset);
400        }
401
402        disasm += "]";
403    } else if (name) {
404        disasm += csprintf("[%s]", name);
405    }
406
407    return disasm;
408}
409
410void
411NoRegAddrOperand::init(unsigned opOffset, const BrigObject *obj)
412{
413    const BrigOperand *baseOp = obj->getOperand(opOffset);
414
415    if (baseOp->kind == BRIG_KIND_OPERAND_ADDRESS) {
416        BrigOperandAddress *addrOp = (BrigOperandAddress*)baseOp;
417        parseAddr(addrOp, obj);
418        offset = (uint64_t(addrOp->offset.hi) << 32) |
419                  uint64_t(addrOp->offset.lo);
420    } else {
421        fatal("NoRegAddrOperand: bad operand kind %d\n", baseOp->kind);
422    }
423
424}
425
426std::string
427NoRegAddrOperand::disassemble()
428{
429    return AddrOperandBase::disassemble(std::string(""));
430}
431
432void
433LabelOperand::init(unsigned opOffset, const BrigObject *obj)
434{
435    const BrigOperandCodeRef *op =
436        (const BrigOperandCodeRef*)obj->getOperand(opOffset);
437
438    assert(op->base.kind == BRIG_KIND_OPERAND_CODE_REF);
439
440    const BrigDirective *dir =
441        (const BrigDirective*)obj->getCodeSectionEntry(op->ref);
442
443    assert(dir->kind == BRIG_KIND_DIRECTIVE_LABEL);
444    label = obj->currentCode->refLabel((BrigDirectiveLabel*)dir, obj);
445}
446
447uint32_t
448LabelOperand::getTarget(Wavefront *w, int lane)
449{
450    return label->get();
451}
452
453std::string
454LabelOperand::disassemble()
455{
456    return label->name;
457}
458