Added compare instructions Finished to implement well formed functions. They basicall...
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Thu, 16 Feb 2012 11:34:31 +0000 (11:34 +0000)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:15:17 +0000 (16:15 -0700)
backend/src/ir/context.hpp
backend/src/ir/instruction.cpp
backend/src/ir/instruction.hpp
backend/src/ir/instruction.hxx
backend/src/ir/type.hpp

index 07e7b4e..afdee73 100644 (file)
@@ -120,34 +120,11 @@ namespace ir {
     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);                                           \
   }
index dbbdda0..1ccc47a 100644 (file)
@@ -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 <uint32_t srcNum>
+    INLINE bool NaryInstruction<srcNum>::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 <typename T>
-    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
index 80b30d3..f4c3015 100644 (file)
@@ -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 */
index 79b80f3..2da6b2b 100644 (file)
@@ -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)
index 52dd5c0..f530c2b 100644 (file)
@@ -68,6 +68,7 @@ namespace ir {
       case TYPE_DOUBLE:
         return Register::QWORD;
     };
+    return Register::DWORD;
   }
 
 } /* namespace ir */