ir/ir_instruction.cpp
ir/ir_instruction.hpp
ir/ir_register.cpp
- ir/ir_register.hpp)
+ ir/ir_register.hpp
+ ir/ir_function.cpp
+ ir/ir_function.hpp)
set (COMPILE_UTEST false CACHE bool "Compile or not the unit tests")
if (COMPILE_UTEST)
#ifndef __GBE_IR_FUNCTION_HPP__
#define __GBE_IR_FUNCTION_HPP__
+#include "ir_value.hpp"
+#include "ir_register.hpp"
+#include "ir_instruction.hpp"
+#include "sys/vector.hpp"
+
namespace gbe
{
/*! A function is no more that a set of declared registers and a set of
/*! Extract the register from the register file */
INLINE Register getRegister(uint32 ID) const { return file.get(ID); }
+ /*! Get the register index from the tuple vector */
+ INLINE RegisterIndex getRegisterIndex(TupleIndex ID, uint32 which) const {
+ return file.get(ID, which);
+ }
private:
/*! Create a function by sequential appending of instructions and registers */
friend class FunctionContext;
vector<uint16> input; //!< Input registers of the function
vector<uint16> output; //!< Output registers of the function
+ vector<Value> immediate; //!< All immediate values stored in the function
vector<BasicBlock> insn; //!< All the basic blocks one after the others
RegisterFile file; //!< All the registers used in the instructions
};
namespace gbe
{
+ ///////////////////////////////////////////////////////////////////////////
+ // Implements the concrete implementations of the instruction classes
+ ///////////////////////////////////////////////////////////////////////////
namespace internal
{
+#define ALIGNED_INSTRUCTION ALIGNED(AlignOf<Instruction>::value)
+
/*! All unary and binary arithmetic instructions */
template <uint32 srcNum> // 1 or 2
- class ALIGNED(AlignOf<Instruction>::value) NaryInstruction
+ class ALIGNED_INSTRUCTION NaryInstruction
{
public:
INLINE uint32 getSrcNum(void) const { return srcNum; }
INLINE uint32 getDstNum(void) const { return 1; }
- INLINE uint32 getDstIndex(const Function &fn, uint32 ID) const {
+ INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
assert(ID == 0);
return dst;
}
- INLINE uint32 getSrcIndex(const Function &fn, uint32 ID) const {
+ INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
assert(ID <= srcNum);
return src[ID];
}
- INLINE Register getDst(const Function &fn, uint32 ID) const {
- return fn.getRegister(this->getDstIndex(fn, ID));
- }
- INLINE Register getSrc(const Function &fn, uint32 ID) const {
- return fn.getRegister(this->getSrcIndex(fn, ID));
- }
- protected:
- uint8 opcode; //!< Instruction opcode
+ INLINE Type getType(void) const { return this->type; }
+ Opcode opcode; //!< Instruction opcode
uint8 type; //!< Type of the instruction
uint16 dst; //!< Index of the register in the register file
uint16 src[srcNum]; //!< Indices of the sources
};
/*! All 1-source arithmetic instructions */
- class UnaryInstruction : public NaryInstruction<1>
+ class ALIGNED_INSTRUCTION UnaryInstruction : public NaryInstruction<1>
{
public:
- UnaryInstruction(uint32 opcode, uint32 type, uint32 dst, uint32 src) {
+ UnaryInstruction(Opcode opcode,
+ Type type,
+ RegisterIndex dst,
+ RegisterIndex src) {
this->opcode = opcode;
this->type = type;
this->dst = dst;
};
/*! All 2-source arithmetic instructions */
- class BinaryInstruction : public NaryInstruction<2>
+ class ALIGNED_INSTRUCTION BinaryInstruction : public NaryInstruction<2>
{
public:
- BinaryInstruction(uint32 opcode, uint32 type, uint32 dst, uint32 src0, uint32 src1) {
+ BinaryInstruction(Opcode opcode,
+ Type type,
+ RegisterIndex dst,
+ RegisterIndex src0,
+ RegisterIndex src1) {
this->opcode = opcode;
this->type = type;
this->dst = dst;
}
};
- STATIC_ASSERT(sizeof(UnaryInstruction) <= sizeof(Instruction));
- STATIC_ASSERT(sizeof(BinaryInstruction) <= sizeof(Instruction));
+ /*! This is for MADs mostly. Since three sources cannot be encoded in 64
+ * bytes, we use tuples of registers
+ */
+ class ALIGNED_INSTRUCTION TernaryInstruction
+ {
+ public:
+ TernaryInstruction(Opcode opcode,
+ Type type,
+ RegisterIndex dst,
+ TupleIndex src)
+ {
+ this->opcode = opcode;
+ this->type = type;
+ this->dst = dst;
+ this->src = src;
+ }
+ INLINE uint32 getSrcNum(void) const { return 3; }
+ INLINE uint32 getDstNum(void) const { return 1; }
+ INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
+ assert(ID == 0);
+ return dst;
+ }
+ INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
+ assert(ID <= 3);
+ return fn.getRegisterIndex(src, ID);
+ }
+ INLINE Type getType(void) const { return this->type; }
+ Opcode opcode; //!< Opcode of the instruction
+ Type type; //!< Type of the instruction
+ RegisterIndex dst; //!< Dst is the register index
+ TupleIndex src; //!< 3 sources do not fit in 8 bytes -> use a tuple
+ };
+
+ class ALIGNED_INSTRUCTION ConvertInstruction
+ {
+ public:
+ ConvertInstruction(RegisterIndex dst,
+ RegisterIndex src,
+ Type dstType,
+ Type srcType)
+ {
+ this->opcode = OP_CVT;
+ this->dst = dst;
+ this->src = src;
+ this->dstType = dstType;
+ this->srcType = srcType;
+ }
+ INLINE Type getSrcType(void) const { return this->srcType; }
+ INLINE Type getDstType(void) const { return this->dstType; }
+ INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
+ assert(ID == 0);
+ return dst;
+ }
+ INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
+ assert(ID == 0);
+ return src;
+ }
+ Opcode opcode; //!< Opcode of the instruction
+ RegisterIndex dst; //!< Converted value
+ RegisterIndex src; //!< To convert
+ Type dstType; //!< Type to convert to
+ Type srcType; //!< Type to convert from
+ };
+
+ class ALIGNED_INSTRUCTION BranchInstruction
+ {
+ public:
+ INLINE BranchInstruction(LabelIndex labelIndex, RegisterIndex predicate)
+ {
+ this->opcode = OP_BRA;
+ this->predicate = predicate;
+ this->labelIndex = labelIndex;
+ this->hasPredicate = true;
+ }
+ INLINE BranchInstruction(LabelIndex labelIndex)
+ {
+ this->opcode = OP_BRA;
+ this->labelIndex = labelIndex;
+ this->hasPredicate = false;
+ }
+ INLINE bool isPredicated(void) const { return hasPredicate; }
+ Opcode opcode; //!< Opcode of the instruction
+ RegisterIndex predicate; //!< Predication means conditional branch
+ LabelIndex labelIndex; //!< Index of the label the branch targets
+ bool hasPredicate; //!< Is it predicated?
+ };
+
+ class ALIGNED_INSTRUCTION LoadInstruction
+ {
+ public:
+ LoadInstruction(Type type,
+ RegisterIndex offset,
+ TupleIndex values,
+ MemorySpace memSpace,
+ uint16 valueNum)
+ {
+ this->opcode = OP_STORE;
+ this->type = type;
+ this->offset = offset;
+ this->values = values;
+ this->memSpace = memSpace;
+ this->valueNum = valueNum;
+ }
+ INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
+ assert(ID == 0u);
+ return offset;
+ }
+ INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
+ assert(ID < valueNum);
+ return fn.getRegisterIndex(values, ID);
+ }
+ INLINE uint32 getValueNum(void) const { return valueNum; }
+ INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
+ Opcode opcode; //!< Opcode of the instruction
+ Type type; //!< Type to store
+ RegisterIndex offset; //!< First source is the offset where to store
+ TupleIndex values; //!< Values to load
+ MemorySpace memSpace; //!< Where to store
+ uint16 valueNum; //!< Number of values to store
+ };
+
+ class ALIGNED_INSTRUCTION StoreInstruction
+ {
+ public:
+ StoreInstruction(Type type,
+ RegisterIndex offset,
+ TupleIndex values,
+ MemorySpace memSpace,
+ uint16 valueNum)
+ {
+ this->opcode = OP_STORE;
+ this->type = type;
+ this->offset = offset;
+ this->values = values;
+ this->memSpace = memSpace;
+ this->valueNum = valueNum;
+ }
+ INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) {
+ assert(ID < valueNum + 1u); // offset + values to store
+ if (ID == 0u)
+ return offset;
+ else
+ return fn.getRegisterIndex(values, ID - 1);
+ }
+ INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) {
+ NOT_IMPLEMENTED;
+ return 0u;
+ }
+ INLINE uint32 getValueNum(void) const { return valueNum; }
+ INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
+ Opcode opcode; //!< Opcode of the instruction
+ Type type; //!< Type to store
+ RegisterIndex offset; //!< First source is the offset where to store
+ TupleIndex values; //!< Values to store
+ MemorySpace memSpace; //!< Where to store
+ uint16 valueNum; //!< Number of values to store
+ };
+
+ class ALIGNED_INSTRUCTION TextureInstruction
+ {
+ public:
+ INLINE TextureInstruction(void) { this->opcode = OP_TEX; }
+ Opcode opcode; //!< Opcode of the instruction
+ };
+
+ class ALIGNED_INSTRUCTION LoadImmInstruction
+ {
+ public:
+ INLINE LoadImmInstruction(ValueIndex valueIndex, Type type) {
+ this->opcode = OP_LOADI;
+ this->valueIndex = valueIndex;
+ this->type = type;
+ }
+ INLINE Type getType(void) const { return this->type; }
+ Opcode opcode; //!< Opcode of the instruction
+ ValueIndex valueIndex;//!< Index in the vector of immediates
+ Type type; //!< Type of the immediate
+ };
+
+ class ALIGNED_INSTRUCTION FenceInstruction
+ {
+ public:
+ INLINE FenceInstruction(MemorySpace memSpace) {
+ this->opcode = OP_FENCE;
+ this->memSpace = memSpace;
+ }
+ Opcode opcode; //!< Opcode of the instruction
+ MemorySpace memSpace; //!< The loads and stores to order
+ };
+
+ class ALIGNED_INSTRUCTION LabelInstruction
+ {
+ public:
+ INLINE LabelInstruction(LabelIndex labelIndex) {
+ this->opcode = OP_LABEL;
+ this->labelIndex = labelIndex;
+ }
+ Opcode opcode; //!< Opcode of the instruction
+ LabelIndex labelIndex; //!< Index of the label
+ };
} /* namespace internal */
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Implements the various instrospection functions
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename T, typename U> struct HelperIntrospection {
+ enum { value = 0 };
+ };
+ template <typename T> struct HelperIntrospection<T,T> {
+ enum { value = 1 };
+ };
+
+ Register Instruction::getDst(const Function &fn, uint32 ID) const {
+ return fn.getRegister(this->getDstIndex(fn, ID));
+ }
+ Register Instruction::getSrc(const Function &fn, uint32 ID) const {
+ return fn.getRegister(this->getSrcIndex(fn, ID));
+ }
+
+#define DECL_INSN(OPCODE, CLASS) \
+ case OP_##OPCODE: \
+ return HelperIntrospection<CLASS, RefClass>::value == 1;
+
+#define START_INTROSPECTION(CLASS) \
+ STATIC_ASSERT(sizeof(CLASS) == sizeof(Instruction));\
+ bool CLASS::isClassOf(const Instruction &insn) { \
+ const Opcode op = insn.getOpcode(); \
+ typedef CLASS RefClass; \
+ switch (op) {
+
+#define END_INTROSPECTION(CLASS) \
+ default: return false; \
+ }; \
+ } \
+ STATIC_ASSERT(offsetof(internal::CLASS, opcode) == 0);
+
+START_INTROSPECTION(UnaryInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(UnaryInstruction)
+
+START_INTROSPECTION(BinaryInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(BinaryInstruction)
+
+START_INTROSPECTION(TernaryInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(TernaryInstruction)
+
+START_INTROSPECTION(ConvertInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(ConvertInstruction)
+
+START_INTROSPECTION(BranchInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(BranchInstruction)
+
+START_INTROSPECTION(TextureInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(TextureInstruction)
+
+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(FenceInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(FenceInstruction)
+
+START_INTROSPECTION(LabelInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(LabelInstruction)
+
+#undef END_INTROSPECTION
+#undef START_INTROSPECTION
+#undef DECL_INSN
+#undef ALIGNED_INSTRUCTION
+
+#if 0
+ ///////////////////////////////////////////////////////////////////////////
+ // Implements the function dispatching from public to internal
+ ///////////////////////////////////////////////////////////////////////////
+#define DECL_INSN(OPCODE, CLASS) \
+ case OP_##OPCODE: return cast<CLASS>(this)->getSrcNum();
+
+ uint32 Instruction::getSrcNum(void) const {
+ const Opcode op = this->getOpcode();
+ switch (op) {
+ #include "ir_instruction.hxx"
+ };
+ return 0;
+ }
+#endif
} /* namespace gbe */
#include "sys/platform.hpp"
#include "ir_register.hpp"
+#include "ir_value.hpp"
+#include "ir_type.hpp"
namespace gbe
{
/*! All opcodes */
- enum {
+ enum Opcode : uint8 {
#define DECL_INSN(INSN, FAMILY) OP_##INSN,
#include "ir_instruction.hxx"
#undef DECL_INSN
- OP_INVALID
};
/*! Different memory spaces */
- enum {
- MEM_GLOBAL = 0, /*! Global memory (a la OCL) */
- MEM_LOCAL, /*! Local memory (thread group memory) */
- MEM_PRIVATE /*! Per thread private memory */
+ enum MemorySpace : uint8 {
+ MEM_GLOBAL = 0, //!< Global memory (a la OCL)
+ MEM_LOCAL, //!< Local memory (thread group memory)
+ MEM_PRIVATE //!< Per thread private memory
};
- /*! All types possibly supported by the instruction */
- enum {
- TYPE_S8 = 0, /*! signed 8 bits integer */
- TYPE_U8, /*! unsigned 8 bits integer */
- TYPE_S16, /*! signed 16 bits integer */
- TYPE_U16, /*! unsigned 16 bits integer */
- TYPE_S32, /*! signed 32 bits integer */
- TYPE_U32, /*! unsigned 32 bits integer */
- TYPE_S64, /*! signed 64 bits integer */
- TYPE_U64, /*! unsigned 64 bits integer */
- TYPE_FLOAT, /*! 32 bits floating point value */
- TYPE_DOUBLE /*! 64 bits floating point value */
- };
+ /*! A label is identified with an unsigned short */
+ typedef uint16 LabelIndex;
+
+ /*! A value is stored in a per-function vector. This is the index to it */
+ typedef uint16 ValueIndex;
/*! Function class contains the register file and the register tuple. Any
* information related to the registers may therefore require a function
{
public:
/*! Get the instruction opcode */
- INLINE uint32 getOpcode(void) const { return op; }
+ INLINE Opcode getOpcode(void) const { return opcode; }
/*! Get the number of sources for this instruction */
uint32 getSrcNum(void) const;
/*! Get the number of destination for this instruction */
uint32 getDstNum(void) const;
/*! Get the register index of the given source */
- uint32 getSrcIndex(const Function &fn, uint32 ID) const;
+ RegisterIndex getSrcIndex(const Function &fn, uint32 ID = 0u) const;
/*! Get the register index of the given destination */
- uint32 getDstIndex(const Function &fn, uint32 ID) const;
+ RegisterIndex getDstIndex(const Function &fn, uint32 ID = 0u) const;
/*! Get the register of the given source */
- Register getSrc(const Function &fn, uint32 ID) const;
+ Register getDst(const Function &fn, uint32 ID = 0u) const;
/*! Get the register of the given destination */
- Register getDst(const Function &fn, uint32 ID) const;
+ Register getSrc(const Function &fn, uint32 ID = 0u) const;
/*! Check that the instruction is well formed. Return true if well formed.
+ * j
* Otherwise, fill the string with a help message
*/
bool check(void) const;
/*! Indicates if the instruction belongs to instruction type T. Typically, T
* can be BinaryInstruction, UnaryInstruction, LoadInstruction and so on
*/
- template <typename T> bool isTypeOf(void) const;
+ template <typename T> INLINE bool isMemberOf(void) const {
+ return T::isClassOf(*this);
+ }
protected:
- uint8 op; //!< Idendifies the instruction
- uint8 opaque[sizeof(uint64)-sizeof(uint8)]; //!< Remainder of it
+ Opcode opcode; //!< Idendifies the instruction
+ uint8 opaque[sizeof(uint64)-sizeof(uint8)];//!< Remainder of it
};
// Check that the instruction is properly formed by the compiler
STATIC_ASSERT(sizeof(Instruction) == sizeof(uint64));
+ /*! 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
- {
+ class BinaryInstruction : public Instruction {
public:
/*! Get the type manipulated by the instruction */
- uint32 getType(void) const;
+ Type getType(void) const;
+ /*! Return true if the given instruction is an instance of this class */
+ static bool isClassOf(const Instruction &insn);
};
/*! Ternary instructions is mostly for MADs */
- class TernaryInstruction : public Instruction
- {
+ class TernaryInstruction : public Instruction {
public:
/*! Get the type manipulated by the instruction */
- uint32 getType(void) const;
+ Type getType(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
- {
+ class ConvertInstruction : public Instruction {
public:
/*! Get the type of the source */
- uint32 getSrcType(void) const;
+ Type getSrcType(void) const;
/*! Get the type of the destination */
- uint32 getDstType(void) const;
+ Type getDstType(void) const;
+ /*! 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
- {
+ class StoreInstruction : public Instruction {
public:
/*! Return the types of the values to store */
- uint32 getValueType(void) const;
+ Type getValueType(void) const;
/*! Give the number of values the instruction is storing (srcNum-1) */
uint32 getValueNum(void) const;
/*! Address space that is manipulated here */
- uint32 getAddressSpace(void) const;
+ MemorySpace getAddressSpace(void) const;
+ /*! 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
- {
+ class LoadInstruction : public Instruction {
public:
/*! Type of the loaded values (ie type of all the destinations) */
- uint32 getValueType(void) const;
+ Type getValueType(void) const;
/*! Number of values loaded (ie number of destinations) */
uint32 getValueNum(void) const;
/*! Address space that is manipulated here */
- uint32 getAddressSpace(void) const;
+ MemorySpace getAddressSpace(void) const;
+ /*! 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
* the immediate themselves are stored in the function core. Contrary to
* regular load instructions, there is only one destination possible
*/
- class LoadImmInstruction : public Instruction
- {
- /*! The value as stored in the instruction */
- union Value {
- int8 s8;
- uint8 u8;
- int16 i16;
- uint16 u16;
- int32 i32;
- uint32 u32;
- int64 i64;
- uint64 u64;
- float f32;
- double f64;
- };
+ class LoadImmInstruction : public Instruction {
/*! Return the value stored in the instruction */
Value getValue(void) const;
/*! Return the type of the stored value */
- uint32 getType(void) const;
+ Type getType(void) const;
+ /*! Return true if the given instruction is an instance of this class */
+ static bool isClassOf(const Instruction &insn);
};
- /*! Prevents all cast to non-instruction types */
- template <typename T> INLINE bool Instruction::isTypeOf(void) const {
- return false;
- }
+ /*! 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;
+ /*! Return the predicate register (if predicated) */
+ Register getPredicate(const Function &fn) const {
+ assert(this->isPredicated() == true);
+ return this->getSrc(fn, 0);
+ }
+ /*! Return the predicate register index (if predicated) */
+ Register getPredicateIndex(const Function &fn) const {
+ assert(this->isPredicated() == true);
+ return this->getSrcIndex(fn, 0);
+ }
+ /*! 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 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);
+ };
+
+ /*! Fence instructions are used to order loads and stores for a given memory
+ * space
+ */
+ class FenceInstruction : public Instruction {
+ public:
+ /*! 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 <typename T>
- T *cast(Instruction *insn)
- {
-
+ INLINE T *cast(Instruction *insn) {
+ assert(insn->isMemberOf<T>() == true);
+ return reinterpret_cast<T*>(insn);
+ }
+ template <typename T>
+ INLINE const T *cast(const Instruction *insn) {
+ assert(insn->isMemberOf<T>() == true);
+ return reinterpret_cast<const T*>(insn);
+ }
+ template <typename T>
+ INLINE T &cast(Instruction &insn) {
+ assert(insn.isMemberOf<T>() == true);
+ return reinterpret_cast<T&>(insn);
+ }
+ template <typename T>
+ INLINE const T &castc(const Instruction &insn) {
+ assert(insn.isMemberOf<T>() == true);
+ return reinterpret_cast<const T&>(insn);
}
} /* namespace gbe */
GBE_CLASS(Register);
};
+ /*! Register index is the position of the register in the register file */
+ typedef uint16 RegisterIndex;
+
+ /*! Tuple index is the position of the register index in the tuple vector */
+ typedef uint32 TupleIndex;
+
/*! A register file allocates and destroys registers. Basically, we will have
* one register file per function
*/
{
public:
/*! Return the index of a newly allocated register register */
- INLINE uint32 append(uint32 type) {
+ INLINE RegisterIndex append(uint32 type) {
const uint32 index = regs.size();
const Register reg(type);
assert(index <= MAX_INDEX);
regs.push_back(reg);
return index;
}
+ /*! Make a tuple and return the index to the first element of the tuple */
+ template <typename First, typename... Rest>
+ INLINE TupleIndex appendTuple(First first, Rest... rest) {
+ const TupleIndex index = regTuples.size();
+ regTuples.push_back(first);
+ appendTuple(rest...);
+ return index;
+ }
+ /*! To terminate variadic recursion */
+ INLINE void appendTuple(void) {}
/*! Return a copy of the register at index */
- INLINE Register get(uint32 index) const {
+ INLINE Register get(RegisterIndex index) const {
assert(index < regs.size() && index <= MAX_INDEX);
return regs[index];
}
+ /*! Get the register index from the tuple */
+ INLINE RegisterIndex get(TupleIndex index, uint32 which) const {
+ assert(index + which < regTuples.size());
+ return regTuples[index + which];
+ }
/*! Number of registers in the register file */
INLINE uint32 regNum(void) const { return regs.size(); }
private:
- enum { MAX_INDEX = 0xffff }; //!< We encode indices in 2 bytes
- vector<Register> regs; //!< All the registers together
+ enum { MAX_INDEX = 0xffff }; //!< We encode indices in 2 bytes
+ vector<Register> regs; //!< All the registers together
+ vector<RegisterIndex> regTuples; //!< Tuples are used for many src / dst
GBE_CLASS(RegisterFile);
};
} /* namespace gbe */
/*! Declare a structure with custom allocators */
-#define GBE_STRUCT(TYPE) \
+#define GBE_STRUCT(TYPE) \
void* operator new(size_t size) { \
if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \
- return gbe::alignedMalloc(size, AlignOf<TYPE>::value); \
+ return gbe::alignedMalloc(size, AlignOf<TYPE>::value); \
else \
- return gbe::malloc(size); \
+ return gbe::malloc(size); \
} \
void* operator new[](size_t size) { \
if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \
- return gbe::alignedMalloc(size, AlignOf<TYPE>::value); \
+ return gbe::alignedMalloc(size, AlignOf<TYPE>::value); \
else \
- return gbe::malloc(size); \
+ return gbe::malloc(size); \
} \
void operator delete(void* ptr) { \
if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \
- return gbe::alignedFree(ptr); \
+ return gbe::alignedFree(ptr); \
else \
- return gbe::free(ptr); \
+ return gbe::free(ptr); \
} \
void operator delete[](void* ptr) { \
if (AlignOf<TYPE>::value > sizeof(uintptr_t)) \
- return gbe::alignedFree(ptr); \
+ return gbe::alignedFree(ptr); \
else \
- return gbe::free(ptr); \
+ return gbe::free(ptr); \
} \
/*! Declare a class with custom allocators */
~GrowingPool(void) { GBE_ASSERT(current); GBE_DELETE(current); }
T *allocate(void) {
if (this->freeList != NULL) {
- T *data = freeList;
- this->freeList = *(void**) free;
+ T *data = (T*) freeList;
+ this->freeList = *(void**) freeList;
}
if (UNLIKELY(current->allocated == current->maxElemNum)) {
GrowingPoolElem *elem = GBE_NEW(GrowingPoolElem, 2 * current->maxElemNum);
#include <vector>
-namespace pf
+namespace gbe
{
/*! Quick and dirty Unit test system with registration */
struct UTest
/*! Run all the tests */
static void runAll(void);
};
-} /* namespace pf */
+} /* namespace gbe */
/*! Register a new unit test */
-#define UTEST_REGISTER(FN) static const pf::UTest __##NAME##__(FN, #FN);
+#define UTEST_REGISTER(FN) static const gbe::UTest __##NAME##__(FN, #FN);
#endif /* __GBE_UTEST_HPP__ */