ir_variable: Add method to get string representing interpolation qualifier
[mesa.git] / ir.h
diff --git a/ir.h b/ir.h
index 4266dbc17aa456a7f0a45b8fe24a7520315e77dd..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,8 +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:
@@ -76,8 +94,34 @@ 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() : ir_instruction() { }
+   ir_rvalue()
+   {
+      /* empty */
+   }
 };
 
 
@@ -110,6 +154,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    /**
     * Duplicate an IR variable
     *
@@ -131,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;
 
    /**
@@ -143,6 +199,12 @@ public:
    unsigned read_only:1;
    unsigned centroid:1;
    unsigned invariant:1;
+   /** If the variable is initialized outside of the scope of the shader */
+   unsigned shader_in:1;
+   /**
+    * If the variable value is later used outside of the scope of the shader.
+    */
+   unsigned shader_out:1;
 
    unsigned mode:3;
    unsigned interpolation:2;
@@ -155,6 +217,11 @@ public:
     */
    unsigned array_lvalue:1;
 
+   /**
+    * Emit a warning if this variable is accessed.
+    */
+   const char *warn_extension;
+
    /**
     * Value assigned in the initializer of a variable declared "const"
     */
@@ -162,21 +229,15 @@ public:
 };
 
 
-class ir_label : public ir_instruction {
-public:
-   ir_label(const char *label);
-
-   virtual void accept(ir_visitor *v)
-   {
-      v->visit(this);
-   }
-
-   const char *label;
-};
-
-
 /*@{*/
+/**
+ * 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.
+    */
 public:
    ir_function_signature(const glsl_type *return_type);
 
@@ -185,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.
     *
@@ -198,14 +275,18 @@ public:
    const struct glsl_type *return_type;
 
    /**
-    * List of function parameters stored as ir_variable objects.
+    * List of ir_variable of function parameters.
+    *
+    * This represents the storage.  The paramaters passed in a particular
+    * call will be in ir_call::actual_paramaters.
     */
    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;
 
 private:
    /** Function of which this signature is one overload. */
@@ -216,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;
@@ -242,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.
     */
@@ -253,7 +350,7 @@ public:
 
 private:
    /**
-    * Set of overloaded functions with this name.
+    * List of ir_function_signature for each overloaded function with this name.
     */
    struct exec_list signatures;
 };
@@ -276,13 +373,22 @@ public:
       /* empty */
    }
 
+   virtual ir_if *as_if()
+   {
+      return this;
+   }
+
    virtual void accept(ir_visitor *v)
    {
       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;
+   /** List of ir_instruction for the body of the else branch */
    exec_list  else_instructions;
 };
 
@@ -302,6 +408,13 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+   virtual ir_loop *as_loop()
+   {
+      return this;
+   }
+
    /**
     * Get an iterator for the instructions of the loop body
     */
@@ -310,7 +423,7 @@ public:
       return body_instructions.iterator();
    }
 
-   /** List of instructions that make up the body of the loop. */
+   /** List of ir_instruction that make up the body of the loop. */
    exec_list body_instructions;
 
    /**
@@ -334,6 +447,13 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+   virtual ir_assignment * as_assignment()
+   {
+      return this;
+   }
+
    /**
     * Left-hand side of the assignment.
     */
@@ -350,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,
@@ -382,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,
@@ -427,13 +564,31 @@ 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;
    ir_rvalue *operands[2];
 };
@@ -445,18 +600,25 @@ public:
 class ir_call : public ir_rvalue {
 public:
    ir_call(const ir_function_signature *callee, exec_list *actual_parameters)
-      : ir_rvalue(), callee(callee)
+      : callee(callee)
    {
       assert(callee->return_type != NULL);
       type = callee->return_type;
       actual_parameters->move_nodes_to(& this->actual_parameters);
    }
 
+   virtual ir_call *as_call()
+   {
+      return this;
+   }
+
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    /**
     * Get a generic ir_call object when an error occurs
     */
@@ -478,14 +640,27 @@ public:
       return callee->function_name();
    }
 
+   const ir_function_signature *get_callee()
+   {
+      return callee;
+   }
+
+   /**
+    * Generates an inline version of the function before @ir,
+    * returning the return value of the function.
+    */
+   ir_rvalue *generate_inline(ir_instruction *ir);
+
 private:
    ir_call()
-      : ir_rvalue(), callee(NULL)
+      : callee(NULL)
    {
       /* empty */
    }
 
    const ir_function_signature *callee;
+
+   /* List of ir_rvalue of paramaters passed in this call. */
    exec_list actual_parameters;
 };
 
@@ -499,7 +674,6 @@ private:
 class ir_jump : public ir_instruction {
 protected:
    ir_jump()
-      : ir_instruction()
    {
       /* empty */
    }
@@ -519,6 +693,11 @@ public:
       /* empty */
    }
 
+   virtual ir_return *as_return()
+   {
+      return this;
+   }
+
    ir_rvalue *get_value() const
    {
       return value;
@@ -529,7 +708,8 @@ public:
       v->visit(this);
    }
 
-private:
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    ir_rvalue *value;
 };
 
@@ -560,6 +740,8 @@ public:
       v->visit(this);
    }
 
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
    bool is_break() const
    {
       return mode == jump_break;
@@ -580,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;
@@ -604,6 +883,18 @@ 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);
+
+   virtual ir_swizzle *as_swizzle()
+   {
+      return this;
+   }
+
+   ir_swizzle *clone()
+   {
+      return new ir_swizzle(this->val, this->mask);
+   }
+
    /**
     * Construct an ir_swizzle from the textual representation.  Can fail.
     */
@@ -614,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;
 };
@@ -626,55 +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);
+};
 
-   enum {
-      ir_reference_variable,
-      ir_reference_array,
-      ir_reference_record
-   } mode;
+
+class ir_dereference_record : public ir_dereference {
+public:
+   ir_dereference_record(ir_rvalue *value, const char *field);
+
+   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);
 
+   /**
+    * 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()
+   {
+      return this;
+   }
+
    virtual void accept(ir_visitor *v)
    {
       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.
     *
@@ -682,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);