set (VISIBILITY_FLAG "-fvisibility=hidden")
if (COMPILER STREQUAL "GCC")
- set (CMAKE_CXX_FLAGS "-Wstrict-aliasing=2 -Wno-invalid-offsetof -fno-strict-aliasing -msse2 -ffast-math -fPIC -Wall -fno-rtti -std=c++0x")
+ set (CMAKE_CXX_FLAGS "-Wstrict-aliasing=2 -Wno-invalid-offsetof -fstrict-aliasing -msse2 -ffast-math -fPIC -Wall -fno-rtti -std=c++0x")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_DEBUG_MEMORY_FLAG}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_COMPILE_UTESTS_FLAG}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG} -Wl,-E")
set (CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")
set (CMAKE_CXX_COMPILER "clang++")
- set (CMAKE_CXX_FLAGS "-fno-strict-aliasing -msse2 -ffast-math -fPIC -Wall -Wno-format-security -Wno-invalid-offsetof -std=c++0x")
+ set (CMAKE_CXX_FLAGS "-fstrict-aliasing -msse2 -ffast-math -fPIC -Wall -Wno-format-security -Wno-invalid-offsetof -std=c++0x")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_DEBUG_MEMORY_FLAG}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_COMPILE_UTESTS_FLAG}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG}")
elseif (COMPILER STREQUAL "ICC")
set (CMAKE_CXX_COMPILER "icpc")
set (CMAKE_C_COMPILER "icc")
- set (CMAKE_CXX_FLAGS "-std=c++0x -wd2928 -Wall -fPIC -fno-strict-aliasing -fp-model fast -xSSE2")
+ set (CMAKE_CXX_FLAGS "-std=c++0x -wd2928 -Wall -fPIC -fstrict-aliasing -fp-model fast -xSSE2")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_DEBUG_MEMORY_FLAG}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_COMPILE_UTESTS_FLAG}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG} -Wl,-E")
Context::Context(Unit &unit) : unit(unit), fn(NULL), bb(NULL) {}
void Context::startFunction(const std::string &name) {
- Function *fn = unit.newFunction(name);
+ if (fn != NULL) fnStack.push_back(fn);
+ fn = unit.newFunction(name);
+ }
+
+ void Context::endFunction(void) {
+ GBE_ASSERT(fn != NULL);
+ if (fnStack.size() != 0) {
+ fn = fnStack.back();
+ fnStack.pop_back();
+ } else
+ fn = NULL;
+ }
+
+ RegisterIndex Context::reg(Register::Family family) {
GBE_ASSERT(fn != NULL);
- fnStack.push_back(fn);
+ return fn->file.append(family);
+ }
+
+ void Context::input(RegisterIndex reg) {
+ GBE_ASSERT(fn != NULL && reg < fn->file.regNum());
+ fn->input.push_back(reg);
+ }
+
+ void Context::output(RegisterIndex reg) {
+ GBE_ASSERT(fn != NULL && reg < fn->file.regNum());
+ fn->output.push_back(reg);
}
} /* namespace ir */
#include "ir/function.hpp"
#include "ir/register.hpp"
#include "sys/vector.hpp"
+#include <tuple>
namespace gbe {
namespace ir {
void startFunction(const std::string &name);
/*! Close the function */
void endFunction(void);
- /*! Create a new register for the given type */
- RegisterIndex reg(Register::Family type);
+ /*! Create a new register for the given family */
+ RegisterIndex reg(Register::Family family);
/*! Append a new input register for the function */
void input(RegisterIndex reg);
/*! Append a new output register for the function */
void output(RegisterIndex reg);
/*! Append a new tuple */
+ template <typename... Args> INLINE TupleIndex tuple(Args...args);
+ /*! We just use variadic templates to forward instruction functions */
+#define DECL_INSN(NAME, FAMILY) \
+ template <typename... Args> INLINE void NAME(Args...args);
+#include "ir/instruction.hxx"
+#undef DECL_INSN
+
+ /*! MAD with sources directly specified */
+ INLINE void MAD(Type type,
+ RegisterIndex dst,
+ RegisterIndex src0,
+ RegisterIndex src1,
+ RegisterIndex src2)
+ {
+ const TupleIndex index = this->tuple(src0, src1, src2);
+ return this->MAD(type, dst, index);
+ }
+
+ /*! LOAD with the destinations directly specified */
+ template <typename... Args>
+ void LOAD(Type type, RegisterIndex offset, MemorySpace space, Args...values)
+ {
+ const TupleIndex index = this->tuple(values...);
+ const uint16_t valueNum = std::tuple_size<std::tuple<Args...>>::value;
+ GBE_ASSERT(valueNum > 0);
+ this->LOAD(type, index, offset, space, valueNum);
+ }
+
+ /*! STORE with the sources directly specified */
template <typename... Args>
- INLINE TupleIndex tuple(Args...args) {
- if (UNLIKELY(fn == NULL))
- throw std::exception("Tuple not defined in a function");
- fn->file.append(args...);
+ void STORE(Type type, RegisterIndex offset, MemorySpace space, Args...values)
+ {
+ const TupleIndex index = this->tuple(values...);
+ const uint16_t valueNum = std::tuple_size<std::tuple<Args...>>::value;
+ GBE_ASSERT(valueNum > 0);
+ this->STORE(type, index, offset, space, valueNum);
}
+
private:
+ /*! Check out-of-bound arguments */
+ template <typename T> void outOfBoundCheck(const T &t);
+ /*! Recurse on the arguments to check their correctness */
+ template <typename First, typename... Rest>
+ INLINE void argumentCheck(First first, Rest... rest);
+ /*! Stop the argument checking */
+ INLINE void argumentCheck(void);
+ /*! A block must be started with a label */
+ void startBlock(void);
+ /*! A block must be ended with a branch */
+ void endBlock(void);
+ /*! Append the instruction in the current basic block */
+ void append(const Instruction &insn);
Unit &unit; //!< A unit is associated to a contect
Function *fn; //!< Current function we are processing
Function::BasicBlock *bb; //!< Current basic block we are filling
vector<Function*> fnStack;//!< Stack of functions still to finish
};
+ template <typename... Args>
+ INLINE TupleIndex Context::tuple(Args...args) {
+ GBE_ASSERT(fn != NULL);
+ return fn->file.appendTuple(args...);
+ }
+
+ // Out-of-bound check for each function argument
+ template <typename T>
+ INLINE void Context::outOfBoundCheck(const T &t) { }
+ template <>
+ INLINE void Context::outOfBoundCheck<RegisterIndex>(const RegisterIndex &index) {
+ GBE_ASSERT(fn != NULL);
+ GBE_ASSERT(index < fn->regNum());
+ }
+ template <>
+ INLINE void Context::outOfBoundCheck<TupleIndex>(const TupleIndex &index) {
+ GBE_ASSERT(fn != NULL);
+ GBE_ASSERT(index < fn->tupleNum());
+ }
+
+ // Recursively check all the arguments
+ template <typename First, typename... Rest>
+ INLINE void Context::argumentCheck(First first, Rest... rest) {
+ this->outOfBoundCheck(first);
+ this->argumentCheck(rest...);
+ }
+ INLINE void Context::argumentCheck(void) {}
+
+ // Use argument checker to assert argument value correctness
+#define DECL_INSN(NAME, FAMILY) \
+ template <typename... Args> \
+ INLINE void Context::NAME(Args...args) { \
+ GBE_ASSERT(fn != NULL); \
+ this->argumentCheck(args...); \
+ const Instruction insn = gbe::ir::NAME(args...); \
+ this->append(insn); \
+ }
+#include "ir/instruction.hxx"
+#undef DECL_INSN
+
} /* namespace ir */
} /* namespace gbe */
}
/*! Get the given value ie immediate from the function */
INLINE Value getValue(uint32_t ID) const {
- assert(ID < value.size());
- return value[ID];
+ GBE_ASSERT(ID < values.size());
+ return values[ID];
}
+ /*! Number of registers in the register file */
+ INLINE uint32_t regNum(void) const { return file.regNum(); }
+ /*! Number of register tuples in the register file */
+ INLINE uint32_t tupleNum(void) const { return file.tupleNum(); }
+ /*! Number of labels in the function */
+ INLINE uint32_t labelNum(void) const { return labels.size(); }
+ /*! Number of immediate values in the function */
+ INLINE uint32_t valueNum(void) const { return values.size(); }
private:
friend class Context; //!< Can freely modify a function
vector<RegisterIndex> input; //!< Input registers of the function
vector<RegisterIndex> output; //!< Output registers of the function
vector<BasicBlock*> labels; //!< Each label points to a basic block
- vector<Value> value; //!< All immediate values stored in the function
+ vector<Value> values; //!< All immediate values stored in the function
vector<BasicBlock*> bb; //!< All the basic blocks one after the others
RegisterFile file; //!< All the registers used in the instructions
};
/**
* \file instruction.cpp
- *
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
#include "ir/instruction.hpp"
}
};
+ /*! Policy shared by all the internal instructions */
+ struct ALIGNED_INSTRUCTION BasePolicy {
+ /*! Create an instruction from its internal representation */
+ Instruction convert(void) const {
+ return Instruction(reinterpret_cast<const char *>(&this->opcode));
+ }
+ /*! Instruction opcode */
+ Opcode opcode;
+ };
+
/*! All unary and binary arithmetic instructions */
template <uint32_t srcNum> // 1 or 2
- class ALIGNED_INSTRUCTION NaryInstruction {
+ class NaryInstruction : public BasePolicy
+ {
public:
INLINE uint32_t getSrcNum(void) const { return srcNum; }
INLINE uint32_t getDstNum(void) const { return 1; }
return src[ID];
}
INLINE Type getType(void) const { return this->type; }
- Opcode opcode; //!< Instruction opcode
Type type; //!< Type of the instruction
RegisterIndex dst; //!< Index of the register in the register file
RegisterIndex src[srcNum];//!< Indices of the sources
};
/*! All 1-source arithmetic instructions */
- class ALIGNED_INSTRUCTION UnaryInstruction : public NaryInstruction<1> {
+ class UnaryInstruction : public NaryInstruction<1>
+ {
public:
UnaryInstruction(Opcode opcode,
Type type,
};
/*! All 2-source arithmetic instructions */
- class ALIGNED_INSTRUCTION BinaryInstruction : public NaryInstruction<2> {
+ class BinaryInstruction : public NaryInstruction<2>
+ {
public:
BinaryInstruction(Opcode opcode,
Type type,
/*! This is for MADs mostly. Since three sources cannot be encoded in 64
* bytes, we use tuples of registers
*/
- class ALIGNED_INSTRUCTION TernaryInstruction {
+ class TernaryInstruction : public BasePolicy
+ {
public:
TernaryInstruction(Opcode opcode,
Type type,
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 {
+ class ConvertInstruction : public BasePolicy
+ {
public:
ConvertInstruction(Type dstType,
Type srcType,
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 NoDstPolicy {
+ class BranchInstruction : public BasePolicy, public NoDstPolicy
+ {
public:
INLINE BranchInstruction(LabelIndex labelIndex, RegisterIndex predicate) {
this->opcode = OP_BRA;
return predicate;
}
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 {
+ class LoadInstruction : public BasePolicy
+ {
public:
LoadInstruction(Type type,
TupleIndex dstValues,
INLINE Type getValueType(void) const { return type; }
INLINE uint32_t getValueNum(void) const { return valueNum; }
INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
- Opcode opcode; //!< Opcode of the instruction
+ INLINE bool wellFormed(const Function &fn, std::string &why) const;
Type type; //!< Type to store
RegisterIndex offset; //!< First source is the offset where to store
TupleIndex values; //!< Values to load
uint16_t valueNum; //!< Number of values to store
};
- class ALIGNED_INSTRUCTION StoreInstruction : public NoDstPolicy {
+ class StoreInstruction : public BasePolicy, public NoDstPolicy
+ {
public:
StoreInstruction(Type type,
RegisterIndex offset,
return fn.getRegisterIndex(values, ID - 1);
}
INLINE uint32_t getSrcNum(void) const { return valueNum + 1u; }
- INLINE Type getValueType(void) const { return type; }
INLINE uint32_t getValueNum(void) const { return valueNum; }
+ INLINE Type getValueType(void) const { return type; }
INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
- Opcode opcode; //!< Opcode of the instruction
+ INLINE bool wellFormed(const Function &fn, std::string &why) const;
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_t valueNum; //!< Number of values to store
+ uint16_t valueNum; //!< Number of values to store
};
- class ALIGNED_INSTRUCTION TextureInstruction :
- public NoDstPolicy, public NoSrcPolicy // TODO REMOVE THIS
+ class TextureInstruction : public BasePolicy, public NoDstPolicy, public NoSrcPolicy // TODO REMOVE THIS
{
public:
INLINE TextureInstruction(void) { this->opcode = OP_TEX; }
- Opcode opcode; //!< Opcode of the instruction
};
- class ALIGNED_INSTRUCTION LoadImmInstruction : public NoSrcPolicy {
+ class LoadImmInstruction : public BasePolicy, public NoSrcPolicy
+ {
public:
INLINE LoadImmInstruction(Type type, RegisterIndex dst, ValueIndex valueIndex) {
this->dst = dst;
return dst;
}
INLINE Type getType(void) const { return this->type; }
- Opcode opcode; //!< Opcode of the instruction
+ bool wellFormed(const Function &fn, std::string &why) const;
RegisterIndex dst; //!< Register to store into
ValueIndex valueIndex;//!< Index in the vector of immediates
Type type; //!< Type of the immediate
};
- class ALIGNED_INSTRUCTION FenceInstruction :
- public NoSrcPolicy, public NoDstPolicy
+ class FenceInstruction : public BasePolicy, public NoSrcPolicy, public NoDstPolicy
{
public:
INLINE FenceInstruction(MemorySpace memSpace) {
this->opcode = OP_FENCE;
this->memSpace = memSpace;
}
- Opcode opcode; //!< Opcode of the instruction
+ bool wellFormed(const Function &fn, std::string &why) const;
MemorySpace memSpace; //!< The loads and stores to order
};
- class ALIGNED_INSTRUCTION LabelInstruction :
- public NoDstPolicy, public NoSrcPolicy
+ class LabelInstruction : public BasePolicy, public NoDstPolicy, public NoSrcPolicy
{
public:
INLINE LabelInstruction(LabelIndex labelIndex) {
this->opcode = OP_LABEL;
this->labelIndex = labelIndex;
}
- Opcode opcode; //!< Opcode of the instruction
+ INLINE bool wellFormed(const Function &fn, std::string &why) const;
LabelIndex labelIndex; //!< Index of the label
};
#undef ALIGNED_INSTRUCTION
+
+ /////////////////////////////////////////////////////////////////////////
+ // Implements all the wellFormed methods
+ /////////////////////////////////////////////////////////////////////////
+
+ /*! Loads and stores follow the same restrictions */
+ template <typename T>
+ INLINE bool wellFormedLoadStore(const T &insn, const Function &fn, std::string &why) {
+ if (UNLIKELY(insn.offset >= fn.regNum())) {
+ why = "Out-of-bound offset register index";
+ return false;
+ } else if (UNLIKELY(insn.values + insn.valueNum > fn.tupleNum())) {
+ why = "Out-of-bound tuple index";
+ return false;
+ }
+ // Check that all the registers have the same size
+ const Register::Family family = getFamily(insn.type);
+ for (uint32_t regID = 0; regID < insn.valueNum; ++regID) {
+ const RegisterIndex index = fn.getRegisterIndex(insn.values, regID);
+ if (index > fn.regNum()) {
+ why = "Out-of-bound register index";
+ return false;
+ } else {
+ const Register reg = fn.getRegister(regID);
+ if (reg.family != family) {
+ why = "Register family does match instruction type";
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ INLINE bool LoadInstruction::wellFormed(const Function &fn, std::string &why) const {
+ return wellFormedLoadStore(*this, fn, why);
+ }
+ INLINE bool StoreInstruction::wellFormed(const Function &fn, std::string &why) const {
+ return wellFormedLoadStore(*this, fn, why);
+ }
+
+ INLINE bool LoadImmInstruction::wellFormed(const Function &fn, std::string &why) const {
+ if (UNLIKELY(dst >= fn.regNum())) {
+ why = "Out-of-bound register index";
+ return false;
+ } else if (UNLIKELY(valueIndex >= fn.valueNum())) {
+ why = "Out-of-bound immediate value index";
+ return false;
+ } else if (UNLIKELY(type != fn.getValue(valueIndex).type)) {
+ why = "Inconsistant type for the immediate value to load";
+ return false;
+ } else
+ return true;
+ }
+
+ INLINE bool FenceInstruction::wellFormed(const Function &fn, std::string &why) const {
+ return true;
+ }
+
+
+ INLINE bool LabelInstruction::wellFormed(const Function &fn, std::string &why) const {
+ if (UNLIKELY(labelIndex >= fn.labelNum())) {
+ why = "Out-of-bound label index";
+ return false;
+ } else
+ return true;
+ }
+
} /* namespace internal */
///////////////////////////////////////////////////////////////////////////
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; \
+#define START_INTROSPECTION(CLASS) \
+ static_assert(sizeof(CLASS)==sizeof(Instruction), "Bad instruction size"); \
+ 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);
+#define END_INTROSPECTION(CLASS) \
+ default: return false; \
+ }; \
+ } \
+ static_assert(offsetof(internal::CLASS, opcode)==0, "Bad opcode offset");
START_INTROSPECTION(UnaryInstruction)
#include "ir/instruction.hxx"
///////////////////////////////////////////////////////////////////////////
// All unary functions
-#define DECL_EMIT_FUNCTION(NAME, OPCODE)\
- Instruction NAME(Type type, RegisterIndex dst, RegisterIndex src) {\
- internal::UnaryInstruction insn(OPCODE, type, dst, src);\
- return *reinterpret_cast<Instruction*>(&insn);\
+#define DECL_EMIT_FUNCTION(NAME) \
+ Instruction NAME(Type type, RegisterIndex dst, RegisterIndex src) { \
+ const internal::UnaryInstruction insn(OP_##NAME, type, dst, src); \
+ return insn.convert(); \
}
- DECL_EMIT_FUNCTION(mov, OP_MOV)
- DECL_EMIT_FUNCTION(cos, OP_COS)
- DECL_EMIT_FUNCTION(sin, OP_SIN)
- DECL_EMIT_FUNCTION(tan, OP_TAN)
- DECL_EMIT_FUNCTION(log, OP_LOG)
- DECL_EMIT_FUNCTION(sqr, OP_SQR)
- DECL_EMIT_FUNCTION(rsq, OP_RSQ)
+ DECL_EMIT_FUNCTION(MOV)
+ DECL_EMIT_FUNCTION(COS)
+ DECL_EMIT_FUNCTION(SIN)
+ DECL_EMIT_FUNCTION(TAN)
+ DECL_EMIT_FUNCTION(LOG)
+ DECL_EMIT_FUNCTION(SQR)
+ DECL_EMIT_FUNCTION(RSQ)
#undef DECL_EMIT_FUNCTION
// All binary functions
-#define DECL_EMIT_FUNCTION(NAME, OPCODE)\
- Instruction NAME(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1) {\
- internal::BinaryInstruction insn(OPCODE, type, dst, src0, src1);\
- return *reinterpret_cast<Instruction*>(&insn);\
+#define DECL_EMIT_FUNCTION(NAME) \
+ Instruction NAME(Type type, RegisterIndex dst, \
+ RegisterIndex src0, \
+ RegisterIndex src1) { \
+ const internal::BinaryInstruction insn(OP_##NAME, type, dst, src0, src1); \
+ return insn.convert(); \
}
- DECL_EMIT_FUNCTION(mul, OP_MUL)
- DECL_EMIT_FUNCTION(add, OP_ADD)
- DECL_EMIT_FUNCTION(sub, OP_SUB)
- DECL_EMIT_FUNCTION(div, OP_DIV)
- DECL_EMIT_FUNCTION(rem, OP_REM)
- DECL_EMIT_FUNCTION(shl, OP_SHL)
- DECL_EMIT_FUNCTION(shr, OP_SHR)
- DECL_EMIT_FUNCTION(asr, OP_ASR)
- DECL_EMIT_FUNCTION(bsf, OP_BSF)
- DECL_EMIT_FUNCTION(bsb, OP_BSB)
- DECL_EMIT_FUNCTION(or$, OP_OR)
- DECL_EMIT_FUNCTION(xor$, OP_XOR)
- DECL_EMIT_FUNCTION(and$, OP_AND)
+ DECL_EMIT_FUNCTION(MUL)
+ DECL_EMIT_FUNCTION(ADD)
+ DECL_EMIT_FUNCTION(SUB)
+ 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)
#undef DECL_EMIT_FUNCTION
// MAD
- Instruction mad(Type type, RegisterIndex dst, TupleIndex src) {
+ Instruction MAD(Type type, RegisterIndex dst, TupleIndex src) {
internal::TernaryInstruction insn(OP_MAD, type, dst, src);
- return *reinterpret_cast<Instruction*>(&insn);
+ return insn.convert();
}
// CVT
- Instruction cvt(Type dstType, Type srcType, RegisterIndex dst, TupleIndex src) {
+ Instruction CVT(Type dstType, Type srcType, RegisterIndex dst, TupleIndex src) {
internal::ConvertInstruction insn(dstType, srcType, dst, src);
- return *reinterpret_cast<Instruction*>(&insn);
+ return insn.convert();
}
// BRA
- Instruction bra(LabelIndex labelIndex) {
+ Instruction BRA(LabelIndex labelIndex) {
internal::BranchInstruction insn(labelIndex);
- return *reinterpret_cast<Instruction*>(&insn);
+ return insn.convert();
}
- Instruction bra(LabelIndex labelIndex, RegisterIndex pred) {
+ Instruction BRA(LabelIndex labelIndex, RegisterIndex pred) {
internal::BranchInstruction insn(labelIndex, pred);
- return *reinterpret_cast<Instruction*>(&insn);
+ return insn.convert();
}
// LOADI
- Instruction loadi(Type type, RegisterIndex dst, ValueIndex value) {
+ Instruction LOADI(Type type, RegisterIndex dst, ValueIndex value) {
internal::LoadImmInstruction insn(type, dst, value);
- return *reinterpret_cast<Instruction*>(&insn);
+ return insn.convert();
}
// LOAD and STORE
-#define DECL_EMIT_FUNCTION(NAME, CLASS) \
- Instruction NAME(Type type, \
- TupleIndex tuple, \
- RegisterIndex offset, \
- MemorySpace space, \
- uint16_t valueNum) \
- { \
+#define DECL_EMIT_FUNCTION(NAME, CLASS) \
+ Instruction NAME(Type type, \
+ TupleIndex tuple, \
+ RegisterIndex offset, \
+ MemorySpace space, \
+ uint16_t valueNum) \
+ { \
const internal::CLASS insn(type, tuple, offset, space, valueNum); \
- return *reinterpret_cast<const Instruction*>(&insn); \
+ return insn.convert(); \
}
- DECL_EMIT_FUNCTION(load, LoadInstruction)
- DECL_EMIT_FUNCTION(store, StoreInstruction)
+ DECL_EMIT_FUNCTION(LOAD, LoadInstruction)
+ DECL_EMIT_FUNCTION(STORE, StoreInstruction)
#undef DECL_EMIT_FUNCTION
// FENCE
- Instruction fence(MemorySpace space) {
- internal::FenceInstruction insn(space);
- return *reinterpret_cast<Instruction*>(&insn);
+ Instruction FENCE(MemorySpace space) {
+ const internal::FenceInstruction insn(space);
+ return insn.convert();
}
// LABEL
- Instruction label(LabelIndex labelIndex) {
- internal::LabelInstruction insn(labelIndex);
- return *reinterpret_cast<Instruction*>(&insn);
+ Instruction LABEL(LabelIndex labelIndex) {
+ const internal::LabelInstruction insn(labelIndex);
+ return insn.convert();
}
} /* namespace ir */
#ifndef __GBE_IR_INSTRUCTION_HPP__
#define __GBE_IR_INSTRUCTION_HPP__
-#include "sys/platform.hpp"
#include "ir/register.hpp"
#include "ir/value.hpp"
#include "ir/type.hpp"
+#include "sys/platform.hpp"
namespace gbe {
namespace ir {
/*! All opcodes */
- enum Opcode : uint8_t {
+ enum Opcode : char {
#define DECL_INSN(INSN, FAMILY) OP_##INSN,
#include "ir/instruction.hxx"
#undef DECL_INSN
class ALIGNED(sizeof(uint64_t)) Instruction
{
public:
+ /*! Initialize the instruction from a 8 bytes stream */
+ INLINE Instruction(const char *stream) {
+ opcode = Opcode(stream[0]);
+ for (uint32_t byte = 0; byte < opaqueSize; ++byte)
+ opaque[byte] = stream[byte+1];
+ }
+ /*! Uninitialize instruction */
+ INLINE Instruction(void) {}
/*! Get the instruction opcode */
INLINE Opcode getOpcode(void) const { return opcode; }
/*! Get the number of sources for this instruction */
Register getDst(const Function &fn, uint32_t ID = 0u) const;
/*! Get the register of the given destination */
Register getSrc(const Function &fn, uint32_t ID = 0u) const;
- /*! Check that the instruction is well formed. Return true if well formed.
- * j
- * Otherwise, fill the string with a help message
+ /*! 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 check(void) const;
+ bool wellFormed(const Function &fn, std::string &why) const;
/*! Indicates if the instruction belongs to instruction type T. Typically, T
* can be BinaryInstruction, UnaryInstruction, LoadInstruction and so on
*/
return T::isClassOf(*this);
}
protected:
- Opcode opcode; //!< Idendifies the instruction
- uint8_t opaque[sizeof(uint64_t)-sizeof(uint8_t)];//!< Remainder of it
+ enum { opaqueSize = sizeof(uint64_t)-sizeof(uint8_t) };
+ Opcode opcode; //!< Idendifies the instruction
+ char opaque[opaqueSize]; //!< Remainder of it
};
// Check that the instruction is properly formed by the compiler
- STATIC_ASSERT(sizeof(Instruction) == sizeof(uint64_t));
+ static_assert(sizeof(Instruction)==sizeof(uint64_t), "Bad instruction size");
/*! Unary instructions are typed. dst and sources share the same type */
class UnaryInstruction : public Instruction {
///////////////////////////////////////////////////////////////////////////
/*! mov.type dst src */
- Instruction mov(Type type, RegisterIndex dst, RegisterIndex src);
+ Instruction MOV(Type type, RegisterIndex dst, RegisterIndex src);
/*! cos.type dst src */
- Instruction cos(Type type, RegisterIndex dst, RegisterIndex src);
+ Instruction COS(Type type, RegisterIndex dst, RegisterIndex src);
/*! sin.type dst src */
- Instruction sin(Type type, RegisterIndex dst, RegisterIndex src);
+ Instruction SIN(Type type, RegisterIndex dst, RegisterIndex src);
/*! tan.type dst src */
- Instruction tan(Type type, RegisterIndex dst, RegisterIndex src);
+ Instruction TAN(Type type, RegisterIndex dst, RegisterIndex src);
/*! log.type dst src */
- Instruction log(Type type, RegisterIndex dst, RegisterIndex src);
+ Instruction LOG(Type type, RegisterIndex dst, RegisterIndex src);
/*! sqr.type dst src */
- Instruction sqr(Type type, RegisterIndex dst, RegisterIndex src);
+ Instruction SQR(Type type, RegisterIndex dst, RegisterIndex src);
/*! rsq.type dst src */
- Instruction rsq(Type type, RegisterIndex dst, RegisterIndex src);
+ Instruction RSQ(Type type, RegisterIndex dst, RegisterIndex src);
/*! pow.type dst src0 src1 */
- Instruction pow(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction POW(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! mul.type dst src0 src1 */
- Instruction mul(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction MUL(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! add.type dst src0 src1 */
- Instruction add(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction ADD(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! sub.type dst src0 src1 */
- Instruction sub(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction SUB(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! div.type dst src0 src1 */
- Instruction div(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction DIV(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! rem.type dst src0 src1 */
- Instruction rem(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction REM(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! shl.type dst src0 src1 */
- Instruction shl(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction SHL(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! shr.type dst src0 src1 */
- Instruction shr(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction SHR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! asr.type dst src0 src1 */
- Instruction asr(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction ASR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! bsf.type dst src0 src1 */
- Instruction bsf(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction BSF(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! bsb.type dst src0 src1 */
- Instruction bsb(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction BSB(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! or.type dst src0 src1 */
- Instruction or$(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction OR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! xor.type dst src0 src1 */
- Instruction xor$(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction XOR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! and.type dst src0 src1 */
- Instruction and$(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction AND(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! mad.type dst {src0, src1, src2} == src */
- Instruction mad(Type type, RegisterIndex dst, TupleIndex src);
+ Instruction MAD(Type type, RegisterIndex dst, TupleIndex src);
/*! cvt.{dstType <- srcType} dst src */
- Instruction cvt(Type dstType, Type srcType, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+ Instruction CVT(Type dstType, Type srcType, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
/*! bra labelIndex */
- Instruction bra(LabelIndex labelIndex);
+ Instruction BRA(LabelIndex labelIndex);
/*! (pred) bra labelIndex */
- Instruction bra(LabelIndex labelIndex, RegisterIndex pred);
+ Instruction BRA(LabelIndex labelIndex, RegisterIndex pred);
/*! loadi.type dst value */
- Instruction loadi(Type type, RegisterIndex dst, ValueIndex value);
+ Instruction LOADI(Type type, RegisterIndex dst, ValueIndex value);
/*! load.type.space {dst1,...,dst_valueNum} offset value */
- Instruction load(Type type, TupleIndex dst, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
+ Instruction LOAD(Type type, TupleIndex dst, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
/*! store.type.space offset {src1,...,src_valueNum} value */
- Instruction store(Type type, TupleIndex src, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
+ Instruction STORE(Type type, TupleIndex src, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
/*! fence.space */
- Instruction fence(MemorySpace space);
+ Instruction FENCE(MemorySpace space);
/*! label labelIndex */
- Instruction label(LabelIndex labelIndex);
+ Instruction LABEL(LabelIndex labelIndex);
+ /*! texture instruction TODO */
+ Instruction TEX(void);
} /* namespace ir */
} /* namespace gbe */
public:
/*! Return the index of a newly allocated register register */
INLINE RegisterIndex append(Register::Family family) {
- const uint32_t index = regs.size();
+ const uint32_t index = regNum();
const Register reg(family);
- assert(index <= MAX_INDEX);
+ GBE_ASSERT(index <= MAX_INDEX);
regs.push_back(reg);
return index;
}
template <typename First, typename... Rest>
INLINE TupleIndex appendTuple(First first, Rest... rest) {
const TupleIndex index = regTuples.size();
- assert(first < regs.size());
+ GBE_ASSERT(first < regNum());
regTuples.push_back(first);
appendTuple(rest...);
return index;
INLINE void appendTuple(void) {}
/*! Return a copy of the register at index */
INLINE Register get(RegisterIndex index) const {
- assert(index < regs.size() && index <= MAX_INDEX);
+ GBE_ASSERT(index < regNum());
return regs[index];
}
/*! Get the register index from the tuple */
INLINE RegisterIndex get(TupleIndex index, uint32_t which) const {
- assert(index + which < regTuples.size());
+ GBE_ASSERT(index + which < regTuples.size());
return regTuples[index + which];
}
/*! Number of registers in the register file */
INLINE uint32_t regNum(void) const { return regs.size(); }
+ /*! Number of tuples in the register file */
+ INLINE uint32_t tupleNum(void) const { return regTuples.size(); }
private:
- 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);
#define __GBE_IR_TYPE_HPP__
#include "sys/platform.hpp"
+#include "ir/register.hpp"
namespace gbe {
namespace ir {
/*! All types possibly supported by the instruction */
enum Type : uint8_t {
- 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
+ TYPE_BOOL = 0, //!< boolean value
+ TYPE_S8, //!< 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_HALF, //!< 16 bits floating point value
+ TYPE_FLOAT, //!< 32 bits floating point value
+ TYPE_DOUBLE //!< 64 bits floating point value
};
+ /*! Get the register family for each type */
+ INLINE Register::Family getFamily(Type type) {
+ switch (type) {
+ case TYPE_BOOL:
+ return Register::BOOL;
+ case TYPE_S8:
+ case TYPE_U8:
+ return Register::BYTE;
+ case TYPE_S16:
+ case TYPE_U16:
+ case TYPE_HALF:
+ return Register::WORD;
+ case TYPE_S32:
+ case TYPE_U32:
+ case TYPE_FLOAT:
+ return Register::DWORD;
+ case TYPE_S64:
+ case TYPE_U64:
+ case TYPE_DOUBLE:
+ return Register::QWORD;
+ };
+ }
+
} /* namespace ir */
} /* namespace gbe */
#define GBE_ASSERT(EXPR) do { } while (0)
#endif
-/*! Compile-time assertion */
-#define STATIC_ASSERT(value) \
- struct JOIN(__,JOIN(__,__LINE__)) { int x[(value) ? 1 : -1]; }
-
/*! Fatal error macros */
#define NOT_IMPLEMENTED FATAL ("Not implemented")
#define FATAL_IF(COND, MSG) \