ir_variable: Add method to get string representing interpolation qualifier
[mesa.git] / ir.h
diff --git a/ir.h b/ir.h
index cb153be77de77291b2181d02f048246638f8cf4b..04ecb582e482268f3f18a85ab1210b5974e4f707 100644 (file)
--- a/ir.h
+++ b/ir.h
 #ifndef IR_H
 #define IR_H
 
+#include <cstdio>
+#include <cstdlib>
+
 #include "list.h"
 #include "ir_visitor.h"
+#include "ir_hierarchical_visitor.h"
 
 struct ir_program {
    void *bong_hits;
@@ -41,7 +45,12 @@ public:
    const struct glsl_type *type;
 
    class ir_constant *constant_expression_value();
+
+   /** ir_print_visitor helper for debugging. */
+   void print(void);
+
    virtual void accept(ir_visitor *) = 0;
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *) = 0;
 
    /**
     * \name IR instruction downcast functions
@@ -52,13 +61,17 @@ public:
     */
    /*@{*/
    virtual class ir_variable *          as_variable()         { return NULL; }
+   virtual class ir_function *          as_function()         { return NULL; }
    virtual class ir_dereference *       as_dereference()      { return NULL; }
+   virtual class ir_dereference_array *        as_dereference_array() { return NULL; }
    virtual class ir_rvalue *            as_rvalue()           { return NULL; }
    virtual class ir_loop *              as_loop()             { return NULL; }
    virtual class ir_assignment *        as_assignment()       { return NULL; }
    virtual class ir_call *              as_call()             { return NULL; }
    virtual class ir_return *            as_return()           { return NULL; }
    virtual class ir_if *                as_if()               { return NULL; }
+   virtual class ir_swizzle *           as_swizzle()          { return NULL; }
+   virtual class ir_constant *          as_constant()         { return NULL; }
    /*@}*/
 
 protected:
@@ -81,6 +94,29 @@ public:
       return false;
    }
 
+   /**
+    * Get the variable that is ultimately referenced by an r-value
+    */
+   virtual ir_variable *variable_referenced()
+   {
+      return NULL;
+   }
+
+
+   /**
+    * If an r-value is a reference to a whole variable, get that variable
+    *
+    * \return
+    * Pointer to a variable that is completely dereferenced by the r-value.  If
+    * the r-value is not a dereference or the dereference does not access the
+    * entire variable (i.e., it's just one array element, struct field), \c NULL
+    * is returned.
+    */
+   virtual ir_variable *whole_variable_referenced()
+   {
+      return NULL;
+   }
+
 protected:
    ir_rvalue()
    {
@@ -118,6 +154,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    /**
     * Duplicate an IR variable
     *
@@ -139,6 +177,16 @@ public:
       return var;
    }
 
+   /**
+    * Get the string value for the interpolation qualifier
+    *
+    * \return
+    * If none of \c shader_in or \c shader_out is set, an empty string will
+    * be returned.  Otherwise the string that would be used in a shader to
+    * specify \c mode will be returned.
+    */
+   const char *interpolation_string() const;
+
    const char *name;
 
    /**
@@ -181,22 +229,11 @@ public:
 };
 
 
-class ir_label : public ir_instruction {
-public:
-   ir_label(const char *label, ir_function_signature *signature);
-
-   virtual void accept(ir_visitor *v)
-   {
-      v->visit(this);
-   }
-
-   const char *label;
-
-   ir_function_signature *signature;
-};
-
-
 /*@{*/
+/**
+ * The representation of a function instance; may be the full definition or
+ * simply a prototype.
+ */
 class ir_function_signature : public ir_instruction {
    /* An ir_function_signature will be part of the list of signatures in
     * an ir_function.
@@ -209,11 +246,27 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    /**
     * Get the name of the function for which this is a signature
     */
    const char *function_name() const;
 
+   /**
+    * Check whether the qualifiers match between this signature's parameters
+    * and the supplied parameter list.  If not, returns the name of the first
+    * parameter with mismatched qualifiers (for use in error messages).
+    */
+   const char *qualifiers_match(exec_list *params);
+
+   /**
+    * Replace the current parameter list with the given one.  This is useful
+    * if the current information came from a prototype, and either has invalid
+    * or missing parameter names.
+    */
+   void replace_parameters(exec_list *new_params);
+
    /**
     * Function return type.
     *
@@ -229,10 +282,8 @@ public:
     */
    struct exec_list parameters;
 
-   /**
-    * Pointer to the label that begins the function definition.
-    */
-   ir_label *definition;
+   /** Whether or not this function has a body (which may be empty). */
+   unsigned is_defined:1;
 
    /** Body of instructions in the function. */
    struct exec_list body;
@@ -246,17 +297,26 @@ private:
 
 
 /**
- * Header for tracking functions in the symbol table
+ * Header for tracking multiple overloaded functions with the same name.
+ * Contains a list of ir_function_signatures representing each of the
+ * actual functions.
  */
 class ir_function : public ir_instruction {
 public:
    ir_function(const char *name);
 
+   virtual ir_function *as_function()
+   {
+      return this;
+   }
+
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    void add_signature(ir_function_signature *sig)
    {
       sig->function = this;
@@ -272,10 +332,17 @@ public:
    }
 
    /**
-    * Find a signature that matches a set of actual parameters.
+    * Find a signature that matches a set of actual parameters, taking implicit
+    * conversions into account.
     */
    const ir_function_signature *matching_signature(exec_list *actual_param);
 
+   /**
+    * Find a signature that exactly matches a set of actual parameters without
+    * any implicit type conversions.
+    */
+   ir_function_signature *exact_matching_signature(exec_list *actual_ps);
+
    /**
     * Name of the function.
     */
@@ -316,6 +383,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    ir_rvalue *condition;
    /** List of ir_instruction for the body of the then branch */
    exec_list  then_instructions;
@@ -339,6 +408,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    virtual ir_loop *as_loop()
    {
       return this;
@@ -376,6 +447,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    virtual ir_assignment * as_assignment()
    {
       return this;
@@ -397,14 +470,15 @@ public:
    ir_rvalue *condition;
 };
 
-/* Update ir_expression::num_operands() and ir_print_visitor.cpp when
+/* Update ir_expression::num_operands() and operator_strs when
  * updating this list.
-*/
+ */
 enum ir_expression_operation {
    ir_unop_bit_not,
    ir_unop_logic_not,
    ir_unop_neg,
    ir_unop_abs,
+   ir_unop_sign,
    ir_unop_rcp,
    ir_unop_rsq,
    ir_unop_sqrt,
@@ -429,6 +503,22 @@ enum ir_expression_operation {
    ir_unop_floor,
    /*@}*/
 
+   /**
+    * \name Trigonometric operations.
+    */
+   /*@{*/
+   ir_unop_sin,
+   ir_unop_cos,
+   /*@}*/
+
+   /**
+    * \name Partial derivatives.
+    */
+   /*@{*/
+   ir_unop_dFdx,
+   ir_unop_dFdy,
+   /*@}*/
+
    ir_binop_add,
    ir_binop_sub,
    ir_binop_mul,
@@ -474,13 +564,29 @@ public:
    ir_expression(int op, const struct glsl_type *type,
                 ir_rvalue *, ir_rvalue *);
 
-   unsigned int get_num_operands(void);
+   static unsigned int get_num_operands(ir_expression_operation);
+   unsigned int get_num_operands()
+   {
+      return get_num_operands(operation);
+   }
+
+   /**
+    * Return a string representing this expression's operator.
+    */
+   const char *operator_string();
+
+   /**
+    * Do a reverse-lookup to translate the given string into an operator.
+    */
+   static ir_expression_operation get_operator(const char *);
 
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    ir_expression *clone();
 
    ir_expression_operation operation;
@@ -511,6 +617,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    /**
     * Get a generic ir_call object when an error occurs
     */
@@ -600,7 +708,8 @@ public:
       v->visit(this);
    }
 
-private:
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    ir_rvalue *value;
 };
 
@@ -631,6 +740,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    bool is_break() const
    {
       return mode == jump_break;
@@ -651,6 +762,103 @@ private:
 /*@}*/
 
 
+/**
+ * Texture sampling opcodes used in ir_texture
+ */
+enum ir_texture_opcode {
+   ir_tex,             /* Regular texture look-up */
+   ir_txb,             /* Texture look-up with LOD bias */
+   ir_txl,             /* Texture look-up with explicit LOD */
+   ir_txd,             /* Texture look-up with partial derivatvies */
+   ir_txf              /* Texel fetch with explicit LOD */
+};
+
+
+/**
+ * IR instruction to sample a texture
+ *
+ * The specific form of the IR instruction depends on the \c mode value
+ * selected from \c ir_texture_opcodes.  In the printed IR, these will
+ * appear as:
+ *
+ *                              Texel offset
+ *                              |       Projection divisor
+ *                              |       |   Shadow comparitor
+ *                              |       |   |
+ *                              v       v   v
+ * (tex (sampler) (coordinate) (0 0 0) (1) ( ))
+ * (txb (sampler) (coordinate) (0 0 0) (1) ( ) (bias))
+ * (txl (sampler) (coordinate) (0 0 0) (1) ( ) (lod))
+ * (txd (sampler) (coordinate) (0 0 0) (1) ( ) (dPdx dPdy))
+ * (txf (sampler) (coordinate) (0 0 0)         (lod))
+ */
+class ir_texture : public ir_rvalue {
+public:
+   ir_texture(enum ir_texture_opcode op)
+      : op(op), projector(NULL), shadow_comparitor(NULL)
+   {
+      /* empty */
+   }
+
+   virtual void accept(ir_visitor *v)
+   {
+      v->visit(this);
+   }
+
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+   /**
+    * Return a string representing the ir_texture_opcode.
+    */
+   const char *opcode_string();
+
+   /** Set the sampler and infer the type. */
+   void set_sampler(ir_dereference *sampler);
+
+   /**
+    * Do a reverse-lookup to translate a string into an ir_texture_opcode.
+    */
+   static ir_texture_opcode get_opcode(const char *);
+
+   enum ir_texture_opcode op;
+
+   /** Sampler to use for the texture access. */
+   ir_dereference *sampler;
+
+   /** Texture coordinate to sample */
+   ir_rvalue *coordinate;
+
+   /**
+    * Value used for projective divide.
+    *
+    * If there is no projective divide (the common case), this will be
+    * \c NULL.  Optimization passes should check for this to point to a constant
+    * of 1.0 and replace that with \c NULL.
+    */
+   ir_rvalue *projector;
+
+   /**
+    * Coordinate used for comparison on shadow look-ups.
+    *
+    * If there is no shadow comparison, this will be \c NULL.  For the
+    * \c ir_txf opcode, this *must* be \c NULL.
+    */
+   ir_rvalue *shadow_comparitor;
+
+   /** Explicit texel offsets. */
+   signed char offsets[3];
+
+   union {
+      ir_rvalue *lod;          /**< Floating point LOD */
+      ir_rvalue *bias;         /**< Floating point LOD bias */
+      struct {
+        ir_rvalue *dPdx;       /**< Partial derivative of coordinate wrt X */
+        ir_rvalue *dPdy;       /**< Partial derivative of coordinate wrt Y */
+      } grad;
+   } lod_info;
+};
+
+
 struct ir_swizzle_mask {
    unsigned x:2;
    unsigned y:2;
@@ -675,10 +883,11 @@ class ir_swizzle : public ir_rvalue {
 public:
    ir_swizzle(ir_rvalue *, unsigned x, unsigned y, unsigned z, unsigned w,
               unsigned count);
-   ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask)
-      : val(val), mask(mask)
+   ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask);
+
+   virtual ir_swizzle *as_swizzle()
    {
-      /* empty */
+      return this;
    }
 
    ir_swizzle *clone()
@@ -696,11 +905,18 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    bool is_lvalue()
    {
       return val->is_lvalue() && !mask.has_duplicates;
    }
 
+   /**
+    * Get the variable that is ultimately referenced by an r-value
+    */
+   virtual ir_variable *variable_referenced();
+
    ir_rvalue *val;
    ir_swizzle_mask mask;
 };
@@ -708,60 +924,188 @@ public:
 
 class ir_dereference : public ir_rvalue {
 public:
-   ir_dereference(struct ir_instruction *);
+   virtual ir_dereference *as_dereference()
+   {
+      return this;
+   }
 
-   ir_dereference(ir_instruction *variable, ir_rvalue *array_index);
+   bool is_lvalue();
 
-   virtual ir_dereference *as_dereference()
+   /**
+    * Get the variable that is ultimately referenced by an r-value
+    */
+   virtual ir_variable *variable_referenced() = 0;
+};
+
+
+class ir_dereference_variable : public ir_dereference {
+public:
+   ir_dereference_variable(ir_variable *var);
+
+   /**
+    * Get the variable that is ultimately referenced by an r-value
+    */
+   virtual ir_variable *variable_referenced()
+   {
+      return this->var;
+   }
+
+   virtual ir_variable *whole_variable_referenced()
+   {
+      /* ir_dereference_variable objects always dereference the entire
+       * variable.  However, if this dereference is dereferenced by anything
+       * else, the complete deferefernce chain is not a whole-variable
+       * dereference.  This method should only be called on the top most
+       * ir_rvalue in a dereference chain.
+       */
+      return this->var;
+   }
+
+   virtual void accept(ir_visitor *v)
+   {
+      v->visit(this);
+   }
+
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+   /**
+    * Object being dereferenced.
+    */
+   ir_variable *var;
+};
+
+
+class ir_dereference_array : public ir_dereference {
+public:
+   ir_dereference_array(ir_rvalue *value, ir_rvalue *array_index);
+
+   ir_dereference_array(ir_variable *var, ir_rvalue *array_index);
+
+   virtual ir_dereference_array *as_dereference_array()
    {
       return this;
    }
 
+   /**
+    * Get the variable that is ultimately referenced by an r-value
+    */
+   virtual ir_variable *variable_referenced()
+   {
+      return this->array->variable_referenced();
+   }
+
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
-   bool is_lvalue();
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+   ir_rvalue *array;
+   ir_rvalue *array_index;
+
+private:
+   void set_array(ir_rvalue *value);
+};
+
+
+class ir_dereference_record : public ir_dereference {
+public:
+   ir_dereference_record(ir_rvalue *value, const char *field);
 
-   enum {
-      ir_reference_variable,
-      ir_reference_array,
-      ir_reference_record
-   } mode;
+   ir_dereference_record(ir_variable *var, const char *field);
 
    /**
-    * Object being dereferenced.
-    *
-    * Must be either an \c ir_variable or an \c ir_rvalue.
+    * Get the variable that is ultimately referenced by an r-value
     */
-   ir_instruction *var;
+   virtual ir_variable *variable_referenced()
+   {
+      return this->record->variable_referenced();
+   }
 
-   union {
-      ir_rvalue *array_index;
-      const char *field;
-   } selector;
+   virtual void accept(ir_visitor *v)
+   {
+      v->visit(this);
+   }
+
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+   ir_rvalue *record;
+   const char *field;
+};
+
+
+/**
+ * Data stored in an ir_constant
+ */
+union ir_constant_data {
+      unsigned u[16];
+      int i[16];
+      float f[16];
+      bool b[16];
 };
 
 
 class ir_constant : public ir_rvalue {
 public:
-   ir_constant(const struct glsl_type *type, const void *data);
+   ir_constant(const struct glsl_type *type, const ir_constant_data *data);
    ir_constant(bool b);
    ir_constant(unsigned int u);
    ir_constant(int i);
    ir_constant(float f);
 
-   virtual void accept(ir_visitor *v)
+   /**
+    * Construct an ir_constant from a list of ir_constant values
+    */
+   ir_constant(const struct glsl_type *type, exec_list *values);
+
+   /**
+    * Construct an ir_constant from a scalar component of another ir_constant
+    *
+    * The new \c ir_constant inherits the type of the component from the
+    * source constant.
+    *
+    * \note
+    * In the case of a matrix constant, the new constant is a scalar, \b not
+    * a vector.
+    */
+   ir_constant(const ir_constant *c, unsigned i);
+
+   virtual ir_constant *as_constant()
    {
-      v->visit(this);
+      return this;
    }
 
-   ir_constant *clone()
+   virtual void accept(ir_visitor *v)
    {
-      return new ir_constant(this->type, &this->value);
+      v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+   ir_constant *clone();
+
+   /**
+    * Get a particular component of a constant as a specific type
+    *
+    * This is useful, for example, to get a value from an integer constant
+    * as a float or bool.  This appears frequently when constructors are
+    * called with all constant parameters.
+    */
+   /*@{*/
+   bool get_bool_component(unsigned i) const;
+   float get_float_component(unsigned i) const;
+   int get_int_component(unsigned i) const;
+   unsigned get_uint_component(unsigned i) const;
+   /*@}*/
+
+   ir_constant *get_record_field(const char *name);
+
+   /**
+    * Determine whether a constant has the same value as another constant
+    */
+   bool has_value(const ir_constant *) const;
+
    /**
     * Value of the constant.
     *
@@ -769,17 +1113,22 @@ public:
     * by the type associated with the \c ir_instruction.  Constants may be
     * scalars, vectors, or matrices.
     */
-   union {
-      unsigned u[16];
-      int i[16];
-      float f[16];
-      bool b[16];
-   } value;
+   union ir_constant_data value;
+
+   exec_list components;
+
+private:
+   /**
+    * Parameterless constructor only used by the clone method
+    */
+   ir_constant(void);
 };
 
 void
 visit_exec_list(exec_list *list, ir_visitor *visitor);
 
+void validate_ir_tree(exec_list *instructions);
+
 extern void
 _mesa_glsl_initialize_variables(exec_list *instructions,
                                struct _mesa_glsl_parse_state *state);