operand.cc revision 11308:7d8836fd043d
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_OPERAND_LIST:
228        {
229             const BrigOperandOperandList *op =
230                (BrigOperandOperandList*)baseOp;
231             const BrigData *data_p = (BrigData*)obj->getData(op->elements);
232
233
234             int num_operands = 0;
235             BrigRegisterKind reg_kind = (BrigRegisterKind)0;
236             for (int offset = 0; offset < data_p->byteCount; offset += 4) {
237                 const BrigOperand *op_p = (const BrigOperand *)
238                    obj->getOperand(((int *)data_p->bytes)[offset/4]);
239
240                 if (op_p->kind == BRIG_KIND_OPERAND_REGISTER) {
241                     const BrigOperandRegister *brigRegOp =
242                        (const BrigOperandRegister*)op_p;
243                     reg_kind = (BrigRegisterKind)brigRegOp->regKind;
244                 } else if (op_p->kind == BRIG_KIND_OPERAND_CONSTANT_BYTES) {
245                     uint16_t num_bytes =
246                        ((Brig::BrigOperandConstantBytes*)op_p)->base.byteCount
247                            - sizeof(BrigBase);
248                     if (num_bytes == sizeof(uint32_t)) {
249                         reg_kind = BRIG_REGISTER_KIND_SINGLE;
250                     } else if (num_bytes == sizeof(uint64_t)) {
251                         reg_kind = BRIG_REGISTER_KIND_DOUBLE;
252                     } else {
253                         fatal("OperandList: bad operand size %d\n", num_bytes);
254                     }
255                 } else {
256                     fatal("OperandList: bad operand kind %d\n", op_p->kind);
257                 }
258
259                 num_operands++;
260             }
261             assert(baseOp->kind == BRIG_KIND_OPERAND_OPERAND_LIST);
262
263             return BrigRegOperandInfo((BrigKind16_t)baseOp->kind, reg_kind);
264        }
265        break;
266
267      case BRIG_KIND_OPERAND_ADDRESS:
268        {
269            const BrigOperandAddress *op = (BrigOperandAddress*)baseOp;
270
271            if (!op->reg) {
272                BrigType type = BRIG_TYPE_NONE;
273
274                if (op->symbol) {
275                    const BrigDirective *dir = (BrigDirective*)
276                        obj->getCodeSectionEntry(op->symbol);
277
278                    assert(dir->kind == BRIG_KIND_DIRECTIVE_VARIABLE);
279
280                    const BrigDirectiveVariable *sym =
281                       (const BrigDirectiveVariable*)dir;
282
283                    type = (BrigType)sym->type;
284                }
285                return BrigRegOperandInfo(BRIG_KIND_OPERAND_ADDRESS,
286                                          (BrigType)type);
287            } else {
288                const BrigOperandAddress *b = (const BrigOperandAddress*)baseOp;
289                const BrigOperand *reg = obj->getOperand(b->reg);
290                const BrigOperandRegister *rop = (BrigOperandRegister*)reg;
291
292                return BrigRegOperandInfo(BRIG_KIND_OPERAND_REGISTER,
293                                          (BrigRegisterKind)rop->regKind);
294            }
295        }
296        break;
297
298     default:
299       fatal("AddrOperand: bad operand kind %d\n", baseOp->kind);
300       break;
301   }
302}
303
304void
305AddrOperandBase::parseAddr(const BrigOperandAddress *op, const BrigObject *obj)
306{
307    assert(op->base.kind == BRIG_KIND_OPERAND_ADDRESS);
308
309    const BrigDirective *d =
310        (BrigDirective*)obj->getCodeSectionEntry(op->symbol);
311
312    assert(d->kind == BRIG_KIND_DIRECTIVE_VARIABLE);
313    const BrigDirectiveVariable *sym = (BrigDirectiveVariable*)d;
314    name = obj->getString(sym->name);
315
316    if (sym->segment != BRIG_SEGMENT_ARG) {
317        storageElement =
318            obj->currentCode->storageMap->findSymbol(sym->segment, name);
319        assert(storageElement);
320        offset = 0;
321    } else {
322        // sym->name does not work for BRIG_SEGMENT_ARG for the following case:
323        //
324        //     void foo(int a);
325        //     void bar(double a);
326        //
327        //     foo(...) --> arg_u32 %param_p0;
328        //                  st_arg_u32 $s0, [%param_p0];
329        //                  call &foo (%param_p0);
330        //     bar(...) --> arg_f64 %param_p0;
331        //                  st_arg_u64 $d0, [%param_p0];
332        //                  call &foo (%param_p0);
333        //
334        //  Both functions use the same variable name (param_p0)!!!
335        //
336        //  Maybe this is a bug in the compiler (I don't know).
337        //
338        // Solution:
339        // Use directive pointer (BrigDirectiveVariable) to differentiate 2
340        // versions of param_p0.
341        //
342        // Note this solution is kind of stupid, because we are pulling stuff
343        // out of the brig binary via the directive pointer and putting it into
344        // the symbol table, but now we are indexing the symbol table by the
345        // brig directive pointer! It makes the symbol table sort of pointless.
346        // But I don't want to mess with the rest of the infrastructure, so
347        // let's go with this for now.
348        //
349        // When we update the compiler again, we should see if this problem goes
350        // away. If so, we can fold some of this functionality into the code for
351        // kernel arguments. If not, maybe we can index the symbol name on a
352        // hash of the variable AND function name
353        storageElement = obj->currentCode->
354                 storageMap->findSymbol((Brig::BrigSegment)sym->segment, sym);
355
356        assert(storageElement);
357    }
358}
359
360uint64_t
361AddrOperandBase::calcUniformBase()
362{
363    // start with offset, will be 0 if not specified
364    uint64_t address = offset;
365
366    // add in symbol value if specified
367    if (storageElement) {
368        address += storageElement->offset;
369    }
370
371    return address;
372}
373
374std::string
375AddrOperandBase::disassemble(std::string reg_disassembly)
376{
377    std::string disasm;
378
379    if (offset || reg_disassembly != "") {
380        disasm += "[";
381
382        if (reg_disassembly != "") {
383            disasm += reg_disassembly;
384
385            if (offset > 0) {
386                disasm += "+";
387            }
388        }
389
390        if (offset) {
391            disasm += csprintf("%d", offset);
392        }
393
394        disasm += "]";
395    } else if (name) {
396        disasm += csprintf("[%s]", name);
397    }
398
399    return disasm;
400}
401
402void
403NoRegAddrOperand::init(unsigned opOffset, const BrigObject *obj)
404{
405    const BrigOperand *baseOp = obj->getOperand(opOffset);
406
407    if (baseOp->kind == BRIG_KIND_OPERAND_ADDRESS) {
408        BrigOperandAddress *addrOp = (BrigOperandAddress*)baseOp;
409        parseAddr(addrOp, obj);
410        offset = (uint64_t(addrOp->offset.hi) << 32) |
411                  uint64_t(addrOp->offset.lo);
412    } else {
413        fatal("NoRegAddrOperand: bad operand kind %d\n", baseOp->kind);
414    }
415
416}
417
418std::string
419NoRegAddrOperand::disassemble()
420{
421    return AddrOperandBase::disassemble(std::string(""));
422}
423
424void
425LabelOperand::init(unsigned opOffset, const BrigObject *obj)
426{
427    const BrigOperandCodeRef *op =
428        (const BrigOperandCodeRef*)obj->getOperand(opOffset);
429
430    assert(op->base.kind == BRIG_KIND_OPERAND_CODE_REF);
431
432    const BrigDirective *dir =
433        (const BrigDirective*)obj->getCodeSectionEntry(op->ref);
434
435    assert(dir->kind == BRIG_KIND_DIRECTIVE_LABEL);
436    label = obj->currentCode->refLabel((BrigDirectiveLabel*)dir, obj);
437}
438
439uint32_t
440LabelOperand::getTarget(Wavefront *w, int lane)
441{
442    return label->get();
443}
444
445std::string
446LabelOperand::disassemble()
447{
448    return label->name;
449}
450