/* * Copyright © 2012 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: Benjamin Segovia */ /** * \file instruction.cpp * \author Benjamin Segovia */ #include "ir/instruction.hpp" #include "ir/function.hpp" namespace gbe { namespace ir { /////////////////////////////////////////////////////////////////////////// // Implements the concrete implementations of the instruction classes. We // cast an instruction to an internal class to run the given member function /////////////////////////////////////////////////////////////////////////// namespace internal { #define ALIGNED_INSTRUCTION ALIGNED(ALIGNOF(Instruction)) /*! Policy shared by all the internal instructions */ struct BasePolicy { /*! Create an instruction from its internal representation */ Instruction convert(void) const { return Instruction(reinterpret_cast(&this->opcode)); } /*! Output the opcode in the given stream */ INLINE void outOpcode(std::ostream &out) const { switch (opcode) { #define DECL_INSN(OPCODE, CLASS) case OP_##OPCODE: out << #OPCODE; break; #include "instruction.hxx" #undef DECL_INSN case OP_INVALID: NOT_SUPPORTED; break; }; } /*! Instruction opcode */ Opcode opcode; }; /*! For regular n source instructions */ template struct NSrcPolicy { INLINE uint32_t getSrcNum(void) const { return srcNum; } INLINE Register getSrc(const Function &fn, uint32_t ID) const { GBE_ASSERTM((int) ID < (int) srcNum, "Out-of-bound source"); return static_cast(this)->src[ID]; } INLINE void setSrc(Function &fn, uint32_t ID, Register reg) { GBE_ASSERTM((int) ID < (int) srcNum, "Out-of-bound source"); static_cast(this)->src[ID] = reg; } }; /*! For regular n destinations instructions */ template struct NDstPolicy { INLINE uint32_t getDstNum(void) const { return dstNum; } INLINE Register getDst(const Function &fn, uint32_t ID) const { GBE_ASSERTM((int) ID < (int) dstNum, "Out-of-bound destination"); return static_cast(this)->dst[ID]; } INLINE void setDst(Function &fn, uint32_t ID, Register reg) { GBE_ASSERTM((int) ID < (int) dstNum, "Out-of-bound destination"); static_cast(this)->dst[ID] = reg; } }; /*! For instructions that use a tuple for source */ template struct TupleSrcPolicy { INLINE uint32_t getSrcNum(void) const { return static_cast(this)->srcNum; } INLINE Register getSrc(const Function &fn, uint32_t ID) const { GBE_ASSERTM(ID < static_cast(this)->srcNum, "Out-of-bound source register"); return fn.getRegister(static_cast(this)->src, ID); } INLINE void setSrc(Function &fn, uint32_t ID, Register reg) { GBE_ASSERTM(ID < static_cast(this)->srcNum, "Out-of-bound source register"); return fn.setRegister(static_cast(this)->src, ID, reg); } }; /*! For instructions that use a tuple for destination */ template struct TupleDstPolicy { INLINE uint32_t getDstNum(void) const { return static_cast(this)->dstNum; } INLINE Register getDst(const Function &fn, uint32_t ID) const { GBE_ASSERTM(ID < static_cast(this)->dstNum, "Out-of-bound source register"); return fn.getRegister(static_cast(this)->dst, ID); } INLINE void setDst(Function &fn, uint32_t ID, Register reg) { GBE_ASSERTM(ID < static_cast(this)->dstNum, "Out-of-bound source register"); return fn.setRegister(static_cast(this)->dst, ID, reg); } }; /*! All unary and binary arithmetic instructions */ template // 1 or 2 class ALIGNED_INSTRUCTION NaryInstruction : public BasePolicy, public NSrcPolicy, srcNum>, public NDstPolicy, 1> { public: INLINE Type getType(void) const { return this->type; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; INLINE void out(std::ostream &out, const Function &fn) const; Type type; //!< Type of the instruction Register dst[1]; //!< Index of the register in the register file Register src[srcNum]; //!< Indices of the sources }; /*! All 0-source arithmetic instructions */ class ALIGNED_INSTRUCTION NullaryInstruction : public NaryInstruction<0> { public: NullaryInstruction(Opcode opcode, Type type, Register dst) { this->opcode = opcode; this->type = type; this->dst[0] = dst; } }; /*! All 1-source arithmetic instructions */ class ALIGNED_INSTRUCTION UnaryInstruction : public NaryInstruction<1> { public: UnaryInstruction(Opcode opcode, Type type, Register dst, Register src) { this->opcode = opcode; this->type = type; this->dst[0] = dst; this->src[0] = src; } }; /*! All 2-source arithmetic instructions */ class ALIGNED_INSTRUCTION BinaryInstruction : public NaryInstruction<2> { public: BinaryInstruction(Opcode opcode, Type type, Register dst, Register src0, Register src1) { this->opcode = opcode; this->type = type; this->dst[0] = dst; this->src[0] = src0; this->src[1] = src1; } INLINE bool commutes(void) const { switch (opcode) { case OP_ADD: case OP_ADDSAT: case OP_XOR: case OP_OR: case OP_AND: case OP_MUL: return true; default: return false; } } }; class ALIGNED_INSTRUCTION TernaryInstruction : public BasePolicy, public NDstPolicy, public TupleSrcPolicy { public: TernaryInstruction(Opcode opcode, Type type, Register dst, Tuple src) { this->opcode = opcode; this->type = type; this->dst[0] = dst; this->src = src; } Type getType(void) const { return type; } bool wellFormed(const Function &fn, std::string &whyNot) const; INLINE void out(std::ostream &out, const Function &fn) const; Type type; Register dst[1]; Tuple src; static const uint32_t srcNum = 3; }; /*! Three sources mean we need a tuple to encode it */ class ALIGNED_INSTRUCTION SelectInstruction : public BasePolicy, public NDstPolicy, public TupleSrcPolicy { public: SelectInstruction(Type type, Register dst, Tuple src) { this->opcode = OP_SEL; this->type = type; this->dst[0] = dst; this->src = src; } INLINE Type getType(void) const { return this->type; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; INLINE void out(std::ostream &out, const Function &fn) const; Type type; //!< Type of the instruction Register dst[1]; //!< Dst is the register index Tuple src; //!< 3 sources do not fit in 8 bytes -> use a tuple static const uint32_t srcNum = 3; }; /*! Comparison instructions take two sources of the same type and return a * boolean value. Since it is pretty similar to binary instruction, we * steal all the methods from it, except wellFormed (dst register is always * a boolean value) */ class ALIGNED_INSTRUCTION CompareInstruction : public NaryInstruction<2> { public: CompareInstruction(Opcode opcode, Type type, Register dst, Register src0, Register src1) { this->opcode = opcode; this->type = type; this->dst[0] = dst; this->src[0] = src0; this->src[1] = src1; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; }; class ALIGNED_INSTRUCTION BitCastInstruction : public BasePolicy, public TupleSrcPolicy, public TupleDstPolicy { public: BitCastInstruction(Type dstType, Type srcType, Tuple dst, Tuple src, uint8_t dstNum, uint8_t srcNum) { this->opcode = OP_BITCAST; this->dst = dst; this->src = src; this->dstFamily = getFamily(dstType); this->srcFamily = getFamily(srcType); GBE_ASSERT(srcNum <= Instruction::MAX_SRC_NUM && dstNum <= Instruction::MAX_DST_NUM); this->dstNum = dstNum; this->srcNum = srcNum; } INLINE Type getSrcType(void) const { return getType((RegisterFamily)srcFamily); } INLINE Type getDstType(void) const { return getType((RegisterFamily)dstFamily); } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; INLINE void out(std::ostream &out, const Function &fn) const; uint8_t dstFamily:4; //!< family to cast to uint8_t srcFamily:4; //!< family to cast from Tuple dst; Tuple src; uint8_t dstNum; //!, public NSrcPolicy { public: ConvertInstruction(Opcode opcode, Type dstType, Type srcType, Register dst, Register src) { this->opcode = opcode; this->dst[0] = dst; this->src[0] = src; this->dstType = dstType; this->srcType = srcType; } INLINE Type getSrcType(void) const { return this->srcType; } INLINE Type getDstType(void) const { return this->dstType; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; INLINE void out(std::ostream &out, const Function &fn) const; Register dst[1]; Register src[1]; Type dstType; //!< Type to convert to Type srcType; //!< Type to convert from }; class ALIGNED_INSTRUCTION MemInstruction : public BasePolicy { public: MemInstruction(AddressMode _AM, AddressSpace _AS, bool _dwAligned, Type _type, Register _offset) : AM(_AM), AS(_AS), dwAligned(_dwAligned), type(_type), SurfaceIndex(0), offset(_offset) { } AddressMode getAddressMode() const { return AM; } AddressSpace getAddressSpace() const { return AS; } /*! MemInstruction may have one possible btiReg */ Register getBtiReg() const { assert(AM == AM_DynamicBti); return BtiReg; } unsigned getSurfaceIndex() const { assert(AM != AM_DynamicBti); return SurfaceIndex; } Register getAddressRegister()const { return offset; } unsigned getAddressIndex() const { return 0; } Type getValueType() const { return type; } INLINE bool isAligned(void) const { return !!dwAligned; } void setSurfaceIndex (unsigned id) { SurfaceIndex = id; } void setBtiReg(Register reg) { BtiReg = reg; } protected: /*! including address reg + optional bti reg */ int getBaseSrcNum() const { return AM == AM_DynamicBti ? 2 : 1; } bool hasExtraBtiReg() const { return AM == AM_DynamicBti; } AddressMode AM; AddressSpace AS; uint8_t dwAligned : 1; Type type; union { Register BtiReg; unsigned SurfaceIndex; }; Register offset; }; class ALIGNED_INSTRUCTION AtomicInstruction : public MemInstruction, public NDstPolicy { public: AtomicInstruction(AtomicOps atomicOp, Type type, Register dst, AddressSpace addrSpace, Register address, Tuple payload, AddressMode AM) : MemInstruction(AM, addrSpace, true, type, address) { this->opcode = OP_ATOMIC; this->atomicOp = atomicOp; this->dst[0] = dst; this->payload = payload; int payloadNum = 1; if((atomicOp == ATOMIC_OP_INC) || (atomicOp == ATOMIC_OP_DEC)) payloadNum = 0; if(atomicOp == ATOMIC_OP_CMPXCHG) payloadNum = 2; srcNum = payloadNum + getBaseSrcNum(); } INLINE Register getSrc(const Function &fn, uint32_t ID) const { GBE_ASSERTM((int)ID < (int)srcNum, "Out-of-bound source register for atomic"); if (ID == 0) { return offset; } else if (hasExtraBtiReg() && (int)ID == (int)srcNum-1) { return getBtiReg(); } else { return fn.getRegister(payload, ID - 1); } } INLINE void setSrc(Function &fn, uint32_t ID, Register reg) { GBE_ASSERTM((int)ID < (int)srcNum, "Out-of-bound source register for atomic"); if (ID == 0) { offset = reg; } else if (hasExtraBtiReg() && (int)ID == (int)srcNum - 1) { setBtiReg(reg); } else { fn.setRegister(payload, ID - 1, reg); } } INLINE uint32_t getSrcNum(void) const { return srcNum; } INLINE AtomicOps getAtomicOpcode(void) const { return this->atomicOp; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; INLINE void out(std::ostream &out, const Function &fn) const; Register dst[1]; Tuple payload; uint8_t srcNum:3; //! { public: INLINE BranchInstruction(Opcode op, LabelIndex labelIndex, Register predicate, bool inv_pred=false) { GBE_ASSERT(op == OP_BRA || op == OP_IF || op == OP_WHILE); this->opcode = op; this->predicate = predicate; this->labelIndex = labelIndex; this->hasPredicate = true; this->hasLabel = true; this->inversePredicate = inv_pred; } INLINE BranchInstruction(Opcode op, LabelIndex labelIndex) { GBE_ASSERT(op == OP_BRA || op == OP_ELSE || op == OP_ENDIF); this->opcode = op; this->labelIndex = labelIndex; this->hasPredicate = false; this->hasLabel = true; } INLINE BranchInstruction(Opcode op) { GBE_ASSERT(op == OP_RET); this->opcode = op; this->hasPredicate = false; this->hasLabel = false; } INLINE LabelIndex getLabelIndex(void) const { GBE_ASSERTM(hasLabel, "No target label for this branch instruction"); return labelIndex; } INLINE uint32_t getSrcNum(void) const { return hasPredicate ? 1 : 0; } INLINE Register getSrc(const Function &fn, uint32_t ID) const { GBE_ASSERTM(hasPredicate, "No source for unpredicated branches"); GBE_ASSERTM(ID == 0, "Only one source for the branch instruction"); return predicate; } INLINE void setSrc(Function &fn, uint32_t ID, Register reg) { GBE_ASSERTM(hasPredicate, "No source for unpredicated branches"); GBE_ASSERTM(ID == 0, "Only one source for the branch instruction"); predicate = reg; } INLINE bool isPredicated(void) const { return hasPredicate; } INLINE bool getInversePredicated(void) const { return inversePredicate; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; Register predicate; //!< Predication means conditional branch LabelIndex labelIndex; //!< Index of the label the branch targets bool hasPredicate:1; //!< Is it predicated? bool inversePredicate:1; //!< Is it inverse predicated? bool hasLabel:1; //!< Is there any target label? Register dst[0]; //!< No destination }; class ALIGNED_INSTRUCTION LoadInstruction : public MemInstruction { public: LoadInstruction(Type type, Tuple dstValues, Register offset, AddressSpace AS, uint32_t _valueNum, bool dwAligned, AddressMode AM) : MemInstruction(AM, AS, dwAligned, type, offset), valueNum(_valueNum), values(dstValues) { this->opcode = OP_LOAD; } INLINE unsigned getSrcNum() const { return getBaseSrcNum(); } INLINE Register getSrc(const Function &fn, unsigned id) const { if (id == 0) return offset; if (hasExtraBtiReg() && id == 1) return BtiReg; assert(0 && "LoadInstruction::getSrc() out-of-range"); return ir::Register(0); } INLINE void setSrc(Function &fn, unsigned id, Register reg) { assert(id < getSrcNum()); if (id == 0) { offset = reg; return; } if (id == 1) { setBtiReg(reg); return; } } INLINE unsigned getDstNum() const { return valueNum; } INLINE Register getDst(const Function &fn, unsigned id) const { assert(id < valueNum); return fn.getRegister(values, id); } INLINE void setDst(Function &fn, unsigned id, Register reg) { assert(id < getDstNum()); fn.setRegister(values, id, reg); } INLINE uint32_t getValueNum(void) const { return valueNum; } INLINE Register getValue(const Function &fn, unsigned id) const { assert(id < valueNum); return fn.getRegister(values, id); } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; uint8_t valueNum; Tuple values; }; class ALIGNED_INSTRUCTION StoreInstruction : public MemInstruction, public NDstPolicy { public: StoreInstruction(Type type, Tuple values, Register offset, AddressSpace addrSpace, uint32_t valueNum, bool dwAligned, AddressMode AM) : MemInstruction(AM, addrSpace, dwAligned, type, offset) { this->opcode = OP_STORE; this->values = values; this->valueNum = valueNum; } INLINE unsigned getValueNum() const { return valueNum; } INLINE Register getValue(const Function &fn, unsigned id) const { return fn.getRegister(values, id); } INLINE unsigned getSrcNum() const { return getBaseSrcNum() + valueNum; } INLINE Register getSrc(const Function &fn, unsigned id) const { if (id == 0) return offset; if (id <= valueNum) return fn.getRegister(values, id-1); if (hasExtraBtiReg() && (int)id == (int)valueNum+1) return getBtiReg(); assert(0 && "StoreInstruction::getSrc() out-of-range"); return Register(0); } INLINE void setSrc(Function &fn, unsigned id, Register reg) { if (id == 0) { offset = reg; return; } if (id > 0 && id <= valueNum) { fn.setRegister(values, id-1, reg); return; } if (hasExtraBtiReg() && (int)id == (int)valueNum + 1) { setBtiReg(reg); return; } assert(0 && "StoreInstruction::setSrc() index out-of-range"); } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; Register dst[0]; uint8_t valueNum; Tuple values; }; class ALIGNED_INSTRUCTION SampleInstruction : // TODO public BasePolicy, public TupleSrcPolicy, public TupleDstPolicy { public: SampleInstruction(uint8_t imageIdx, Tuple dstTuple, Tuple srcTuple, uint8_t srcNum, bool dstIsFloat, bool srcIsFloat, uint8_t sampler, uint8_t samplerOffset) { this->opcode = OP_SAMPLE; this->dst = dstTuple; this->src = srcTuple; this->srcNum = srcNum; this->dstIsFloat = dstIsFloat; this->srcIsFloat = srcIsFloat; this->samplerIdx = sampler; this->imageIdx = imageIdx; this->samplerOffset = samplerOffset; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << this->getDstType() << "." << this->getSrcType() << " surface id " << (int)this->getImageIndex(); out << " coord u %" << this->getSrc(fn, 0); if (srcNum >= 2) out << " coord v %" << this->getSrc(fn, 1); if (srcNum >= 3) out << " coord w %" << this->getSrc(fn, 2); out << " %" << this->getDst(fn, 0) << " %" << this->getDst(fn, 1) << " %" << this->getDst(fn, 2) << " %" << this->getDst(fn, 3) << " sampler idx " << (int)this->getSamplerIndex(); } Tuple src; Tuple dst; INLINE uint8_t getImageIndex(void) const { return this->imageIdx; } INLINE Type getSrcType(void) const { return this->srcIsFloat ? TYPE_FLOAT : TYPE_S32; } INLINE Type getDstType(void) const { return this->dstIsFloat ? TYPE_FLOAT : TYPE_U32; } INLINE uint8_t getSamplerIndex(void) const { return this->samplerIdx; } INLINE uint8_t getSamplerOffset(void) const { return this->samplerOffset; } uint8_t srcIsFloat:1; uint8_t dstIsFloat:1; uint8_t samplerIdx:4; uint8_t samplerOffset:2; uint8_t imageIdx; uint8_t srcNum; static const uint32_t dstNum = 4; }; class ALIGNED_INSTRUCTION VmeInstruction : public BasePolicy, public TupleSrcPolicy, public TupleDstPolicy { public: VmeInstruction(uint8_t imageIdx, Tuple dstTuple, Tuple srcTuple, uint32_t dstNum, uint32_t srcNum, int msg_type, int vme_search_path_lut, int lut_sub) { this->opcode = OP_VME; this->dst = dstTuple; this->src = srcTuple; this->dstNum = dstNum; this->srcNum = srcNum; this->imageIdx = imageIdx; this->msg_type = msg_type; this->vme_search_path_lut = vme_search_path_lut; this->lut_sub = lut_sub; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << " src_surface id " << (int)this->getImageIndex() << " ref_surface id " << (int)this->getImageIndex() + 1; for(uint32_t i = 0; i < dstNum; i++){ out<< " %" << this->getDst(fn, i); } for(uint32_t i = 0; i < srcNum; i++){ out<< " %" << this->getSrc(fn, i); } out << " msg_type " << (int)this->getMsgType() << " vme_search_path_lut " << (int)this->vme_search_path_lut << " lut_sub " << (int)this->lut_sub; } Tuple src; Tuple dst; INLINE uint8_t getImageIndex(void) const { return this->imageIdx; } INLINE uint8_t getMsgType(void) const { return this->msg_type; } INLINE Type getSrcType(void) const { return TYPE_U32; } INLINE Type getDstType(void) const { return TYPE_U32; } uint8_t imageIdx; uint8_t msg_type; uint8_t vme_search_path_lut; uint8_t lut_sub; uint32_t srcNum; uint32_t dstNum; }; class ALIGNED_INSTRUCTION TypedWriteInstruction : // TODO public BasePolicy, public TupleSrcPolicy, public NDstPolicy { public: INLINE TypedWriteInstruction(uint8_t imageIdx, Tuple srcTuple, uint8_t srcNum, Type srcType, Type coordType) { this->opcode = OP_TYPED_WRITE; this->src = srcTuple; this->srcNum = srcNum; this->coordType = coordType; this->srcType = srcType; this->imageIdx = imageIdx; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const { this->outOpcode(out); uint32_t srcID = 0; out << "." << this->getSrcType() << " surface id " << (int)this->getImageIndex() << " coord u %" << this->getSrc(fn, srcID++); if (srcNum >= 6) out << " coord v %" << this->getSrc(fn, srcID++); if (srcNum >= 7) out << " coord w %" << this->getSrc(fn, srcID++); out << " %" << this->getSrc(fn, srcID++); out << " %" << this->getSrc(fn, srcID++); out << " %" << this->getSrc(fn, srcID++); out << " %" << this->getSrc(fn, srcID++); } Tuple src; uint8_t srcType; uint8_t coordType; uint8_t imageIdx; // bti, u, [v], [w], 4 data elements uint8_t srcNum; INLINE uint8_t getImageIndex(void) const { return this->imageIdx; } INLINE Type getSrcType(void) const { return (Type)this->srcType; } INLINE Type getCoordType(void) const { return (Type)this->coordType; } Register dst[0]; //!< No dest register }; class ALIGNED_INSTRUCTION GetImageInfoInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: GetImageInfoInstruction( int type, Register dst, uint8_t imageIdx, Register infoReg) { this->opcode = OP_GET_IMAGE_INFO; this->infoType = type; this->dst[0] = dst; this->src[0] = infoReg; this->imageIdx = imageIdx; } INLINE uint32_t getInfoType(void) const { return infoType; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << this->getInfoType() << " %" << this->getDst(fn, 0) << " surface id " << (int)this->getImageIndex() << " info reg %" << this->getSrc(fn, 0); } INLINE uint8_t getImageIndex(void) const { return imageIdx; } uint8_t infoType; //!< Type of the requested information. uint8_t imageIdx; //!< surface index. Register src[1]; //!< surface info register. Register dst[1]; //!< dest register to put the information. static const uint32_t dstNum = 1; }; class ALIGNED_INSTRUCTION CalcTimestampInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: CalcTimestampInstruction(uint32_t pointNum, uint32_t timestampType) { this->opcode = OP_CALC_TIMESTAMP; this->timestampType = static_cast(timestampType); this->pointNum = static_cast(pointNum); } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "TimeStamp pointer " << static_cast(pointNum) << " (Type " << static_cast(timestampType) << ")"; } uint32_t getPointNum(void) const { return this->pointNum; } uint32_t getTimestamptType(void) const { return this->timestampType; } uint8_t timestampType; //!< Type of the time stamp, 16bits or 32bits, eg. uint8_t pointNum; //!< The insert point number. Register dst[0], src[0]; }; class ALIGNED_INSTRUCTION StoreProfilingInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: StoreProfilingInstruction(uint32_t bti, uint32_t profilingType) { this->opcode = OP_STORE_PROFILING; this->profilingType = static_cast(profilingType); this->bti = static_cast(bti); } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << " BTI " << static_cast(this->bti) << " (Type " << static_cast(this->profilingType) << ")"; } uint32_t getProfilingType(void) const { return this->profilingType; } uint32_t getBTI(void) const { return this->bti; } uint8_t profilingType; //!< Type format of profiling, 16bits or 32bits, eg. uint8_t bti; Register src[0]; Register dst[0]; }; class ALIGNED_INSTRUCTION LoadImmInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: INLINE LoadImmInstruction(Type type, Register dst, ImmediateIndex index) { this->dst[0] = dst; this->opcode = OP_LOADI; this->immediateIndex = index; this->type = type; } INLINE Immediate getImmediate(const Function &fn) const { return fn.getImmediate(immediateIndex); } INLINE Type getType(void) const { return this->type; } bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; Register dst[1]; //!< RegisterData to store into Register src[0]; //!< No source register ImmediateIndex immediateIndex; //!< Index in the vector of immediates Type type; //!< Type of the immediate }; class ALIGNED_INSTRUCTION SyncInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: INLINE SyncInstruction(uint32_t parameters) { this->opcode = OP_SYNC; this->parameters = parameters; } INLINE uint32_t getParameters(void) const { return this->parameters; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; uint32_t parameters; Register dst[0], src[0]; }; class ALIGNED_INSTRUCTION ReadARFInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: INLINE ReadARFInstruction(Type type, Register dst, ARFRegister arf) { this->type = type; this->dst[0] = dst; this->opcode = OP_READ_ARF; this->arf = arf; } INLINE ir::ARFRegister getARFRegister(void) const { return this->arf; } INLINE Type getType(void) const { return this->type; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; Type type; ARFRegister arf; Register dst[1]; Register src[0]; }; class ALIGNED_INSTRUCTION SimdShuffleInstruction : public NaryInstruction<2> { public: SimdShuffleInstruction(Type type, Register dst, Register src0, Register src1) { this->opcode = OP_SIMD_SHUFFLE; this->type = type; this->dst[0] = dst; this->src[0] = src0; this->src[1] = src1; } INLINE bool wellFormed(const Function &fn, std::string &why) const; }; class ALIGNED_INSTRUCTION RegionInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: INLINE RegionInstruction(Register dst, Register src, uint32_t offset) { this->offset = offset; this->dst[0] = dst; this->src[0] = src; this->opcode = OP_REGION; } INLINE uint32_t getOffset(void) const { return this->offset; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; uint32_t offset; Register dst[1]; Register src[1]; }; class ALIGNED_INSTRUCTION IndirectMovInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: INLINE IndirectMovInstruction(Type type, Register dst, Register src0, Register src1, uint32_t offset) { this->type = type; this->offset = offset; this->dst[0] = dst; this->src[0] = src0; this->src[1] = src1; this->opcode = OP_INDIRECT_MOV; } INLINE Type getType(void) const { return this->type; } INLINE uint32_t getOffset(void) const { return this->offset; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; Type type; uint32_t offset; Register dst[1]; Register src[2]; }; class ALIGNED_INSTRUCTION LabelInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: INLINE LabelInstruction(LabelIndex labelIndex) { this->opcode = OP_LABEL; this->labelIndex = labelIndex; } INLINE LabelIndex getLabelIndex(void) const { return labelIndex; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; LabelIndex labelIndex; //!< Index of the label Register dst[0], src[0]; }; /*! Wait instructions */ class ALIGNED_INSTRUCTION WaitInstruction : public BasePolicy, public NSrcPolicy, public NDstPolicy { public: INLINE WaitInstruction() { this->opcode = OP_WAIT; } INLINE bool wellFormed(const Function &fn, std::string &why) const; INLINE void out(std::ostream &out, const Function &fn) const; Register dst[0], src[0]; }; #undef ALIGNED_INSTRUCTION ///////////////////////////////////////////////////////////////////////// // Implements all the wellFormed methods ///////////////////////////////////////////////////////////////////////// /*! All Nary instruction registers must be of the same family and properly * defined (i.e. not out-of-bound) */ static INLINE bool checkRegisterData(RegisterFamily family, const Register &ID, const Function &fn, std::string &whyNot) { if (UNLIKELY(ID.value() >= fn.regNum())) { whyNot = "Out-of-bound destination register index"; return false; } const RegisterData reg = fn.getRegisterData(ID); if (UNLIKELY(reg.family != family)) { whyNot = "Destination family does not match instruction type"; return false; } return true; } /*! Special registers are *not* writeable */ static INLINE bool checkSpecialRegForWrite(const Register ®, const Function &fn, std::string &whyNot) { if (fn.isSpecialReg(reg) == true && reg != ir::ocl::stackptr) { whyNot = "Non stack pointer special registers are not writeable"; return false; } return true; } /*! We check that the given type belongs to the provided type family */ static INLINE bool checkTypeFamily(const Type &type, const Type *family, uint32_t typeNum, std::string &whyNot) { uint32_t typeID = 0; for (; typeID < typeNum; ++typeID) if (family[typeID] == type) break; if (typeID == typeNum) { whyNot = "Type is not supported by the instruction"; return false; } return true; } #define CHECK_TYPE(TYPE, FAMILY) \ do { \ if (UNLIKELY(checkTypeFamily(TYPE, FAMILY, FAMILY##Num, whyNot)) == false) \ return false; \ } while (0) static const Type madType[] = {TYPE_FLOAT}; static const uint32_t madTypeNum = ARRAY_ELEM_NUM(madType); // TODO add support for 64 bits values static const Type allButBool[] = {TYPE_S8, TYPE_U8, TYPE_S16, TYPE_U16, TYPE_S32, TYPE_U32, TYPE_S64, TYPE_U64, TYPE_HALF, TYPE_FLOAT, TYPE_DOUBLE}; static const uint32_t allButBoolNum = ARRAY_ELEM_NUM(allButBool); // TODO add support for 64 bits values static const Type logicalType[] = {TYPE_S8, TYPE_U8, TYPE_S16, TYPE_U16, TYPE_S32, TYPE_U32, TYPE_S64, TYPE_U64, TYPE_BOOL}; static const uint32_t logicalTypeNum = ARRAY_ELEM_NUM(logicalType); // Unary and binary instructions share the same rules template INLINE bool NaryInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const RegisterFamily family = getFamily(this->type); if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (opcode != OP_CBIT && UNLIKELY(checkRegisterData(family, dst[0], fn, whyNot) == false)) return false; for (uint32_t srcID = 0; srcID < srcNum; ++srcID) if (UNLIKELY(checkRegisterData(family, src[srcID], fn, whyNot) == false)) return false; // We actually support logical operations on boolean values for AND, OR, // and XOR switch (this->opcode) { case OP_OR: case OP_XOR: case OP_AND: CHECK_TYPE(this->type, logicalType); break; default: CHECK_TYPE(this->type, allButBool); break; case OP_MOV: break; case OP_POW: case OP_COS: case OP_SIN: case OP_RCP: case OP_ABS: case OP_RSQ: case OP_SQR: case OP_RNDD: case OP_RNDE: case OP_RNDU: case OP_RNDZ: const Type fp = TYPE_FLOAT; if (UNLIKELY(checkTypeFamily(TYPE_FLOAT, &fp, 1, whyNot)) == false) return false; break; } return true; } // First source must a boolean. Other must match the destination type INLINE bool SelectInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const RegisterFamily family = getFamily(this->type); if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(family, dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(src + 3u > fn.tupleNum())) { whyNot = "Out-of-bound index for ternary instruction"; return false; } const Register regID = fn.getRegister(src, 0); if (UNLIKELY(checkRegisterData(FAMILY_BOOL, regID, fn, whyNot) == false)) return false; for (uint32_t srcID = 1; srcID < 3; ++srcID) { const Register regID = fn.getRegister(src, srcID); if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false)) return false; } return true; } // Pretty similar to binary instruction. Only the destination is of type // boolean INLINE bool CompareInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(FAMILY_BOOL, dst[0], fn, whyNot) == false)) return false; const RegisterFamily family = getFamily(this->type); for (uint32_t srcID = 0; srcID < 2; ++srcID) if (UNLIKELY(checkRegisterData(family, src[srcID], fn, whyNot) == false)) return false; return true; } // The bit sizes of src and the dst must be identical, and don't support bool now, bool need double check. INLINE bool BitCastInstruction::wellFormed(const Function &fn, std::string &whyNot) const { for (uint32_t dstID = 0; dstID < dstNum; ++dstID) { if (UNLIKELY(checkSpecialRegForWrite(getDst(fn, dstID), fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData((RegisterFamily)dstFamily, getDst(fn, dstID), fn, whyNot) == false)) return false; } for (uint32_t srcID = 0; srcID < srcNum; ++srcID) { if (UNLIKELY(checkRegisterData((RegisterFamily)srcFamily, getSrc(fn, srcID), fn, whyNot) == false)) return false; } CHECK_TYPE(getType((RegisterFamily)dstFamily), allButBool); CHECK_TYPE(getType((RegisterFamily)srcFamily), allButBool); uint32_t dstBytes = 0, srcBtyes = 0; dstBytes = dstNum * getFamilySize((RegisterFamily)dstFamily); srcBtyes = srcNum * getFamilySize((RegisterFamily)srcFamily); if(dstBytes != srcBtyes){ whyNot = " The bit sizes of src and the dst is not identical."; return false; } return true; } // We can convert anything to anything, but types and families must match INLINE bool ConvertInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const RegisterFamily dstFamily = getFamily(dstType); const RegisterFamily srcFamily = getFamily(srcType); if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(dstFamily, dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(srcFamily, src[0], fn, whyNot) == false)) return false; CHECK_TYPE(this->dstType, allButBool); CHECK_TYPE(this->srcType, allButBool); return true; } // We can convert anything to anything, but types and families must match INLINE bool AtomicInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(FAMILY_DWORD, dst[0], fn, whyNot) == false)) return false; for (uint32_t srcID = 0; srcID < srcNum-1u; ++srcID) if (UNLIKELY(checkRegisterData(FAMILY_DWORD, getSrc(fn, srcID+1u), fn, whyNot) == false)) return false; return true; } INLINE bool TernaryInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const RegisterFamily family = getFamily(this->type); if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(family, dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(src + 3u > fn.tupleNum())) { whyNot = "Out-of-bound index for ternary instruction"; return false; } for (uint32_t srcID = 0; srcID < 3; ++srcID) { const Register regID = fn.getRegister(src, srcID); if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false)) return false; } return true; } /*! Loads and stores follow the same restrictions */ template INLINE bool wellFormedLoadStore(const T &insn, const Function &fn, std::string &whyNot) { if (UNLIKELY(insn.getAddressRegister() >= fn.regNum())) { whyNot = "Out-of-bound offset register index"; return false; } if (UNLIKELY(insn.values + insn.valueNum > fn.tupleNum())) { whyNot = "Out-of-bound tuple index"; return false; } // Check all registers const RegisterFamily family = getFamily(insn.getValueType()); for (uint32_t valueID = 0; valueID < insn.getValueNum(); ++valueID) { const Register regID = insn.getValue(fn, valueID);; if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false)) return false; } return true; } INLINE bool LoadInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const uint32_t dstNum = this->getDstNum(); for (uint32_t dstID = 0; dstID < dstNum; ++dstID) { const Register reg = this->getDst(fn, dstID); const bool isOK = checkSpecialRegForWrite(reg, fn, whyNot); if (UNLIKELY(isOK == false)) return false; } if (UNLIKELY(dstNum > Instruction::MAX_DST_NUM)) { whyNot = "Too many destinations for load instruction"; return false; } return wellFormedLoadStore(*this, fn, whyNot); } INLINE bool StoreInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const uint32_t srcNum = this->getSrcNum(); if (UNLIKELY(srcNum > Instruction::MAX_SRC_NUM)) { whyNot = "Too many source for store instruction"; return false; } return wellFormedLoadStore(*this, fn, whyNot); } // TODO INLINE bool SampleInstruction::wellFormed(const Function &fn, std::string &why) const { return true; } INLINE bool VmeInstruction::wellFormed(const Function &fn, std::string &why) const { return true; } INLINE bool TypedWriteInstruction::wellFormed(const Function &fn, std::string &why) const { return true; } INLINE bool GetImageInfoInstruction::wellFormed(const Function &fn, std::string &why) const { return true; } INLINE bool WaitInstruction::wellFormed(const Function &fn, std::string &why) const { return true; } // Ensure that types and register family match INLINE bool LoadImmInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY(immediateIndex >= fn.immediateNum())) { whyNot = "Out-of-bound immediate value index"; return false; } const ir::Type immType = fn.getImmediate(immediateIndex).getType(); if (UNLIKELY(type != immType)) { whyNot = "Inconsistent type for the immediate value to load"; return false; } const RegisterFamily family = getFamily(type); if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(family, dst[0], fn, whyNot) == false)) return false; //Support all type IMM, disable check //CHECK_TYPE(this->type, allButBool); return true; } INLINE bool SyncInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const uint32_t maxParams = SYNC_WORKGROUP_EXEC | SYNC_LOCAL_READ_FENCE | SYNC_LOCAL_WRITE_FENCE | SYNC_GLOBAL_READ_FENCE | SYNC_GLOBAL_WRITE_FENCE; if (UNLIKELY(this->parameters > maxParams)) { whyNot = "Invalid parameters for sync instruction"; return false; } else if (UNLIKELY(this->parameters == 0)) { whyNot = "Missing parameters for sync instruction"; return false; } return true; } INLINE bool ReadARFInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY( this->type != TYPE_U32 && this->type != TYPE_S32)) { whyNot = "Only support S32/U32 type"; return false; } const RegisterFamily family = getFamily(this->type); if (UNLIKELY(checkRegisterData(family, dst[0], fn, whyNot) == false)) return false; return true; } INLINE bool SimdShuffleInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY( this->type != TYPE_U32 && this->type != TYPE_S32 && this->type != TYPE_FLOAT)) { whyNot = "Only support S32/U32/FLOAT type"; return false; } if (UNLIKELY(checkRegisterData(FAMILY_DWORD, src[1], fn, whyNot) == false)) return false; return true; } INLINE bool RegionInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY(checkRegisterData(FAMILY_DWORD, src[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(FAMILY_DWORD, dst[0], fn, whyNot) == false)) return false; return true; } INLINE bool IndirectMovInstruction::wellFormed(const Function &fn, std::string &whyNot) const { const RegisterFamily family = getFamily(this->type); if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false)) return false; if (UNLIKELY(checkRegisterData(family, dst[0], fn, whyNot) == false)) return false; return true; } // Only a label index is required INLINE bool LabelInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY(labelIndex >= fn.labelNum())) { whyNot = "Out-of-bound label index"; return false; } return true; } // The label must exist and the register must of boolean family INLINE bool BranchInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (hasLabel) if (UNLIKELY(labelIndex >= fn.labelNum())) { whyNot = "Out-of-bound label index"; return false; } if (hasPredicate) if (UNLIKELY(checkRegisterData(FAMILY_BOOL, predicate, fn, whyNot) == false)) return false; return true; } INLINE bool CalcTimestampInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY(this->timestampType != 1)) { whyNot = "Wrong time stamp type"; return false; } if (UNLIKELY(this->pointNum >= 20 && this->pointNum != 0xff && this->pointNum != 0xfe)) { whyNot = "To much Insert pointer"; return false; } return true; } INLINE bool StoreProfilingInstruction::wellFormed(const Function &fn, std::string &whyNot) const { if (UNLIKELY(this->profilingType != 1)) { whyNot = "Wrong profiling format"; return false; } return true; } #undef CHECK_TYPE ///////////////////////////////////////////////////////////////////////// // Implements all the output stream methods ///////////////////////////////////////////////////////////////////////// template INLINE void NaryInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << this->getType() << " %" << this->getDst(fn, 0); for (uint32_t i = 0; i < srcNum; ++i) out << " %" << this->getSrc(fn, i); } template static void ternaryOrSelectOut(const T &insn, std::ostream &out, const Function &fn) { insn.outOpcode(out); out << "." << insn.getType() << " %" << insn.getDst(fn, 0) << " %" << insn.getSrc(fn, 0) << " %" << insn.getSrc(fn, 1) << " %" << insn.getSrc(fn, 2); } INLINE void SelectInstruction::out(std::ostream &out, const Function &fn) const { ternaryOrSelectOut(*this, out, fn); } INLINE void TernaryInstruction::out(std::ostream &out, const Function &fn) const { ternaryOrSelectOut(*this, out, fn); } INLINE void AtomicInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << AS; out << " %" << this->getDst(fn, 0); out << " {" << "%" << this->getSrc(fn, 0) << "}"; for (uint32_t i = 1; i < srcNum; ++i) out << " %" << this->getSrc(fn, i); AddressMode am = this->getAddressMode(); out << " bti:"; if ( am == AM_DynamicBti) { out << " %" << this->getBtiReg(); } else { out << this->getSurfaceIndex(); } } INLINE void BitCastInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << this->getDstType() << "." << this->getSrcType(); out << " {"; for (uint32_t i = 0; i < dstNum; ++i) out << "%" << this->getDst(fn, i) << (i != (dstNum-1u) ? " " : ""); out << "}"; out << " {"; for (uint32_t i = 0; i < srcNum; ++i) out << "%" << this->getSrc(fn, i) << (i != (srcNum-1u) ? " " : ""); out << "}"; } INLINE void ConvertInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << this->getDstType() << "." << this->getSrcType() << " %" << this->getDst(fn, 0) << " %" << this->getSrc(fn, 0); } INLINE void LoadInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << type << "." << AS << (dwAligned ? "." : ".un") << "aligned"; out << " {"; for (uint32_t i = 0; i < valueNum; ++i) out << "%" << this->getDst(fn, i) << (i != (valueNum-1u) ? " " : ""); out << "}"; out << " %" << this->getSrc(fn, 0); AddressMode am = this->getAddressMode(); out << " bti:"; if ( am == AM_DynamicBti) { out << " %" << this->getBtiReg(); } else { out << this->getSurfaceIndex(); } } INLINE void StoreInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << type << "." << AS << (dwAligned ? "." : ".un") << "aligned"; out << " %" << this->getSrc(fn, 0) << " {"; for (uint32_t i = 0; i < valueNum; ++i) out << "%" << this->getSrc(fn, i+1) << (i != (valueNum-1u) ? " " : ""); out << "}"; AddressMode am = this->getAddressMode(); out << " bti:"; if ( am == AM_DynamicBti) { out << " %" << this->getBtiReg(); } else { out << this->getSurfaceIndex(); } } INLINE void ReadARFInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << " %" << this->getDst(fn, 0) << " arf:" << arf; } INLINE void RegionInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << " %" << this->getDst(fn, 0) << " %" << this->getSrc(fn, 0) << " offset: " << this->offset; } INLINE void IndirectMovInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << type << " %" << this->getDst(fn, 0) << " %" << this->getSrc(fn, 0); out << " %" << this->getSrc(fn, 1) << " offset: " << this->offset; } INLINE void LabelInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << " $" << labelIndex; } INLINE void BranchInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); if(opcode == OP_IF && inversePredicate) out << " !"; if (hasPredicate) out << "<%" << this->getSrc(fn, 0) << ">"; if (hasLabel) out << " -> label$" << labelIndex; } INLINE void LoadImmInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); out << "." << type; out << " %" << this->getDst(fn,0) << " "; fn.outImmediate(out, immediateIndex); } static const char *syncStr[syncFieldNum] = { "workgroup", "local_read", "local_write", "global_read", "global_write" }; INLINE void SyncInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); for (uint32_t field = 0; field < syncFieldNum; ++field) if (this->parameters & (1 << field)) out << "." << syncStr[field]; } INLINE void WaitInstruction::out(std::ostream &out, const Function &fn) const { this->outOpcode(out); } } /* namespace internal */ std::ostream &operator<< (std::ostream &out, AddressSpace addrSpace) { switch (addrSpace) { case MEM_GLOBAL: return out << "global"; case MEM_LOCAL: return out << "local"; case MEM_CONSTANT: return out << "constant"; case MEM_PRIVATE: return out << "private"; case MEM_MIXED: return out << "mixed"; case MEM_INVALID: return out << "invalid"; }; return out; } /////////////////////////////////////////////////////////////////////////// // Implements the various introspection functions /////////////////////////////////////////////////////////////////////////// template struct HelperIntrospection { enum { value = 0 }; }; template struct HelperIntrospection { enum { value = 1 }; }; RegisterData Instruction::getDstData(uint32_t ID) const { const Function &fn = this->getFunction(); return fn.getRegisterData(this->getDst(ID)); } RegisterData Instruction::getSrcData(uint32_t ID) const { const Function &fn = this->getFunction(); return fn.getRegisterData(this->getSrc(ID)); } #define DECL_INSN(OPCODE, CLASS) \ case OP_##OPCODE: \ return HelperIntrospection::value == 1; #define START_INTROSPECTION(CLASS) \ static_assert(sizeof(internal::CLASS) == (sizeof(uint64_t)*4), \ "Bad instruction size"); \ static_assert(offsetof(internal::CLASS, opcode) == 0, \ "Bad opcode offset"); \ bool CLASS::isClassOf(const Instruction &insn) { \ const Opcode op = insn.getOpcode(); \ typedef CLASS RefClass; \ switch (op) { #define END_INTROSPECTION(CLASS) \ default: return false; \ }; \ } START_INTROSPECTION(NullaryInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(NullaryInstruction) START_INTROSPECTION(UnaryInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(UnaryInstruction) START_INTROSPECTION(BinaryInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(BinaryInstruction) START_INTROSPECTION(CompareInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(CompareInstruction) START_INTROSPECTION(BitCastInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(BitCastInstruction) START_INTROSPECTION(ConvertInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(ConvertInstruction) START_INTROSPECTION(AtomicInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(AtomicInstruction) START_INTROSPECTION(SelectInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(SelectInstruction) START_INTROSPECTION(TernaryInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(TernaryInstruction) START_INTROSPECTION(BranchInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(BranchInstruction) START_INTROSPECTION(SampleInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(SampleInstruction) START_INTROSPECTION(TypedWriteInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(TypedWriteInstruction) START_INTROSPECTION(GetImageInfoInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(GetImageInfoInstruction) START_INTROSPECTION(CalcTimestampInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(CalcTimestampInstruction) START_INTROSPECTION(StoreProfilingInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(StoreProfilingInstruction) START_INTROSPECTION(LoadImmInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(LoadImmInstruction) START_INTROSPECTION(LoadInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(LoadInstruction) START_INTROSPECTION(StoreInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(StoreInstruction) START_INTROSPECTION(SyncInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(SyncInstruction) START_INTROSPECTION(ReadARFInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(ReadARFInstruction) START_INTROSPECTION(RegionInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(RegionInstruction) START_INTROSPECTION(SimdShuffleInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(SimdShuffleInstruction) START_INTROSPECTION(IndirectMovInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(IndirectMovInstruction) START_INTROSPECTION(LabelInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(LabelInstruction) START_INTROSPECTION(WaitInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(WaitInstruction) START_INTROSPECTION(VmeInstruction) #include "ir/instruction.hxx" END_INTROSPECTION(VmeInstruction) #undef END_INTROSPECTION #undef START_INTROSPECTION #undef DECL_INSN /////////////////////////////////////////////////////////////////////////// // Implements the function dispatching from public to internal with some // macro horrors /////////////////////////////////////////////////////////////////////////// #define DECL_INSN(OPCODE, CLASS) \ case OP_##OPCODE: return reinterpret_cast(this)->CALL; #define START_FUNCTION(CLASS, RET, PROTOTYPE) \ RET CLASS::PROTOTYPE const { \ const Opcode op = this->getOpcode(); \ switch (op) { #define END_FUNCTION(CLASS, RET) \ case OP_INVALID: return RET(); \ }; \ return RET(); \ } #define CALL getSrcNum() START_FUNCTION(Instruction, uint32_t, getSrcNum(void)) #include "ir/instruction.hxx" END_FUNCTION(Instruction, uint32_t) #undef CALL #define CALL getDstNum() START_FUNCTION(Instruction, uint32_t, getDstNum(void)) #include "ir/instruction.hxx" END_FUNCTION(Instruction, uint32_t) #undef CALL #undef DECL_INSN #define DECL_INSN(OPCODE, CLASS) \ case OP_##OPCODE: \ { \ const Function &fn = this->getFunction(); \ return reinterpret_cast(this)->CALL; \ } #define CALL wellFormed(fn, whyNot) START_FUNCTION(Instruction, bool, wellFormed(std::string &whyNot)) #include "ir/instruction.hxx" END_FUNCTION(Instruction, bool) #undef CALL #define CALL getDst(fn, ID) START_FUNCTION(Instruction, Register, getDst(uint32_t ID)) #include "ir/instruction.hxx" END_FUNCTION(Instruction, Register) #undef CALL #define CALL getSrc(fn, ID) START_FUNCTION(Instruction, Register, getSrc(uint32_t ID)) #include "ir/instruction.hxx" END_FUNCTION(Instruction, Register) #undef CALL #undef DECL_INSN #undef END_FUNCTION #undef START_FUNCTION void Instruction::setSrc(uint32_t srcID, Register reg) { Function &fn = this->getFunction(); #if GBE_DEBUG const RegisterData oldData = this->getSrcData(srcID); const RegisterData newData = fn.getRegisterData(reg); GBE_ASSERT(oldData.family == newData.family); #endif /* GBE_DEBUG */ const Opcode op = this->getOpcode(); switch (op) { #define DECL_INSN(OP, FAMILY)\ case OP_##OP:\ reinterpret_cast(this)->setSrc(fn, srcID, reg);\ break; #include "instruction.hxx" #undef DECL_INSN case OP_INVALID: NOT_SUPPORTED; break; }; } void Instruction::setDst(uint32_t dstID, Register reg) { Function &fn = this->getFunction(); #if GBE_DEBUG const RegisterData oldData = this->getDstData(dstID); const RegisterData newData = fn.getRegisterData(reg); GBE_ASSERT(oldData.family == newData.family); #endif /* GBE_DEBUG */ const Opcode op = this->getOpcode(); switch (op) { #define DECL_INSN(OP, FAMILY)\ case OP_##OP:\ reinterpret_cast(this)->setDst(fn, dstID, reg);\ break; #include "instruction.hxx" #undef DECL_INSN case OP_INVALID: NOT_SUPPORTED; break; }; } const Function &Instruction::getFunction(void) const { const BasicBlock *bb = this->getParent(); GBE_ASSERT(bb != NULL); return bb->getParent(); } Function &Instruction::getFunction(void) { BasicBlock *bb = this->getParent(); GBE_ASSERT(bb != NULL); return bb->getParent(); } void Instruction::replace(Instruction *other) const { Function &fn = other->getFunction(); Instruction *insn = fn.newInstruction(*this); intrusive_list_node *prev = other->prev; insn->parent = other->parent; other->remove(); append(insn, prev); } void Instruction::remove(void) { Function &fn = this->getFunction(); unlink(this); fn.deleteInstruction(this); } void Instruction::insert(Instruction *prev, Instruction ** new_ins) { Function &fn = prev->getFunction(); Instruction *insn = fn.newInstruction(*this); insn->parent = prev->parent; append(insn, prev); if (new_ins) *new_ins = insn; } bool Instruction::hasSideEffect(void) const { return opcode == OP_STORE || opcode == OP_TYPED_WRITE || opcode == OP_SYNC || opcode == OP_ATOMIC || opcode == OP_CALC_TIMESTAMP || opcode == OP_STORE_PROFILING || opcode == OP_WAIT; } #define DECL_MEM_FN(CLASS, RET, PROTOTYPE, CALL) \ RET CLASS::PROTOTYPE const { \ return reinterpret_cast(this)->CALL; \ } DECL_MEM_FN(NullaryInstruction, Type, getType(void), getType()) DECL_MEM_FN(UnaryInstruction, Type, getType(void), getType()) DECL_MEM_FN(BinaryInstruction, Type, getType(void), getType()) DECL_MEM_FN(BinaryInstruction, bool, commutes(void), commutes()) DECL_MEM_FN(SelectInstruction, Type, getType(void), getType()) DECL_MEM_FN(TernaryInstruction, Type, getType(void), getType()) DECL_MEM_FN(CompareInstruction, Type, getType(void), getType()) DECL_MEM_FN(BitCastInstruction, Type, getSrcType(void), getSrcType()) DECL_MEM_FN(BitCastInstruction, Type, getDstType(void), getDstType()) DECL_MEM_FN(ConvertInstruction, Type, getSrcType(void), getSrcType()) DECL_MEM_FN(ConvertInstruction, Type, getDstType(void), getDstType()) DECL_MEM_FN(MemInstruction, AddressSpace, getAddressSpace(void), getAddressSpace()) DECL_MEM_FN(MemInstruction, AddressMode, getAddressMode(void), getAddressMode()) DECL_MEM_FN(MemInstruction, Register, getAddressRegister(void), getAddressRegister()) DECL_MEM_FN(MemInstruction, Register, getBtiReg(void), getBtiReg()) DECL_MEM_FN(MemInstruction, unsigned, getSurfaceIndex(void), getSurfaceIndex()) DECL_MEM_FN(MemInstruction, Type, getValueType(void), getValueType()) DECL_MEM_FN(MemInstruction, bool, isAligned(void), isAligned()) DECL_MEM_FN(MemInstruction, unsigned, getAddressIndex(void), getAddressIndex()) DECL_MEM_FN(AtomicInstruction, AtomicOps, getAtomicOpcode(void), getAtomicOpcode()) DECL_MEM_FN(StoreInstruction, uint32_t, getValueNum(void), getValueNum()) DECL_MEM_FN(LoadInstruction, uint32_t, getValueNum(void), getValueNum()) DECL_MEM_FN(LoadImmInstruction, Type, getType(void), getType()) DECL_MEM_FN(LabelInstruction, LabelIndex, getLabelIndex(void), getLabelIndex()) DECL_MEM_FN(BranchInstruction, bool, isPredicated(void), isPredicated()) DECL_MEM_FN(BranchInstruction, bool, getInversePredicated(void), getInversePredicated()) DECL_MEM_FN(BranchInstruction, LabelIndex, getLabelIndex(void), getLabelIndex()) DECL_MEM_FN(SyncInstruction, uint32_t, getParameters(void), getParameters()) DECL_MEM_FN(ReadARFInstruction, Type, getType(void), getType()) DECL_MEM_FN(ReadARFInstruction, ARFRegister, getARFRegister(void), getARFRegister()) DECL_MEM_FN(SimdShuffleInstruction, Type, getType(void), getType()) DECL_MEM_FN(RegionInstruction, uint32_t, getOffset(void), getOffset()) DECL_MEM_FN(IndirectMovInstruction, uint32_t, getOffset(void), getOffset()) DECL_MEM_FN(IndirectMovInstruction, Type, getType(void), getType()) DECL_MEM_FN(SampleInstruction, Type, getSrcType(void), getSrcType()) DECL_MEM_FN(SampleInstruction, Type, getDstType(void), getDstType()) DECL_MEM_FN(SampleInstruction, uint8_t, getSamplerIndex(void), getSamplerIndex()) DECL_MEM_FN(SampleInstruction, uint8_t, getSamplerOffset(void), getSamplerOffset()) DECL_MEM_FN(SampleInstruction, uint8_t, getImageIndex(void), getImageIndex()) DECL_MEM_FN(VmeInstruction, Type, getSrcType(void), getSrcType()) DECL_MEM_FN(VmeInstruction, Type, getDstType(void), getDstType()) DECL_MEM_FN(VmeInstruction, uint8_t, getImageIndex(void), getImageIndex()) DECL_MEM_FN(VmeInstruction, uint8_t, getMsgType(void), getMsgType()) DECL_MEM_FN(TypedWriteInstruction, Type, getSrcType(void), getSrcType()) DECL_MEM_FN(TypedWriteInstruction, Type, getCoordType(void), getCoordType()) DECL_MEM_FN(TypedWriteInstruction, uint8_t, getImageIndex(void), getImageIndex()) DECL_MEM_FN(GetImageInfoInstruction, uint32_t, getInfoType(void), getInfoType()) DECL_MEM_FN(GetImageInfoInstruction, uint8_t, getImageIndex(void), getImageIndex()) DECL_MEM_FN(CalcTimestampInstruction, uint32_t, getPointNum(void), getPointNum()) DECL_MEM_FN(CalcTimestampInstruction, uint32_t, getTimestamptType(void), getTimestamptType()) DECL_MEM_FN(StoreProfilingInstruction, uint32_t, getProfilingType(void), getProfilingType()) DECL_MEM_FN(StoreProfilingInstruction, uint32_t, getBTI(void), getBTI()) #undef DECL_MEM_FN #define DECL_MEM_FN(CLASS, RET, PROTOTYPE, CALL) \ RET CLASS::PROTOTYPE { \ return reinterpret_cast(this)->CALL; \ } DECL_MEM_FN(MemInstruction, void, setSurfaceIndex(unsigned id), setSurfaceIndex(id)) DECL_MEM_FN(MemInstruction, void, setBtiReg(Register reg), setBtiReg(reg)) #undef DECL_MEM_FN Immediate LoadImmInstruction::getImmediate(void) const { const Function &fn = this->getFunction(); return reinterpret_cast(this)->getImmediate(fn); } /////////////////////////////////////////////////////////////////////////// // Implements the emission functions /////////////////////////////////////////////////////////////////////////// // For all nullary functions with given opcode Instruction ALU0(Opcode opcode, Type type, Register dst) { return internal::NullaryInstruction(opcode, type, dst).convert(); } // All nullary functions #define DECL_EMIT_FUNCTION(NAME) \ Instruction NAME(Type type, Register dst) { \ return ALU0(OP_##NAME, type, dst);\ } DECL_EMIT_FUNCTION(SIMD_SIZE) DECL_EMIT_FUNCTION(SIMD_ID) #undef DECL_EMIT_FUNCTION // For all unary functions with given opcode Instruction ALU1(Opcode opcode, Type type, Register dst, Register src) { return internal::UnaryInstruction(opcode, type, dst, src).convert(); } // All unary functions #define DECL_EMIT_FUNCTION(NAME) \ Instruction NAME(Type type, Register dst, Register src) { \ return ALU1(OP_##NAME, type, dst, src);\ } DECL_EMIT_FUNCTION(MOV) DECL_EMIT_FUNCTION(FBH) DECL_EMIT_FUNCTION(FBL) DECL_EMIT_FUNCTION(CBIT) DECL_EMIT_FUNCTION(LZD) DECL_EMIT_FUNCTION(COS) DECL_EMIT_FUNCTION(SIN) DECL_EMIT_FUNCTION(LOG) DECL_EMIT_FUNCTION(SQR) DECL_EMIT_FUNCTION(RSQ) DECL_EMIT_FUNCTION(RNDD) DECL_EMIT_FUNCTION(RNDE) DECL_EMIT_FUNCTION(RNDU) DECL_EMIT_FUNCTION(RNDZ) #undef DECL_EMIT_FUNCTION // All binary functions #define DECL_EMIT_FUNCTION(NAME) \ Instruction NAME(Type type, Register dst, Register src0, Register src1) { \ return internal::BinaryInstruction(OP_##NAME, type, dst, src0, src1).convert(); \ } DECL_EMIT_FUNCTION(POW) DECL_EMIT_FUNCTION(MUL) DECL_EMIT_FUNCTION(ADD) DECL_EMIT_FUNCTION(ADDSAT) DECL_EMIT_FUNCTION(SUB) DECL_EMIT_FUNCTION(SUBSAT) DECL_EMIT_FUNCTION(MUL_HI) DECL_EMIT_FUNCTION(I64_MUL_HI) DECL_EMIT_FUNCTION(UPSAMPLE_SHORT) DECL_EMIT_FUNCTION(UPSAMPLE_INT) DECL_EMIT_FUNCTION(UPSAMPLE_LONG) DECL_EMIT_FUNCTION(DIV) DECL_EMIT_FUNCTION(REM) DECL_EMIT_FUNCTION(SHL) DECL_EMIT_FUNCTION(SHR) DECL_EMIT_FUNCTION(ASR) DECL_EMIT_FUNCTION(BSF) DECL_EMIT_FUNCTION(BSB) DECL_EMIT_FUNCTION(OR) DECL_EMIT_FUNCTION(XOR) DECL_EMIT_FUNCTION(AND) DECL_EMIT_FUNCTION(HADD) DECL_EMIT_FUNCTION(RHADD) DECL_EMIT_FUNCTION(I64HADD) DECL_EMIT_FUNCTION(I64RHADD) #undef DECL_EMIT_FUNCTION // SEL Instruction SEL(Type type, Register dst, Tuple src) { return internal::SelectInstruction(type, dst, src).convert(); } Instruction I64MADSAT(Type type, Register dst, Tuple src) { return internal::TernaryInstruction(OP_I64MADSAT, type, dst, src).convert(); } Instruction MAD(Type type, Register dst, Tuple src) { return internal::TernaryInstruction(OP_MAD, type, dst, src).convert(); } // All compare functions #define DECL_EMIT_FUNCTION(NAME) \ Instruction NAME(Type type, Register dst, Register src0, Register src1) { \ const internal::CompareInstruction insn(OP_##NAME, type, dst, src0, src1); \ return insn.convert(); \ } DECL_EMIT_FUNCTION(EQ) DECL_EMIT_FUNCTION(NE) DECL_EMIT_FUNCTION(LE) DECL_EMIT_FUNCTION(LT) DECL_EMIT_FUNCTION(GE) DECL_EMIT_FUNCTION(GT) DECL_EMIT_FUNCTION(ORD) #undef DECL_EMIT_FUNCTION // BITCAST Instruction BITCAST(Type dstType, Type srcType, Tuple dst, Tuple src, uint8_t dstNum, uint8_t srcNum) { return internal::BitCastInstruction(dstType, srcType, dst, src, dstNum, srcNum).convert(); } // CVT Instruction CVT(Type dstType, Type srcType, Register dst, Register src) { return internal::ConvertInstruction(OP_CVT, dstType, srcType, dst, src).convert(); } // saturated convert Instruction SAT_CVT(Type dstType, Type srcType, Register dst, Register src) { return internal::ConvertInstruction(OP_SAT_CVT, dstType, srcType, dst, src).convert(); } // CVT Instruction F16TO32(Type dstType, Type srcType, Register dst, Register src) { return internal::ConvertInstruction(OP_F16TO32, dstType, srcType, dst, src).convert(); } // saturated convert Instruction F32TO16(Type dstType, Type srcType, Register dst, Register src) { return internal::ConvertInstruction(OP_F32TO16, dstType, srcType, dst, src).convert(); } // For all unary functions with given opcode Instruction ATOMIC(AtomicOps atomicOp, Type type, Register dst, AddressSpace space, Register address, Tuple payload, AddressMode AM, Register bti) { internal::AtomicInstruction insn = internal::AtomicInstruction(atomicOp, type, dst, space, address, payload, AM); insn.setBtiReg(bti); return insn.convert(); } Instruction ATOMIC(AtomicOps atomicOp, Type type, Register dst, AddressSpace space, Register address, Tuple payload, AddressMode AM, unsigned SurfaceIndex) { internal::AtomicInstruction insn = internal::AtomicInstruction(atomicOp, type, dst, space, address, payload, AM); insn.setSurfaceIndex(SurfaceIndex); return insn.convert(); } // BRA Instruction BRA(LabelIndex labelIndex) { return internal::BranchInstruction(OP_BRA, labelIndex).convert(); } Instruction BRA(LabelIndex labelIndex, Register pred) { return internal::BranchInstruction(OP_BRA, labelIndex, pred).convert(); } // IF Instruction IF(LabelIndex labelIndex, Register pred, bool inv_pred) { return internal::BranchInstruction(OP_IF, labelIndex, pred, inv_pred).convert(); } // ELSE Instruction ELSE(LabelIndex labelIndex) { return internal::BranchInstruction(OP_ELSE, labelIndex).convert(); } // ENDIF Instruction ENDIF(LabelIndex labelIndex) { return internal::BranchInstruction(OP_ENDIF, labelIndex).convert(); } // WHILE Instruction WHILE(LabelIndex labelIndex, Register pred) { return internal::BranchInstruction(OP_WHILE, labelIndex, pred).convert(); } // RET Instruction RET(void) { return internal::BranchInstruction(OP_RET).convert(); } // LOADI Instruction LOADI(Type type, Register dst, ImmediateIndex value) { return internal::LoadImmInstruction(type, dst, value).convert(); } // LOAD and STORE #define DECL_EMIT_FUNCTION(NAME, CLASS) \ Instruction NAME(Type type, \ Tuple tuple, \ Register offset, \ AddressSpace space, \ uint32_t valueNum, \ bool dwAligned, \ AddressMode AM, \ unsigned SurfaceIndex) \ { \ internal::CLASS insn = internal::CLASS(type,tuple,offset,space,valueNum,dwAligned,AM); \ insn.setSurfaceIndex(SurfaceIndex);\ return insn.convert(); \ } \ Instruction NAME(Type type, \ Tuple tuple, \ Register offset, \ AddressSpace space, \ uint32_t valueNum, \ bool dwAligned, \ AddressMode AM, \ Register bti) \ { \ internal::CLASS insn = internal::CLASS(type,tuple,offset,space,valueNum,dwAligned,AM); \ insn.setBtiReg(bti); \ return insn.convert(); \ } DECL_EMIT_FUNCTION(LOAD, LoadInstruction) DECL_EMIT_FUNCTION(STORE, StoreInstruction) #undef DECL_EMIT_FUNCTION // FENCE Instruction SYNC(uint32_t parameters) { return internal::SyncInstruction(parameters).convert(); } Instruction READ_ARF(Type type, Register dst, ARFRegister arf) { return internal::ReadARFInstruction(type, dst, arf).convert(); } Instruction REGION(Register dst, Register src, uint32_t offset) { return internal::RegionInstruction(dst, src, offset).convert(); } Instruction SIMD_SHUFFLE(Type type, Register dst, Register src0, Register src1) { return internal::SimdShuffleInstruction(type, dst, src0, src1).convert(); } Instruction INDIRECT_MOV(Type type, Register dst, Register src0, Register src1, uint32_t offset) { return internal::IndirectMovInstruction(type, dst, src0, src1, offset).convert(); } // LABEL Instruction LABEL(LabelIndex labelIndex) { return internal::LabelInstruction(labelIndex).convert(); } // SAMPLE Instruction SAMPLE(uint8_t imageIndex, Tuple dst, Tuple src, uint8_t srcNum, bool dstIsFloat, bool srcIsFloat, uint8_t sampler, uint8_t samplerOffset) { return internal::SampleInstruction(imageIndex, dst, src, srcNum, dstIsFloat, srcIsFloat, sampler, samplerOffset).convert(); } Instruction VME(uint8_t imageIndex, Tuple dst, Tuple src, uint32_t dstNum, uint32_t srcNum, int msg_type, int vme_search_path_lut, int lut_sub) { return internal::VmeInstruction(imageIndex, dst, src, dstNum, srcNum, msg_type, vme_search_path_lut, lut_sub).convert(); } Instruction TYPED_WRITE(uint8_t imageIndex, Tuple src, uint8_t srcNum, Type srcType, Type coordType) { return internal::TypedWriteInstruction(imageIndex, src, srcNum, srcType, coordType).convert(); } Instruction GET_IMAGE_INFO(int infoType, Register dst, uint8_t imageIndex, Register infoReg) { return internal::GetImageInfoInstruction(infoType, dst, imageIndex, infoReg).convert(); } Instruction CALC_TIMESTAMP(uint32_t pointNum, uint32_t tsType) { return internal::CalcTimestampInstruction(pointNum, tsType).convert(); } Instruction STORE_PROFILING(uint32_t bti, uint32_t profilingType) { return internal::StoreProfilingInstruction(bti, profilingType).convert(); } // WAIT Instruction WAIT(void) { return internal::WaitInstruction().convert(); } std::ostream &operator<< (std::ostream &out, const Instruction &insn) { const Function &fn = insn.getFunction(); const BasicBlock *bb = insn.getParent(); switch (insn.getOpcode()) { #define DECL_INSN(OPCODE, CLASS) \ case OP_##OPCODE: \ if(OP_##OPCODE == OP_ELSE) \ { \ reinterpret_cast(insn).out(out, fn); \ out << " <**>label: " << bb->thisElseLabel; \ break; \ } \ reinterpret_cast(insn).out(out, fn); \ break; #include "instruction.hxx" #undef DECL_INSN case OP_INVALID: NOT_SUPPORTED; break; }; return out; } } /* namespace ir */ } /* namespace gbe */