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 __ARCH_HSAIL_OPERAND_HH__
37#define __ARCH_HSAIL_OPERAND_HH__
38
39/**
40 *  @file operand.hh
41 *
42 *  Defines classes encapsulating HSAIL instruction operands.
43 */
44
45#include <limits>
46#include <string>
47
48#include "arch/hsail/Brig.h"
49#include "base/trace.hh"
50#include "base/types.hh"
51#include "debug/GPUReg.hh"
52#include "enums/RegisterType.hh"
53#include "gpu-compute/brig_object.hh"
54#include "gpu-compute/compute_unit.hh"
55#include "gpu-compute/hsail_code.hh"
56#include "gpu-compute/shader.hh"
57#include "gpu-compute/vector_register_file.hh"
58#include "gpu-compute/wavefront.hh"
59
60class Label;
61class StorageElement;
62
63class BaseOperand
64{
65  public:
66    Enums::RegisterType registerType;
67    uint32_t regOperandSize;
68    BaseOperand() { registerType = Enums::RT_NONE; regOperandSize = 0; }
69    bool isVectorRegister() { return registerType == Enums::RT_VECTOR; }
70    bool isScalarRegister() { return registerType == Enums::RT_SCALAR; }
71    bool isCondRegister() { return registerType == Enums::RT_CONDITION; }
72    unsigned int regIndex() { return 0; }
73    uint32_t opSize() { return regOperandSize; }
74    virtual ~BaseOperand() { }
75};
76
77class BrigRegOperandInfo
78{
79  public:
80    Brig::BrigKind16_t kind;
81    Brig::BrigType type;
82    Brig::BrigRegisterKind regKind;
83
84    BrigRegOperandInfo(Brig::BrigKind16_t _kind,
85                       Brig::BrigRegisterKind _regKind)
86        : kind(_kind), regKind(_regKind)
87    {
88    }
89
90    BrigRegOperandInfo(Brig::BrigKind16_t _kind, Brig::BrigType _type)
91        : kind(_kind), type(_type)
92    {
93    }
94
95    BrigRegOperandInfo() : kind(Brig::BRIG_KIND_OPERAND_CONSTANT_BYTES),
96                           type(Brig::BRIG_TYPE_NONE)
97    {
98    }
99};
100
101BrigRegOperandInfo findRegDataType(unsigned opOffset, const BrigObject *obj);
102
103class BaseRegOperand : public BaseOperand
104{
105  public:
106    unsigned regIdx;
107    char regFileChar;
108
109    bool init(unsigned opOffset, const BrigObject *obj,
110              unsigned &maxRegIdx, char _regFileChar);
111
112    bool init_from_vect(unsigned opOffset, const BrigObject *obj, int at,
113                        unsigned &maxRegIdx, char _regFileChar);
114
115    void initWithStrOffset(unsigned strOffset, const BrigObject *obj,
116                           unsigned &maxRegIdx, char _regFileChar);
117    unsigned int regIndex() { return regIdx; }
118};
119
120class SRegOperand : public BaseRegOperand
121{
122  public:
123    static unsigned maxRegIdx;
124
125    bool
126    init(unsigned opOffset, const BrigObject *obj)
127    {
128        regOperandSize = sizeof(uint32_t);
129        registerType = Enums::RT_VECTOR;
130
131        return BaseRegOperand::init(opOffset, obj, maxRegIdx, 's');
132    }
133
134    bool
135    init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
136    {
137        regOperandSize = sizeof(uint32_t);
138        registerType = Enums::RT_VECTOR;
139
140        return BaseRegOperand::init_from_vect(opOffset, obj, at, maxRegIdx,
141                                              's');
142    }
143
144    void
145    initWithStrOffset(unsigned strOffset, const BrigObject *obj)
146    {
147        regOperandSize = sizeof(uint32_t);
148        registerType = Enums::RT_VECTOR;
149
150        return BaseRegOperand::initWithStrOffset(strOffset, obj, maxRegIdx,
151                                                 's');
152    }
153
154    template<typename OperandType>
155    OperandType
156    get(Wavefront *w, int lane)
157    {
158        assert(sizeof(OperandType) <= sizeof(uint32_t));
159        assert(regIdx < w->maxSpVgprs);
160        // if OperandType is smaller than 32-bit, we truncate the value
161        OperandType ret;
162        uint32_t vgprIdx;
163
164        switch (sizeof(OperandType)) {
165          case 1: // 1 byte operand
166              vgprIdx = w->remap(regIdx, 1, 1);
167              ret = (w->computeUnit->vrf[w->simdId]->
168                      read<uint32_t>(vgprIdx, lane)) & 0xff;
169            break;
170          case 2: // 2 byte operand
171              vgprIdx = w->remap(regIdx, 2, 1);
172              ret = (w->computeUnit->vrf[w->simdId]->
173                      read<uint32_t>(vgprIdx, lane)) & 0xffff;
174            break;
175          case 4: // 4 byte operand
176              vgprIdx = w->remap(regIdx,sizeof(OperandType), 1);
177              ret = w->computeUnit->vrf[w->simdId]->
178                  read<OperandType>(vgprIdx, lane);
179            break;
180          default:
181            panic("Bad OperandType\n");
182            break;
183        }
184
185        return (OperandType)ret;
186    }
187
188    // special get method for compatibility with LabelOperand
189    uint32_t
190    getTarget(Wavefront *w, int lane)
191    {
192        return get<uint32_t>(w, lane);
193    }
194
195    template<typename OperandType>
196    void set(Wavefront *w, int lane, OperandType &val);
197    std::string disassemble();
198};
199
200template<typename OperandType>
201void
202SRegOperand::set(Wavefront *w, int lane, OperandType &val)
203{
204    DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $s%d <- %d\n",
205            w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx, val);
206
207    assert(sizeof(OperandType) == sizeof(uint32_t));
208    assert(regIdx < w->maxSpVgprs);
209    uint32_t vgprIdx = w->remap(regIdx, sizeof(OperandType), 1);
210    w->computeUnit->vrf[w->simdId]->write<OperandType>(vgprIdx,val,lane);
211}
212
213template<>
214inline void
215SRegOperand::set(Wavefront *w, int lane, uint64_t &val)
216{
217    DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $s%d <- %d\n",
218            w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx, val);
219
220    assert(regIdx < w->maxSpVgprs);
221    uint32_t vgprIdx = w->remap(regIdx, sizeof(uint32_t), 1);
222    w->computeUnit->vrf[w->simdId]->write<uint32_t>(vgprIdx, val, lane);
223}
224
225class DRegOperand : public BaseRegOperand
226{
227  public:
228    static unsigned maxRegIdx;
229
230    bool
231    init(unsigned opOffset, const BrigObject *obj)
232    {
233        regOperandSize = sizeof(uint64_t);
234        registerType = Enums::RT_VECTOR;
235
236        return BaseRegOperand::init(opOffset, obj, maxRegIdx, 'd');
237    }
238
239    bool
240    init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
241    {
242        regOperandSize = sizeof(uint64_t);
243        registerType = Enums::RT_VECTOR;
244
245        return BaseRegOperand::init_from_vect(opOffset, obj, at, maxRegIdx,
246                                              'd');
247    }
248
249    void
250    initWithStrOffset(unsigned strOffset, const BrigObject *obj)
251    {
252        regOperandSize = sizeof(uint64_t);
253        registerType = Enums::RT_VECTOR;
254
255        return BaseRegOperand::initWithStrOffset(strOffset, obj, maxRegIdx,
256                                                 'd');
257    }
258
259    template<typename OperandType>
260    OperandType
261    get(Wavefront *w, int lane)
262    {
263        assert(sizeof(OperandType) <= sizeof(uint64_t));
264        // TODO: this check is valid only for HSAIL
265        assert(regIdx < w->maxDpVgprs);
266        uint32_t vgprIdx = w->remap(regIdx, sizeof(OperandType), 1);
267
268        return w->computeUnit->vrf[w->simdId]->read<OperandType>(vgprIdx,lane);
269    }
270
271    template<typename OperandType>
272    void
273    set(Wavefront *w, int lane, OperandType &val)
274    {
275        DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $d%d <- %d\n",
276                w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx,
277                val);
278
279        assert(sizeof(OperandType) <= sizeof(uint64_t));
280        // TODO: this check is valid only for HSAIL
281        assert(regIdx < w->maxDpVgprs);
282        uint32_t vgprIdx = w->remap(regIdx, sizeof(OperandType), 1);
283        w->computeUnit->vrf[w->simdId]->write<OperandType>(vgprIdx,val,lane);
284    }
285
286    std::string disassemble();
287};
288
289class CRegOperand : public BaseRegOperand
290{
291  public:
292    static unsigned maxRegIdx;
293
294    bool
295    init(unsigned opOffset, const BrigObject *obj)
296    {
297        regOperandSize = sizeof(uint8_t);
298        registerType = Enums::RT_CONDITION;
299
300        return BaseRegOperand::init(opOffset, obj, maxRegIdx, 'c');
301    }
302
303    bool
304    init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
305    {
306        regOperandSize = sizeof(uint8_t);
307        registerType = Enums::RT_CONDITION;
308
309        return BaseRegOperand::init_from_vect(opOffset, obj, at, maxRegIdx,
310                                              'c');
311    }
312
313    void
314    initWithStrOffset(unsigned strOffset, const BrigObject *obj)
315    {
316        regOperandSize = sizeof(uint8_t);
317        registerType = Enums::RT_CONDITION;
318
319        return BaseRegOperand::initWithStrOffset(strOffset, obj, maxRegIdx,
320                                                 'c');
321    }
322
323    template<typename OperandType>
324    OperandType
325    get(Wavefront *w, int lane)
326    {
327        assert(regIdx < w->condRegState->numRegs());
328
329        return w->condRegState->read<OperandType>((int)regIdx, lane);
330    }
331
332    template<typename OperandType>
333    void
334    set(Wavefront *w, int lane, OperandType &val)
335    {
336        DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: $c%d <- %d\n",
337                w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane, regIdx,
338                val);
339
340        assert(regIdx < w->condRegState->numRegs());
341        w->condRegState->write<OperandType>(regIdx,lane,val);
342    }
343
344    std::string disassemble();
345};
346
347template<typename T>
348class ImmOperand : public BaseOperand
349{
350  private:
351    uint16_t kind;
352  public:
353    T bits;
354
355    bool init(unsigned opOffset, const BrigObject *obj);
356    bool init_from_vect(unsigned opOffset, const BrigObject *obj, int at);
357    std::string disassemble();
358
359    template<typename OperandType>
360    OperandType
361    get(Wavefront *w)
362    {
363        assert(sizeof(OperandType) <= sizeof(T));
364        panic_if(w == nullptr, "WF pointer needs to be set");
365
366        switch (kind) {
367          // immediate operand is WF size
368          case Brig::BRIG_KIND_OPERAND_WAVESIZE:
369            return (OperandType)w->computeUnit->wfSize();
370            break;
371
372          default:
373            return *(OperandType*)&bits;
374            break;
375        }
376    }
377
378    // This version of get() takes a WF* and a lane id for
379    // compatibility with the register-based get() methods.
380    template<typename OperandType>
381    OperandType
382    get(Wavefront *w, int lane)
383    {
384        return get<OperandType>(w);
385    }
386};
387
388template<typename T>
389bool
390ImmOperand<T>::init(unsigned opOffset, const BrigObject *obj)
391{
392    const Brig::BrigOperand *brigOp = obj->getOperand(opOffset);
393
394    switch (brigOp->kind) {
395      // this is immediate operand
396      case Brig::BRIG_KIND_OPERAND_CONSTANT_BYTES:
397        {
398            DPRINTF(GPUReg, "sizeof(T): %lu, byteCount: %d\n", sizeof(T),
399                    brigOp->byteCount);
400
401            auto cbptr = (Brig::BrigOperandConstantBytes*)brigOp;
402
403            bits = *((T*)(obj->getData(cbptr->bytes + 4)));
404            kind = brigOp->kind;
405            return true;
406        }
407        break;
408
409      case Brig::BRIG_KIND_OPERAND_WAVESIZE:
410        kind = brigOp->kind;
411        bits = std::numeric_limits<unsigned long long>::digits;
412        return true;
413
414      default:
415        kind = Brig::BRIG_KIND_NONE;
416        return false;
417    }
418}
419
420template <typename T>
421bool
422ImmOperand<T>::init_from_vect(unsigned opOffset, const BrigObject *obj, int at)
423{
424    const Brig::BrigOperand *brigOp = obj->getOperand(opOffset);
425
426    if (brigOp->kind != Brig::BRIG_KIND_OPERAND_OPERAND_LIST) {
427        kind = Brig::BRIG_KIND_NONE;
428        return false;
429    }
430
431
432    const Brig::BrigOperandOperandList *brigVecOp =
433         (const Brig::BrigOperandOperandList *)brigOp;
434
435    unsigned *data_offset =
436        (unsigned *)obj->getData(brigVecOp->elements + 4 * (at + 1));
437
438    const Brig::BrigOperand *p =
439        (const Brig::BrigOperand *)obj->getOperand(*data_offset);
440
441    if (p->kind != Brig::BRIG_KIND_OPERAND_CONSTANT_BYTES) {
442        kind = Brig::BRIG_KIND_NONE;
443        return false;
444    }
445
446    return init(*data_offset, obj);
447}
448template<typename T>
449std::string
450ImmOperand<T>::disassemble()
451{
452    return csprintf("0x%08x", bits);
453}
454
455template<typename RegOperand, typename T>
456class RegOrImmOperand : public BaseOperand
457{
458  private:
459    bool is_imm;
460
461  public:
462    void setImm(const bool value) { is_imm = value; }
463
464    ImmOperand<T> imm_op;
465    RegOperand reg_op;
466
467    RegOrImmOperand() { is_imm = false; }
468    void init(unsigned opOffset, const BrigObject *obj);
469    void init_from_vect(unsigned opOffset, const BrigObject *obj, int at);
470    std::string disassemble();
471
472    template<typename OperandType>
473    OperandType
474    get(Wavefront *w, int lane)
475    {
476        return is_imm ?  imm_op.template get<OperandType>(w) :
477                         reg_op.template get<OperandType>(w, lane);
478    }
479
480    uint32_t
481    opSize()
482    {
483        if (!is_imm) {
484            return reg_op.opSize();
485        }
486
487        return 0;
488    }
489
490    bool
491    isVectorRegister()
492    {
493        if (!is_imm) {
494            return reg_op.registerType == Enums::RT_VECTOR;
495        }
496        return false;
497    }
498
499    bool
500    isCondRegister()
501    {
502        if (!is_imm) {
503            return reg_op.registerType == Enums::RT_CONDITION;
504        }
505
506        return false;
507    }
508
509    bool
510    isScalarRegister()
511    {
512        if (!is_imm) {
513            return reg_op.registerType == Enums::RT_SCALAR;
514        }
515
516        return false;
517    }
518
519    unsigned int
520    regIndex()
521    {
522        if (!is_imm) {
523            return reg_op.regIndex();
524        }
525        return 0;
526    }
527};
528
529template<typename RegOperand, typename T>
530void
531RegOrImmOperand<RegOperand, T>::init(unsigned opOffset, const BrigObject *obj)
532{
533    is_imm = false;
534
535    if (reg_op.init(opOffset, obj)) {
536        return;
537    }
538
539    if (imm_op.init(opOffset, obj)) {
540        is_imm = true;
541        return;
542    }
543
544    fatal("RegOrImmOperand::init(): bad operand kind %d\n",
545          obj->getOperand(opOffset)->kind);
546}
547
548template<typename RegOperand, typename T>
549void
550RegOrImmOperand<RegOperand, T>::init_from_vect(unsigned opOffset,
551                                               const BrigObject *obj, int at)
552{
553    if (reg_op.init_from_vect(opOffset, obj, at)) {
554        is_imm = false;
555
556        return;
557    }
558
559    if (imm_op.init_from_vect(opOffset, obj, at)) {
560        is_imm = true;
561
562        return;
563    }
564
565    fatal("RegOrImmOperand::init(): bad operand kind %d\n",
566          obj->getOperand(opOffset)->kind);
567}
568
569template<typename RegOperand, typename T>
570std::string
571RegOrImmOperand<RegOperand, T>::disassemble()
572{
573    return is_imm ? imm_op.disassemble() : reg_op.disassemble();
574}
575
576typedef RegOrImmOperand<SRegOperand, uint32_t> SRegOrImmOperand;
577typedef RegOrImmOperand<DRegOperand, uint64_t> DRegOrImmOperand;
578typedef RegOrImmOperand<CRegOperand, bool> CRegOrImmOperand;
579
580class AddrOperandBase : public BaseOperand
581{
582  protected:
583    // helper function for init()
584    void parseAddr(const Brig::BrigOperandAddress *op, const BrigObject *obj);
585
586    // helper function for disassemble()
587    std::string disassemble(std::string reg_disassembly);
588    uint64_t calcUniformBase();
589
590  public:
591    virtual void calcVector(Wavefront *w, std::vector<Addr> &addrVec) = 0;
592    virtual uint64_t calcLane(Wavefront *w, int lane=0) = 0;
593
594    int64_t offset;
595    const char *name = nullptr;
596    StorageElement *storageElement;
597};
598
599template<typename RegOperandType>
600class RegAddrOperand : public AddrOperandBase
601{
602  public:
603    RegOperandType reg;
604    void init(unsigned opOffset, const BrigObject *obj);
605    uint64_t calcUniform();
606    void calcVector(Wavefront *w, std::vector<Addr> &addrVec);
607    uint64_t calcLane(Wavefront *w, int lane=0);
608    uint32_t opSize() { return reg.opSize(); }
609    bool isVectorRegister() { return reg.registerType == Enums::RT_VECTOR; }
610    bool isCondRegister() { return reg.registerType == Enums::RT_CONDITION; }
611    bool isScalarRegister() { return reg.registerType == Enums::RT_SCALAR; }
612    unsigned int regIndex() { return reg.regIndex(); }
613    std::string disassemble();
614};
615
616template<typename RegOperandType>
617void
618RegAddrOperand<RegOperandType>::init(unsigned opOffset, const BrigObject *obj)
619{
620    using namespace Brig;
621
622    const BrigOperand *baseOp = obj->getOperand(opOffset);
623
624    switch (baseOp->kind) {
625      case BRIG_KIND_OPERAND_ADDRESS:
626        {
627            const BrigOperandAddress *op = (BrigOperandAddress*)baseOp;
628            storageElement = nullptr;
629
630            reg.init(op->reg, obj);
631
632            if (reg.regFileChar == 's') {
633                // if the address expression is 32b, then the hi
634                // bits of the offset must be set to 0 in the BRIG
635                assert(!op->offset.hi);
636                /**
637                 * the offset field of an HSAIL instruction may be negative
638                 * so here we cast the raw bits we get from the BRIG file to
639                 * a signed type to avoid address calculation errors
640                 */
641                offset = (int32_t)(op->offset.lo);
642                reg.regOperandSize = sizeof(uint32_t);
643                registerType = Enums::RT_VECTOR;
644            }
645            else if (reg.regFileChar == 'd') {
646                offset = (int64_t)(((uint64_t)(op->offset.hi) << 32)
647                    | (uint64_t)(op->offset.lo));
648                reg.regOperandSize = sizeof(uint64_t);
649                registerType = Enums::RT_VECTOR;
650            }
651        }
652        break;
653
654      default:
655        fatal("RegAddrOperand: bad operand kind %d\n", baseOp->kind);
656        break;
657    }
658}
659
660template<typename RegOperandType>
661uint64_t
662RegAddrOperand<RegOperandType>::calcUniform()
663{
664    fatal("can't do calcUniform() on register-based address\n");
665
666    return 0;
667}
668
669template<typename RegOperandType>
670void
671RegAddrOperand<RegOperandType>::calcVector(Wavefront *w,
672                                           std::vector<Addr> &addrVec)
673{
674    Addr address = calcUniformBase();
675
676    for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) {
677        if (w->execMask(lane)) {
678            if (reg.regFileChar == 's') {
679                addrVec[lane] = address + reg.template get<uint32_t>(w, lane);
680            } else {
681                addrVec[lane] = address + reg.template get<Addr>(w, lane);
682            }
683        }
684    }
685}
686
687template<typename RegOperandType>
688uint64_t
689RegAddrOperand<RegOperandType>::calcLane(Wavefront *w, int lane)
690{
691    Addr address = calcUniformBase();
692
693    return address + reg.template get<Addr>(w, lane);
694}
695
696template<typename RegOperandType>
697std::string
698RegAddrOperand<RegOperandType>::disassemble()
699{
700    return AddrOperandBase::disassemble(reg.disassemble());
701}
702
703typedef RegAddrOperand<SRegOperand> SRegAddrOperand;
704typedef RegAddrOperand<DRegOperand> DRegAddrOperand;
705
706class NoRegAddrOperand : public AddrOperandBase
707{
708  public:
709    void init(unsigned opOffset, const BrigObject *obj);
710    uint64_t calcUniform();
711    void calcVector(Wavefront *w, std::vector<Addr> &addrVec);
712    uint64_t calcLane(Wavefront *w, int lane=0);
713    std::string disassemble();
714};
715
716inline uint64_t
717NoRegAddrOperand::calcUniform()
718{
719    return AddrOperandBase::calcUniformBase();
720}
721
722inline uint64_t
723NoRegAddrOperand::calcLane(Wavefront *w, int lane)
724{
725    return calcUniform();
726}
727
728inline void
729NoRegAddrOperand::calcVector(Wavefront *w, std::vector<Addr> &addrVec)
730{
731    uint64_t address = calcUniformBase();
732
733    for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane)
734        addrVec[lane] = address;
735}
736
737class LabelOperand : public BaseOperand
738{
739  public:
740    Label *label;
741
742    void init(unsigned opOffset, const BrigObject *obj);
743    std::string disassemble();
744
745    // special get method for compatibility with SRegOperand
746    uint32_t getTarget(Wavefront *w, int lane);
747
748};
749
750class ListOperand : public BaseOperand
751{
752  public:
753    int elementCount;
754    std::vector<StorageElement*> callArgs;
755
756    int
757    getSrcOperand(int idx)
758    {
759        DPRINTF(GPUReg, "getSrcOperand, idx: %d, sz_args: %d\n", idx,
760                callArgs.size());
761
762        return callArgs.at(idx)->offset;
763    }
764
765    void init(unsigned opOffset, const BrigObject *obj);
766
767    std::string disassemble();
768
769    template<typename OperandType>
770    OperandType
771    get(Wavefront *w, int lane, int arg_idx)
772    {
773        return w->readCallArgMem<OperandType>(lane, getSrcOperand(arg_idx));
774    }
775
776    template<typename OperandType>
777    void
778    set(Wavefront *w, int lane, OperandType val)
779    {
780        w->writeCallArgMem<OperandType>(lane, getSrcOperand(0), val);
781        DPRINTF(GPUReg, "CU%d, WF[%d][%d], lane %d: arg[%d] <- %d\n",
782                w->computeUnit->cu_id, w->simdId, w->wfSlotId, lane,
783                getSrcOperand(0), val);
784    }
785};
786
787class FunctionRefOperand : public BaseOperand
788{
789  public:
790    const char *func_name;
791
792    void init(unsigned opOffset, const BrigObject *obj);
793    std::string disassemble();
794};
795
796#endif // __ARCH_HSAIL_OPERAND_HH__
797