From: Benjamin Segovia Date: Thu, 16 Feb 2012 11:34:31 +0000 (+0000) Subject: Added compare instructions Finished to implement well formed functions. They basicall... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=78c71dceaa3d9261876949244b22e9d3c4cebd1e;p=contrib%2Fbeignet.git Added compare instructions Finished to implement well formed functions. They basically check that the definition is consistent (types match, registers and tuple are not out-of-bound the register files or the tuple files...) --- diff --git a/backend/src/ir/context.hpp b/backend/src/ir/context.hpp index 07e7b4e..afdee73 100644 --- a/backend/src/ir/context.hpp +++ b/backend/src/ir/context.hpp @@ -120,34 +120,11 @@ namespace ir { return fn->file.appendTuple(args...); } - // Out-of-bound check for each function argument - template - INLINE void Context::outOfBoundCheck(const T &t) { } - template <> - INLINE void Context::outOfBoundCheck(const RegisterIndex &index) { - GBE_ASSERT(fn != NULL); - GBE_ASSERT(index < fn->regNum()); - } - template <> - INLINE void Context::outOfBoundCheck(const TupleIndex &index) { - GBE_ASSERT(fn != NULL); - GBE_ASSERT(index < fn->tupleNum()); - } - - // Recursively check all the arguments - template - 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 \ INLINE void Context::NAME(Args...args) { \ GBE_ASSERT(fn != NULL); \ - this->argumentCheck(args...); \ const Instruction insn = gbe::ir::NAME(args...); \ this->append(insn); \ } diff --git a/backend/src/ir/instruction.cpp b/backend/src/ir/instruction.cpp index dbbdda0..1ccc47a 100644 --- a/backend/src/ir/instruction.cpp +++ b/backend/src/ir/instruction.cpp @@ -79,6 +79,7 @@ namespace ir { return src[ID]; } INLINE Type getType(void) const { return this->type; } + INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; Type type; //!< Type of the instruction RegisterIndex dst; //!< Index of the register in the register file RegisterIndex src[srcNum];//!< Indices of the sources @@ -143,11 +144,33 @@ namespace ir { return fn.getRegisterIndex(src, ID); } INLINE Type getType(void) const { return this->type; } + INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; 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 }; + /*! 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 CompareInstruction : public BinaryInstruction + { + public: + CompareInstruction(Type type, + CompareOperation operation, + RegisterIndex dst, + RegisterIndex src0, + RegisterIndex src1) : + BinaryInstruction(OP_CMP, type, dst, src0, src1) + { + this->operation = operation; + } + INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; + CompareOperation operation; + }; + class ConvertInstruction : public BasePolicy { public: @@ -174,6 +197,7 @@ namespace ir { assert(ID == 0); return src; } + INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; RegisterIndex dst; //!< Converted value RegisterIndex src; //!< To convert Type dstType; //!< Type to convert to @@ -200,6 +224,7 @@ namespace ir { return predicate; } INLINE bool isPredicated(void) const { return hasPredicate; } + INLINE bool wellFormed(const Function &fn, std::string &why) const; RegisterIndex predicate; //!< Predication means conditional branch LabelIndex labelIndex; //!< Index of the label the branch targets bool hasPredicate; //!< Is it predicated? @@ -281,6 +306,7 @@ namespace ir { { public: INLINE TextureInstruction(void) { this->opcode = OP_TEX; } + INLINE bool wellFormed(const Function &fn, std::string &why) const; }; class LoadImmInstruction : public BasePolicy, public NoSrcPolicy @@ -335,65 +361,164 @@ namespace ir { // Implements all the wellFormed methods ///////////////////////////////////////////////////////////////////////// + /*! All Nary instruction register must be of the same family and properly + * defined (i.e. not out-of-bound) + */ + static INLINE bool checkRegister(Register::Family family, + const RegisterIndex ID, + const Function &fn, + std::string &whyNot) + { + if (UNLIKELY(ID >= fn.regNum())) { + whyNot = "Out-of-bound destination register index"; + return false; + } + const Register reg = fn.getRegister(ID); + if (UNLIKELY(reg.family != family)) { + whyNot = "Destination family does not match instruction type"; + return false; + } + return true; + } + + // Unary and binary instructions share the same rules + template + INLINE bool NaryInstruction::wellFormed(const Function &fn, std::string &whyNot) const + { + const Register::Family family = getFamily(this->type); + if (UNLIKELY(checkRegister(family, dst, fn, whyNot) == false)) + return false; + for (uint32_t srcID = 0; srcID < srcNum; ++srcID) + if (UNLIKELY(checkRegister(family, src[srcID], fn, whyNot) == false)) + return false; + return true; + } + + // Idem for ternary instructions except that sources are in a tuple + INLINE bool TernaryInstruction::wellFormed(const Function &fn, std::string &whyNot) const + { + const Register::Family family = getFamily(this->type); + if (UNLIKELY(checkRegister(family, dst, 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 < 3u; ++srcID) { + const RegisterIndex regID = fn.getRegisterIndex(src, srcID); + if (UNLIKELY(checkRegister(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(checkRegister(Register::BOOL, dst, fn, whyNot) == false)) + return false; + const Register::Family family = getFamily(this->type); + for (uint32_t srcID = 0; srcID < 2; ++srcID) + if (UNLIKELY(checkRegister(family, src[srcID], fn, whyNot) == false)) + 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 Register::Family dstFamily = getFamily(srcType); + const Register::Family srcFamily = getFamily(srcType); + if (UNLIKELY(checkRegister(dstFamily, dst, fn, whyNot) == false)) + return false; + if (UNLIKELY(checkRegister(srcFamily, src, 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 &why) { + INLINE bool wellFormedLoadStore(const T &insn, const Function &fn, std::string &whyNot) + { if (UNLIKELY(insn.offset >= fn.regNum())) { - why = "Out-of-bound offset register index"; + whyNot = "Out-of-bound offset register index"; return false; - } else if (UNLIKELY(insn.values + insn.valueNum > fn.tupleNum())) { - why = "Out-of-bound tuple index"; + } + if (UNLIKELY(insn.values + insn.valueNum > fn.tupleNum())) { + whyNot = "Out-of-bound tuple index"; return false; } - // Check that all the registers have the same size + // Check all registers 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"; + for (uint32_t valueID = 0; valueID < insn.valueNum; ++valueID) { + const RegisterIndex regID = fn.getRegisterIndex(insn.values, valueID); + if (UNLIKELY(checkRegister(family, regID, fn, whyNot) == false)) 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 LoadInstruction::wellFormed(const Function &fn, std::string &whyNot) const + { + return wellFormedLoadStore(*this, fn, whyNot); } - INLINE bool StoreInstruction::wellFormed(const Function &fn, std::string &why) const { - return wellFormedLoadStore(*this, fn, why); + + INLINE bool StoreInstruction::wellFormed(const Function &fn, std::string &whyNot) const + { + return wellFormedLoadStore(*this, fn, whyNot); } - INLINE bool LoadImmInstruction::wellFormed(const Function &fn, std::string &why) const { - if (UNLIKELY(dst >= fn.regNum())) { - why = "Out-of-bound register index"; + // TODO + INLINE bool TextureInstruction::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(valueIndex >= fn.valueNum())) { + whyNot = "Out-of-bound immediate value index"; return false; - } else if (UNLIKELY(valueIndex >= fn.valueNum())) { - why = "Out-of-bound immediate value index"; + } + if (UNLIKELY(type != fn.getValue(valueIndex).type)) { + whyNot = "Inconsistant type for the immediate value to load"; return false; - } else if (UNLIKELY(type != fn.getValue(valueIndex).type)) { - why = "Inconsistant type for the immediate value to load"; + } + const Register::Family family = getFamily(type); + if (UNLIKELY(checkRegister(family, dst, fn, whyNot) == false)) return false; - } else - return true; + return true; } - INLINE bool FenceInstruction::wellFormed(const Function &fn, std::string &why) const { + // Nothing can go wrong here + INLINE bool FenceInstruction::wellFormed(const Function &fn, std::string &whyNot) const + { 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; + } - INLINE bool LabelInstruction::wellFormed(const Function &fn, std::string &why) const { + // The label must exist and the register must of boolean family + INLINE bool BranchInstruction::wellFormed(const Function &fn, std::string &whyNot) const + { if (UNLIKELY(labelIndex >= fn.labelNum())) { - why = "Out-of-bound label index"; + whyNot = "Out-of-bound label index"; return false; - } else - return true; + } + if (hasPredicate) + if (UNLIKELY(checkRegister(Register::BOOL, predicate, fn, whyNot) == false)) + return false; + return true; } } /* namespace internal */ @@ -519,7 +644,13 @@ END_FUNCTION(Instruction, RegisterIndex) #define CALL getSrcIndex(fn, ID) START_FUNCTION(Instruction, RegisterIndex, getSrcIndex(const Function &fn, uint32_t ID)) #include "ir/instruction.hxx" -END_FUNCTION(Instruction, RegisterIndex) +END_FUNCTION(Instruction, bool) +#undef CALL + +#define CALL wellFormed(fn, whyNot) +START_FUNCTION(Instruction, bool, wellFormed(const Function &fn, std::string &whyNot)) +#include "ir/instruction.hxx" +END_FUNCTION(Instruction, bool) #undef CALL #undef END_FUNCTION diff --git a/backend/src/ir/instruction.hpp b/backend/src/ir/instruction.hpp index 80b30d3..f4c3015 100644 --- a/backend/src/ir/instruction.hpp +++ b/backend/src/ir/instruction.hpp @@ -136,6 +136,29 @@ namespace ir { static bool isClassOf(const Instruction &insn); }; + /*! Operation done in comparison */ + enum CompareOperation : uint8_t { + EQ = 0, // == + NE, // != + LT, // < + LE, // <= + GT, // > + GE // >= + }; + + /*! 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; + /*! Compare operation in the instruction */ + CompareOperation getOperation(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: @@ -311,6 +334,8 @@ namespace ir { 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); + /*! cmp.type.op dst src0 src1 */ + Instruction CMP(Type type, CompareInstruction op, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1); /*! cvt.{dstType <- srcType} dst src */ Instruction CVT(Type dstType, Type srcType, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1); /*! bra labelIndex */ diff --git a/backend/src/ir/instruction.hxx b/backend/src/ir/instruction.hxx index 79b80f3..2da6b2b 100644 --- a/backend/src/ir/instruction.hxx +++ b/backend/src/ir/instruction.hxx @@ -48,6 +48,7 @@ DECL_INSN(OR, BinaryInstruction) DECL_INSN(XOR, BinaryInstruction) DECL_INSN(AND, BinaryInstruction) DECL_INSN(MAD, TernaryInstruction) +DECL_INSN(CMP, CompareInstruction) DECL_INSN(CVT, ConvertInstruction) DECL_INSN(BRA, BranchInstruction) DECL_INSN(TEX, TextureInstruction) diff --git a/backend/src/ir/type.hpp b/backend/src/ir/type.hpp index 52dd5c0..f530c2b 100644 --- a/backend/src/ir/type.hpp +++ b/backend/src/ir/type.hpp @@ -68,6 +68,7 @@ namespace ir { case TYPE_DOUBLE: return Register::QWORD; }; + return Register::DWORD; } } /* namespace ir */