/*
* 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.hpp
* \author Benjamin Segovia
*/
#ifndef __GBE_IR_INSTRUCTION_HPP__
#define __GBE_IR_INSTRUCTION_HPP__
#include "ir/register.hpp"
#include "ir/immediate.hpp"
#include "ir/type.hpp"
#include "sys/platform.hpp"
#include "sys/intrusive_list.hpp"
#include
#define MAX_MIXED_POINTER 4
namespace gbe {
namespace ir {
struct BTI {
uint8_t bti[MAX_MIXED_POINTER];
uint8_t count;
BTI() : count(0) {
memset(bti, 0, MAX_MIXED_POINTER);
}
~BTI() {}
};
/*! All opcodes */
enum Opcode : uint8_t {
#define DECL_INSN(INSN, FAMILY) OP_##INSN,
#include "ir/instruction.hxx"
#undef DECL_INSN
OP_INVALID
};
/*! Different memory spaces */
enum AddressSpace : uint8_t {
MEM_GLOBAL = 0, //!< Global memory (a la OCL)
MEM_LOCAL, //!< Local memory (thread group memory)
MEM_CONSTANT, //!< Immutable global memory
MEM_PRIVATE, //!< Per thread private memory
MEM_MIXED, //!< mixed address space pointer.
MEM_INVALID
};
enum AtomicOps {
ATOMIC_OP_AND = 1,
ATOMIC_OP_OR = 2,
ATOMIC_OP_XOR = 3,
ATOMIC_OP_XCHG = 4,
ATOMIC_OP_INC = 5,
ATOMIC_OP_DEC = 6,
ATOMIC_OP_ADD = 7,
ATOMIC_OP_SUB = 8,
ATOMIC_OP_IMAX = 10,
ATOMIC_OP_IMIN = 11,
ATOMIC_OP_UMAX = 12,
ATOMIC_OP_UMIN = 13,
ATOMIC_OP_CMPXCHG = 14,
ATOMIC_OP_INVALID
};
/* Vote function per hardware thread */
enum VotePredicate : uint8_t {
VOTE_ALL = 0,
VOTE_ANY
};
/*! Output the memory space */
std::ostream &operator<< (std::ostream &out, AddressSpace addrSpace);
/*! A label is identified with an unsigned short */
TYPE_SAFE(LabelIndex, uint32_t)
/*! Function class contains the register file and the register tuple. Any
* information related to the registers may therefore require a function
*/
class Function;
/*! Contains the stream of instructions */
class BasicBlock;
///////////////////////////////////////////////////////////////////////////
/// All public instruction classes as manipulated by all public classes
///////////////////////////////////////////////////////////////////////////
/*! Stores instruction internal data and opcode */
class ALIGNED(sizeof(uint64_t)*4) InstructionBase
{
public:
/*! Initialize the instruction from a 8 bytes stream */
INLINE InstructionBase(const char *stream) {
opcode = Opcode(stream[0]);
for (uint32_t byte = 0; byte < opaqueSize; ++byte)
opaque[byte] = stream[byte+1];
}
/*! Uninitialized instruction */
INLINE InstructionBase(void) {}
/*! Get the instruction opcode */
INLINE Opcode getOpcode(void) const { return opcode; }
protected:
enum { opaqueSize = sizeof(uint64_t)*4-sizeof(uint8_t) };
Opcode opcode; //!< Idendifies the instruction
char opaque[opaqueSize]; //!< Remainder of it
GBE_CLASS(InstructionBase); //!< Use internal allocators
};
/*! Store the instruction description in 32 bytes */
class Instruction : public InstructionBase, public intrusive_list_node
{
public:
/*! Initialize the instruction from a 8 bytes stream */
INLINE Instruction(const char *stream) : InstructionBase(stream) {
parent = NULL;
}
/*! Copy the private fields and give it the same parent */
INLINE Instruction(const Instruction &other) :
InstructionBase(reinterpret_cast(&other.opcode)) {
parent = other.parent;
}
private:
/*! To be consistant with copy constructor */
INLINE Instruction &operator= (const Instruction &other) { return *this; }
public:
/*! Nothing to do here */
INLINE ~Instruction(void) {}
/*! Uninitialized instruction */
INLINE Instruction(void) {}
/*! Get the number of sources for this instruction */
uint32_t getSrcNum(void) const;
/*! Get the number of destination for this instruction */
uint32_t getDstNum(void) const;
/*! Get the register index of the given source */
Register getSrc(uint32_t ID = 0u) const;
/*! Get the register index of the given destination */
Register getDst(uint32_t ID = 0u) const;
/*! Get the register of the given source */
RegisterData getDstData(uint32_t ID = 0u) const;
/*! Get the register of the given destination */
RegisterData getSrcData(uint32_t ID = 0u) const;
/*! Set a register in src srcID */
void setSrc(uint32_t srcID, Register reg);
/*! Set a register in dst dstID */
void setDst(uint32_t dstID, Register reg);
/*! Is there any side effect in the memory sub-system? */
bool hasSideEffect(void) const;
/*! Get / set the parent basic block */
BasicBlock *getParent(void) { return parent; }
const BasicBlock *getParent(void) const { return parent; }
void setParent(BasicBlock *block) { this->parent = block; }
/*! Get the function from the parent basic block */
const Function &getFunction(void) const;
Function &getFunction(void);
/*! Check that the instruction is well formed (type properly match,
* registers not of bound and so on). If not well formed, provide a reason
* in string why
*/
bool wellFormed(std::string &why) const;
/*! Replace other by this instruction */
void replace(Instruction *other) const;
/*! Remove the instruction from the instruction stream */
void remove(void);
/* Insert the instruction after the previous one. */
void insert(Instruction *prev, Instruction ** new_ins = NULL);
/*! Indicates if the instruction belongs to instruction type T. Typically, T
* can be BinaryInstruction, UnaryInstruction, LoadInstruction and so on
*/
template INLINE bool isMemberOf(void) const {
return T::isClassOf(*this);
}
/*! max_src for store instruction (vec16 + addr) */
static const uint32_t MAX_SRC_NUM = 32;
static const uint32_t MAX_DST_NUM = 32;
protected:
BasicBlock *parent; //!< The basic block containing the instruction
GBE_CLASS(Instruction); //!< Use internal allocators
};
/*! Output the instruction string in the given stream */
std::ostream &operator<< (std::ostream &out, const Instruction &proxy);
/*! Nullary instruction instructions are typed. */
class NullaryInstruction : public Instruction {
public:
/*! Get the type manipulated by the instruction */
Type getType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Unary instructions are typed. dst and sources share the same type */
class UnaryInstruction : public Instruction {
public:
/*! Get the type manipulated by the instruction */
Type getType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Binary instructions are typed. dst and sources share the same type */
class BinaryInstruction : public Instruction {
public:
/*! Get the type manipulated by the instruction */
Type getType(void) const;
/*! Commutative instructions can allow better optimizations */
bool commutes(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Ternary instructions are typed. dst and sources share the same type */
class TernaryInstruction : public Instruction {
public:
Type getType(void) const;
static bool isClassOf(const Instruction &insn);
};
/*! Select instructions writes src0 to dst if cond is true. Otherwise, it
* writes src1
*/
class SelectInstruction : public Instruction {
public:
/*! Predicate is in slot 0. So first source to selec is in slot 1 */
static const uint32_t src0Index = 1;
/*! Second source to select is in slot 2 */
static const uint32_t src1Index = 2;
/*! Get the predicate of the selection instruction */
INLINE Register getPredicate(void) const { return this->getSrc(0); }
/*! Get the type of both sources */
Type getType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Compare instructions compare anything from the same type and return a
* boolean value
*/
class CompareInstruction : public Instruction {
public:
/*! Get the type of the source registers */
Type getType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! BitCast instruction converts from one type to another */
class BitCastInstruction : public Instruction {
public:
/*! Get the type of the source */
Type getSrcType(void) const;
/*! Get the type of the destination */
Type getDstType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Conversion instruction converts from one type to another */
class ConvertInstruction : public Instruction {
public:
/*! Get the type of the source */
Type getSrcType(void) const;
/*! Get the type of the destination */
Type getDstType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Atomic instruction */
class AtomicInstruction : public Instruction {
public:
/*! Where the address register goes */
static const uint32_t addressIndex = 0;
/*! Address space that is manipulated here */
AddressSpace getAddressSpace(void) const;
BTI getBTI(void) const;
/*! Return the atomic function code */
AtomicOps getAtomicOpcode(void) const;
/*! Return the register that contains the addresses */
INLINE Register getAddress(void) const { return this->getSrc(addressIndex); }
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Store instruction. First source is the address. Next sources are the
* values to store contiguously at the given address
*/
class StoreInstruction : public Instruction {
public:
/*! Where the address register goes */
static const uint32_t addressIndex = 0;
/*! Return the types of the values to store */
Type getValueType(void) const;
/*! Give the number of values the instruction is storing (srcNum-1) */
uint32_t getValueNum(void) const;
BTI getBTI(void) const;
/*! Address space that is manipulated here */
AddressSpace getAddressSpace(void) const;
/*! DWORD aligned means untyped read for Gen. That is what matters */
bool isAligned(void) const;
/*! Return the register that contains the addresses */
INLINE Register getAddress(void) const { return this->getSrc(addressIndex); }
/*! Return the register that contain value valueID */
INLINE Register getValue(uint32_t valueID) const {
GBE_ASSERT(valueID < this->getValueNum());
return this->getSrc(valueID + 1u);
}
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Load instruction. The source is simply the address where to get the data.
* The multiple destinations are the contiguous values loaded at the given
* address
*/
class LoadInstruction : public Instruction {
public:
/*! Type of the loaded values (ie type of all the destinations) */
Type getValueType(void) const;
/*! Number of values loaded (ie number of destinations) */
uint32_t getValueNum(void) const;
/*! Address space that is manipulated here */
AddressSpace getAddressSpace(void) const;
/*! DWORD aligned means untyped read for Gen. That is what matters */
bool isAligned(void) const;
/*! Return the register that contains the addresses */
INLINE Register getAddress(void) const { return this->getSrc(0u); }
BTI getBTI(void) const;
/*! Return the register that contain value valueID */
INLINE Register getValue(uint32_t valueID) const {
return this->getDst(valueID);
}
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Load immediate instruction loads an typed immediate value into the given
* register. Since double and uint64_t values will not fit into an
* instruction, the immediate themselves are stored in the function core.
* Contrary to regular load instructions, there is only one destination
* possible
*/
class LoadImmInstruction : public Instruction {
public:
/*! Return the value stored in the instruction */
Immediate getImmediate(void) const;
/*! Return the type of the stored value */
Type getType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Store data in an texture */
class TypedWriteInstruction : public Instruction {
public:
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
uint8_t getImageIndex() const;
Type getSrcType(void) const;
Type getCoordType(void) const;
};
/*! Load texels from a texture */
class SampleInstruction : public Instruction {
public:
uint8_t getImageIndex() const;
uint8_t getSamplerIndex(void) const;
uint8_t getSamplerOffset(void) const;
Type getSrcType(void) const;
Type getDstType(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
typedef union _ImageInfoKey{
_ImageInfoKey(uint8_t i, uint8_t t) : index(i), type(t) {};
struct {
uint8_t index; /*! the allocated image index */
uint8_t type; /*! the information type */
};
uint16_t data;
} ImageInfoKey;
/*! Get image information */
class GetImageInfoInstruction : public Instruction {
public:
enum {
WIDTH = 0,
HEIGHT = 1,
DEPTH = 2,
CHANNEL_DATA_TYPE = 3,
CHANNEL_ORDER = 4,
};
static INLINE uint32_t getDstNum4Type(int infoType) {
switch (infoType) {
case WIDTH:
case HEIGHT:
case DEPTH:
case CHANNEL_DATA_TYPE:
case CHANNEL_ORDER:
return 1;
break;
default:
GBE_ASSERT(0);
}
return 0;
}
uint8_t getImageIndex() const;
uint32_t getInfoType() const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Branch instruction is the unified way to branch (with or without
* predicate)
*/
class BranchInstruction : public Instruction {
public:
/*! Indicate if the branch is predicated */
bool isPredicated(void) const;
/*! Indicate if the branch is inverse predicated */
bool getInversePredicated(void) const;
/*! Return the predicate register (if predicated) */
RegisterData getPredicate(void) const {
GBE_ASSERTM(this->isPredicated() == true, "Branch is not predicated");
return this->getSrcData(0);
}
/*! Return the predicate register index (if predicated) */
Register getPredicateIndex(void) const {
GBE_ASSERTM(this->isPredicated() == true, "Branch is not predicated");
return this->getSrc(0);
}
/*! Return the label index pointed by the branch */
LabelIndex getLabelIndex(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Label instruction are actual no-op but are referenced by branches as their
* targets
*/
class LabelInstruction : public Instruction {
public:
/*! Return the label index of the instruction */
LabelIndex getLabelIndex(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Texture instruction are used for any texture mapping requests */
class TextureInstruction : public Instruction {
public:
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Mapped to OpenCL (mem_fence, read_mem_fence, write_mem_fence, barrier) */
enum {
SYNC_WORKGROUP_EXEC = 1<<0,
SYNC_LOCAL_READ_FENCE = 1<<1,
SYNC_LOCAL_WRITE_FENCE = 1<<2,
SYNC_GLOBAL_READ_FENCE = 1<<3,
SYNC_GLOBAL_WRITE_FENCE = 1<<4,
SYNC_INVALID = 1<<5
};
/*! 5 bits to encode all possible synchronization capablities */
static const uint32_t syncFieldNum = 5u;
/*! When barrier(CLK_LOCAL_MEM_FENCE) is issued */
static const uint32_t syncLocalBarrier = SYNC_WORKGROUP_EXEC |SYNC_LOCAL_WRITE_FENCE | SYNC_LOCAL_READ_FENCE;
/*! When barrier(CLK_GLOBAL_MEM_FENCE) is issued */
static const uint32_t syncGlobalBarrier = SYNC_WORKGROUP_EXEC | SYNC_GLOBAL_WRITE_FENCE | SYNC_GLOBAL_READ_FENCE;
/*! Sync instructions are used to order loads and stores for a given memory
* space and/or to serialize threads at a given point in the program
*/
class SyncInstruction : public Instruction {
public:
/*! Get the parameters (bitfields) of the sync instructions (see above) */
uint32_t getParameters(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Read one register (8 DWORD) in arf */
class ReadARFInstruction : public Instruction {
public:
Type getType() const;
ir::ARFRegister getARFRegister() const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! return a region of a register, make sure the offset does not exceed the register size */
class RegionInstruction : public Instruction {
public:
uint32_t getOffset(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Indirect Move instruction */
class IndirectMovInstruction : public Instruction {
public:
Type getType(void) const;
uint32_t getOffset(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/*! Specialize the instruction. Also performs typechecking first based on the
* opcode. Crashes if it fails
*/
template
INLINE T *cast(Instruction *insn) {
if(insn->isMemberOf())
return reinterpret_cast(insn);
else
return NULL;
}
template
INLINE const T *cast(const Instruction *insn) {
if(insn->isMemberOf())
return reinterpret_cast(insn);
else
return NULL;
}
template
INLINE T &cast(Instruction &insn) {
GBE_ASSERTM(insn.isMemberOf() == true, "Invalid instruction type");
return reinterpret_cast(insn);
}
template
INLINE const T &cast(const Instruction &insn) {
GBE_ASSERTM(insn.isMemberOf() == true, "Invalid instruction type");
return reinterpret_cast(insn);
}
/*! Indicates if the given opcode belongs the given instruction family */
template struct EqualType {enum {value = false};};
template struct EqualType { enum {value = true};};
template
INLINE bool isOpcodeFrom(Opcode op) {
switch (op) {
#define DECL_INSN(OPCODE, FAMILY) \
case OP_##OPCODE: return EqualType::value;
#include "instruction.hxx"
#undef DECL_INSN
default: NOT_SUPPORTED; return false;
}
}
///////////////////////////////////////////////////////////////////////////
/// All emission functions
///////////////////////////////////////////////////////////////////////////
/*! alu0.type dst */
Instruction ALU0(Opcode opcode, Type type, Register dst);
/*! simd_size.type dst */
Instruction SIMD_SIZE(Type type, Register dst);
/*! simd_id.type dst */
Instruction SIMD_ID(Type type, Register dst);
/*! alu1.type dst src */
Instruction ALU1(Opcode opcode, Type type, Register dst, Register src);
/*! mov.type dst src */
Instruction MOV(Type type, Register dst, Register src);
/*! cos.type dst src */
Instruction COS(Type type, Register dst, Register src);
/*! sin.type dst src */
Instruction SIN(Type type, Register dst, Register src);
/*! mul_hi.type dst src */
Instruction MUL_HI(Type type, Register dst, Register src0, Register src1);
/*! i64_mul_hi.type dst src */
Instruction I64_MUL_HI(Type type, Register dst, Register src0, Register src1);
/*! i64madsat.type dst src */
Instruction I64MADSAT(Type type, Register dst, Tuple src);
/*! mad.type dst src */
Instruction MAD(Type type, Register dst, Tuple src);
/*! upsample_short.type dst src */
Instruction UPSAMPLE_SHORT(Type type, Register dst, Register src0, Register src1);
/*! upsample_int.type dst src */
Instruction UPSAMPLE_INT(Type type, Register dst, Register src0, Register src1);
/*! upsample_long.type dst src */
Instruction UPSAMPLE_LONG(Type type, Register dst, Register src0, Register src1);
/*! fbh.type dst src */
Instruction FBH(Type type, Register dst, Register src);
/*! fbl.type dst src */
Instruction FBL(Type type, Register dst, Register src);
/*! cbit.type dst src */
Instruction CBIT(Type type, Register dst, Register src);
/*! lzd.type dst src */
Instruction LZD(Type type, Register dst, Register src);
/*! hadd.type dst src */
Instruction HADD(Type type, Register dst, Register src0, Register src1);
/*! rhadd.type dst src */
Instruction RHADD(Type type, Register dst, Register src0, Register src1);
/*! i64hadd.type dst src */
Instruction I64HADD(Type type, Register dst, Register src0, Register src1);
/*! i64rhadd.type dst src */
Instruction I64RHADD(Type type, Register dst, Register src0, Register src1);
/*! tan.type dst src */
Instruction RCP(Type type, Register dst, Register src);
/*! abs.type dst src */
Instruction ABS(Type type, Register dst, Register src);
/*! simd_all.type dst src */
Instruction SIMD_ALL(Type type, Register dst, Register src);
/*! simd_any.type dst src */
Instruction SIMD_ANY(Type type, Register dst, Register src);
/*! log.type dst src */
Instruction LOG(Type type, Register dst, Register src);
/*! exp.type dst src */
Instruction EXP(Type type, Register dst, Register src);
/*! sqr.type dst src */
Instruction SQR(Type type, Register dst, Register src);
/*! rsq.type dst src */
Instruction RSQ(Type type, Register dst, Register src);
/*! rndd.type dst src */
Instruction RNDD(Type type, Register dst, Register src);
/*! rnde.type dst src */
Instruction RNDE(Type type, Register dst, Register src);
/*! rndu.type dst src */
Instruction RNDU(Type type, Register dst, Register src);
/*! rndz.type dst src */
Instruction RNDZ(Type type, Register dst, Register src);
/*! bswap.type dst src */
Instruction BSWAP(Type type, Register dst, Register src);
/*! pow.type dst src0 src1 */
Instruction POW(Type type, Register dst, Register src0, Register src1);
/*! mul.type dst src0 src1 */
Instruction MUL(Type type, Register dst, Register src0, Register src1);
/*! add.type dst src0 src1 */
Instruction ADD(Type type, Register dst, Register src0, Register src1);
/*! addsat.type dst src0 src1 */
Instruction ADDSAT(Type type, Register dst, Register src0, Register src1);
/*! sub.type dst src0 src1 */
Instruction SUB(Type type, Register dst, Register src0, Register src1);
/*! subsat.type dst src0 src1 */
Instruction SUBSAT(Type type, Register dst, Register src0, Register src1);
/*! div.type dst src0 src1 */
Instruction DIV(Type type, Register dst, Register src0, Register src1);
/*! rem.type dst src0 src1 */
Instruction REM(Type type, Register dst, Register src0, Register src1);
/*! shl.type dst src0 src1 */
Instruction SHL(Type type, Register dst, Register src0, Register src1);
/*! shr.type dst src0 src1 */
Instruction SHR(Type type, Register dst, Register src0, Register src1);
/*! asr.type dst src0 src1 */
Instruction ASR(Type type, Register dst, Register src0, Register src1);
/*! bsf.type dst src0 src1 */
Instruction BSF(Type type, Register dst, Register src0, Register src1);
/*! bsb.type dst src0 src1 */
Instruction BSB(Type type, Register dst, Register src0, Register src1);
/*! or.type dst src0 src1 */
Instruction OR(Type type, Register dst, Register src0, Register src1);
/*! xor.type dst src0 src1 */
Instruction XOR(Type type, Register dst, Register src0, Register src1);
/*! and.type dst src0 src1 */
Instruction AND(Type type, Register dst, Register src0, Register src1);
/*! sel.type dst {cond, src0, src1} (== src) */
Instruction SEL(Type type, Register dst, Tuple src);
/*! eq.type dst src0 src1 */
Instruction EQ(Type type, Register dst, Register src0, Register src1);
/*! ne.type dst src0 src1 */
Instruction NE(Type type, Register dst, Register src0, Register src1);
/*! lt.type dst src0 src1 */
Instruction LE(Type type, Register dst, Register src0, Register src1);
/*! le.type dst src0 src1 */
Instruction LT(Type type, Register dst, Register src0, Register src1);
/*! gt.type dst src0 src1 */
Instruction GE(Type type, Register dst, Register src0, Register src1);
/*! ge.type dst src0 src1 */
Instruction GT(Type type, Register dst, Register src0, Register src1);
/*! ord.type dst src0 src1 */
Instruction ORD(Type type, Register dst, Register src0, Register src1);
/*! sub_group_shuffle.type dst src0 src1 */
Instruction SIMD_SHUFFLE(Type type, Register dst, Register src0, Register src1);
/*! BITCAST.{dstType <- srcType} dst src */
Instruction BITCAST(Type dstType, Type srcType, Tuple dst, Tuple src, uint8_t dstNum, uint8_t srcNum);
/*! cvt.{dstType <- srcType} dst src */
Instruction CVT(Type dstType, Type srcType, Register dst, Register src);
/*! sat_cvt.{dstType <- srcType} dst src */
Instruction SAT_CVT(Type dstType, Type srcType, Register dst, Register src);
/*! F16TO32.{dstType <- srcType} dst src */
Instruction F16TO32(Type dstType, Type srcType, Register dst, Register src);
/*! F32TO16.{dstType <- srcType} dst src */
Instruction F32TO16(Type dstType, Type srcType, Register dst, Register src);
/*! atomic dst addr.space {src1 {src2}} */
Instruction ATOMIC(AtomicOps opcode, Register dst, AddressSpace space, BTI bti, Tuple src);
/*! bra labelIndex */
Instruction BRA(LabelIndex labelIndex);
/*! (pred) bra labelIndex */
Instruction BRA(LabelIndex labelIndex, Register pred);
/*! (pred) if labelIndex */
Instruction IF(LabelIndex labelIndex, Register pred, bool inv_pred=true);
/*! else labelIndex */
Instruction ELSE(LabelIndex labelIndex);
/*! endif */
Instruction ENDIF(LabelIndex labelIndex);
/*! (pred) while labelIndex */
Instruction WHILE(LabelIndex labelIndex, Register pred);
/*! ret */
Instruction RET(void);
/*! load.type.space {dst1,...,dst_valueNum} offset value */
Instruction LOAD(Type type, Tuple dst, Register offset, AddressSpace space, uint32_t valueNum, bool dwAligned, BTI bti);
/*! store.type.space offset {src1,...,src_valueNum} value */
Instruction STORE(Type type, Tuple src, Register offset, AddressSpace space, uint32_t valueNum, bool dwAligned, BTI bti);
/*! loadi.type dst value */
Instruction LOADI(Type type, Register dst, ImmediateIndex value);
/*! sync.params... (see Sync instruction) */
Instruction SYNC(uint32_t parameters);
Instruction READ_ARF(Type type, Register dst, ARFRegister arf);
Instruction REGION(Register dst, Register src, uint32_t offset);
Instruction INDIRECT_MOV(Type type, Register dst, Register src0, Register src1, uint32_t offset);
/*! typed write */
Instruction TYPED_WRITE(uint8_t imageIndex, Tuple src, uint8_t srcNum, Type srcType, Type coordType);
/*! sample textures */
Instruction SAMPLE(uint8_t imageIndex, Tuple dst, Tuple src, uint8_t srcNum, bool dstIsFloat, bool srcIsFloat, uint8_t sampler, uint8_t samplerOffset);
/*! get image information , such as width/height/depth/... */
Instruction GET_IMAGE_INFO(int infoType, Register dst, uint8_t imageIndex, Register infoReg);
/*! label labelIndex */
Instruction LABEL(LabelIndex labelIndex);
} /* namespace ir */
} /* namespace gbe */
#endif /* __GBE_IR_INSTRUCTION_HPP__ */