glsl: fix the type of ir_constant_data::u16
[mesa.git] / src / compiler / glsl / ir.h
index 83b810bba91318d5314a21476ea5d3d069496a8f..e2e46adc8554866cb2d6b08d5e202f411c677eee 100644 (file)
@@ -22,7 +22,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#pragma once
 #ifndef IR_H
 #define IR_H
 
 #include <stdlib.h>
 
 #include "util/ralloc.h"
+#include "util/format/u_format.h"
+#include "util/half_float.h"
 #include "compiler/glsl_types.h"
 #include "list.h"
 #include "ir_visitor.h"
 #include "ir_hierarchical_visitor.h"
-#include "main/mtypes.h"
 
 #ifdef __cplusplus
 
@@ -76,6 +76,7 @@ enum ir_node_type {
    ir_type_loop_jump,
    ir_type_return,
    ir_type_discard,
+   ir_type_demote,
    ir_type_emit_vertex,
    ir_type_end_primitive,
    ir_type_barrier,
@@ -230,11 +231,12 @@ public:
 
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    ir_rvalue *as_rvalue_to_saturate();
 
-   virtual bool is_lvalue() const
+   virtual bool is_lvalue(const struct _mesa_glsl_parse_state * = NULL) const
    {
       return false;
    }
@@ -397,7 +399,7 @@ depth_layout_string(ir_depth_layout layout);
  * \sa ir_variable::state_slots
  */
 struct ir_state_slot {
-   int tokens[5];
+   gl_state_index16 tokens[STATE_LENGTH];
    int swizzle;
 };
 
@@ -457,7 +459,7 @@ public:
     *
     * For the first declaration below, there will be an \c ir_variable named
     * "instance" whose type and whose instance_type will be the same
-    *  \cglsl_type.  For the second declaration, there will be an \c ir_variable
+    * \c glsl_type.  For the second declaration, there will be an \c ir_variable
     * named "f" whose type is float and whose instance_type is B2.
     *
     * "instance" is an interface instance variable, but "f" is not.
@@ -475,6 +477,17 @@ public:
       return this->type->without_array() == this->interface_type;
    }
 
+   /**
+    * Return whether this variable contains a bindless sampler/image.
+    */
+   inline bool contains_bindless() const
+   {
+      if (!this->type->contains_sampler() && !this->type->contains_image())
+         return false;
+
+      return this->data.bindless || this->data.mode != ir_var_uniform;
+   }
+
    /**
     * Set this->interface_type on a newly created variable.
     */
@@ -599,7 +612,8 @@ public:
 
    inline bool is_name_ralloced() const
    {
-      return this->name != ir_variable::tmp_name;
+      return this->name != ir_variable::tmp_name &&
+             this->name != this->name_storage;
    }
 
    /**
@@ -624,6 +638,16 @@ public:
     */
    const char *name;
 
+private:
+   /**
+    * If the name length fits into name_storage, it's used, otherwise
+    * the name is ralloc'd. shader-db mining showed that 70% of variables
+    * fit here. This is a win over ralloc where only ralloc_header has
+    * 20 bytes on 64-bit (28 bytes with DEBUG), and we can also skip malloc.
+    */
+   char name_storage[16];
+
+public:
    struct ir_variable_data {
 
       /**
@@ -636,6 +660,19 @@ public:
       unsigned centroid:1;
       unsigned sample:1;
       unsigned patch:1;
+      /**
+       * Was an 'invariant' qualifier explicitly set in the shader?
+       *
+       * This is used to cross validate qualifiers.
+       */
+      unsigned explicit_invariant:1;
+      /**
+       * Is the variable invariant?
+       *
+       * It can happen either by having the 'invariant' qualifier
+       * explicitly set in the shader or by being used in calculations
+       * of other invariant variables.
+       */
       unsigned invariant:1;
       unsigned precise:1;
 
@@ -646,8 +683,8 @@ public:
        * variable has been used.  For example, it is an error to redeclare a
        * variable as invariant after it has been used.
        *
-       * This is only maintained in the ast_to_hir.cpp path, not in
-       * Mesa's fixed function or ARB program paths.
+       * This is maintained in the ast_to_hir.cpp path and during linking,
+       * but not in Mesa's fixed function or ARB program paths.
        */
       unsigned used:1;
 
@@ -690,14 +727,6 @@ public:
        */
       unsigned interpolation:2;
 
-      /**
-       * \name ARB_fragment_coord_conventions
-       * @{
-       */
-      unsigned origin_upper_left:1;
-      unsigned pixel_center_integer:1;
-      /*@}*/
-
       /**
        * Was the location explicitly set in the shader?
        *
@@ -729,6 +758,11 @@ public:
        */
       unsigned has_initializer:1;
 
+      /**
+       * Is the initializer created by the compiler (glsl_zero_init)
+       */
+      unsigned is_implicit_initializer:1;
+
       /**
        * Is this variable a generic output or input that has not yet been matched
        * up to a variable in another stage of the pipeline?
@@ -738,6 +772,13 @@ public:
        */
       unsigned is_unmatched_generic_inout:1;
 
+      /**
+       * Is this varying used by transform feedback?
+       *
+       * This is used by the linker to decide if it's safe to pack the varying.
+       */
+      unsigned is_xfb:1;
+
       /**
        * Is this varying used only by transform feedback?
        *
@@ -746,17 +787,17 @@ public:
       unsigned is_xfb_only:1;
 
       /**
-       * Was a transfor feedback buffer set in the shader?
+       * Was a transform feedback buffer set in the shader?
        */
       unsigned explicit_xfb_buffer:1;
 
       /**
-       * Was a transfor feedback offset set in the shader?
+       * Was a transform feedback offset set in the shader?
        */
       unsigned explicit_xfb_offset:1;
 
       /**
-       * Was a transfor feedback stride set in the shader?
+       * Was a transform feedback stride set in the shader?
        */
       unsigned explicit_xfb_stride:1;
 
@@ -817,13 +858,13 @@ public:
       ir_depth_layout depth_layout:3;
 
       /**
-       * ARB_shader_image_load_store qualifiers.
+       * Memory qualifiers.
        */
-      unsigned image_read_only:1; /**< "readonly" qualifier. */
-      unsigned image_write_only:1; /**< "writeonly" qualifier. */
-      unsigned image_coherent:1;
-      unsigned image_volatile:1;
-      unsigned image_restrict:1;
+      unsigned memory_read_only:1; /**< "readonly" qualifier. */
+      unsigned memory_write_only:1; /**< "writeonly" qualifier. */
+      unsigned memory_coherent:1;
+      unsigned memory_volatile:1;
+      unsigned memory_restrict:1;
 
       /**
        * ARB_shader_storage_buffer_object
@@ -839,6 +880,18 @@ public:
        */
       unsigned fb_fetch_output:1;
 
+      /**
+       * Non-zero if this variable is considered bindless as defined by
+       * ARB_bindless_texture.
+       */
+      unsigned bindless:1;
+
+      /**
+       * Non-zero if this variable is considered bound as defined by
+       * ARB_bindless_texture.
+       */
+      unsigned bound:1;
+
       /**
        * Emit a warning if this variable is accessed.
        */
@@ -846,8 +899,11 @@ public:
       uint8_t warn_extension_index;
 
    public:
-      /** Image internal format if specified explicitly, otherwise GL_NONE. */
-      uint16_t image_format;
+      /**
+       * Image internal format if specified explicitly, otherwise
+       * PIPE_FORMAT_NONE.
+       */
+      enum pipe_format image_format;
 
    private:
       /**
@@ -866,7 +922,7 @@ public:
        *
        * For array types, this represents the binding point for the first element.
        */
-      int16_t binding;
+      uint16_t binding;
 
       /**
        * Storage location of the base of this variable
@@ -900,6 +956,9 @@ public:
 
       /**
        * Vertex stream output identifier.
+       *
+       * For packed outputs, bit 31 is set and bits [2*i+1,2*i] indicate the
+       * stream of the i-th component.
        */
       unsigned stream;
 
@@ -1065,6 +1124,8 @@ enum ir_intrinsic_id {
    ir_intrinsic_image_atomic_comp_swap,
    ir_intrinsic_image_size,
    ir_intrinsic_image_samples,
+   ir_intrinsic_image_atomic_inc_wrap,
+   ir_intrinsic_image_atomic_dec_wrap,
 
    ir_intrinsic_ssbo_load,
    ir_intrinsic_ssbo_store = MAKE_INTRINSIC_FOR_TYPE(store, ssbo),
@@ -1084,6 +1145,17 @@ enum ir_intrinsic_id {
    ir_intrinsic_memory_barrier_buffer,
    ir_intrinsic_memory_barrier_image,
    ir_intrinsic_memory_barrier_shared,
+   ir_intrinsic_begin_invocation_interlock,
+   ir_intrinsic_end_invocation_interlock,
+
+   ir_intrinsic_vote_all,
+   ir_intrinsic_vote_any,
+   ir_intrinsic_vote_eq,
+   ir_intrinsic_ballot,
+   ir_intrinsic_read_invocation,
+   ir_intrinsic_read_first_invocation,
+
+   ir_intrinsic_helper_invocation,
 
    ir_intrinsic_shared_load,
    ir_intrinsic_shared_store = MAKE_INTRINSIC_FOR_TYPE(store, shared),
@@ -1127,7 +1199,9 @@ public:
     * given a list of the actual parameters and the variable context.
     * Returns NULL for non-built-ins.
     */
-   ir_constant *constant_expression_value(exec_list *actual_parameters, struct hash_table *variable_context);
+   ir_constant *constant_expression_value(void *mem_ctx,
+                                          exec_list *actual_parameters,
+                                          struct hash_table *variable_context);
 
    /**
     * Get the name of the function for which this is a signature
@@ -1168,7 +1242,7 @@ public:
    /**
     * Function return type.
     *
-    * \note This discards the optional precision qualifier.
+    * \note The precision qualifier is stored separately in return_precision.
     */
    const struct glsl_type *return_type;
 
@@ -1183,6 +1257,13 @@ public:
    /** Whether or not this function has a body (which may be empty). */
    unsigned is_defined:1;
 
+   /*
+    * Precision qualifier for the return type.
+    *
+    * See the comment for ir_variable_data::precision for more details.
+    */
+   unsigned return_precision:2;
+
    /** Whether or not this function signature is a built-in. */
    bool is_builtin() const;
 
@@ -1230,7 +1311,8 @@ private:
     * Returns false if the expression is not constant, true otherwise,
     * and the value in *result if result is non-NULL.
     */
-   bool constant_expression_evaluate_expression_list(const struct exec_list &body,
+   bool constant_expression_evaluate_expression_list(void *mem_ctx,
+                                                     const struct exec_list &body,
                                                     struct hash_table *variable_context,
                                                     ir_constant **result);
 };
@@ -1386,7 +1468,8 @@ public:
 
    virtual ir_assignment *clone(void *mem_ctx, struct hash_table *ht) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
@@ -1454,6 +1537,7 @@ public:
 #include "ir_expression_operation.h"
 
 extern const char *const ir_expression_operation_strings[ir_last_opcode + 1];
+extern const char *const ir_expression_operation_enum_strings[ir_last_opcode + 1];
 
 class ir_expression : public ir_rvalue {
 public:
@@ -1491,21 +1575,14 @@ public:
     * If the expression cannot be constant folded, this method will return
     * \c NULL.
     */
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    /**
-    * Determine the number of operands used by an expression
+    * This is only here for ir_reader to used for testing purposes please use
+    * the precomputed num_operands field if you need the number of operands.
     */
-   static unsigned int get_num_operands(ir_expression_operation);
-
-   /**
-    * Determine the number of operands used by an expression
-    */
-   unsigned int get_num_operands() const
-   {
-      return (this->operation == ir_quadop_vector)
-        ? this->type->vector_elements : get_num_operands(operation);
-   }
+   static unsigned get_num_operands(ir_expression_operation);
 
    /**
     * Return whether the expression operates on vectors horizontally.
@@ -1535,8 +1612,21 @@ public:
 
    virtual ir_variable *variable_referenced() const;
 
+   /**
+    * Determine the number of operands used by an expression
+    */
+   void init_num_operands()
+   {
+      if (operation == ir_quadop_vector) {
+         num_operands = this->type->vector_elements;
+      } else {
+         num_operands = get_num_operands(operation);
+      }
+   }
+
    ir_expression_operation operation;
    ir_rvalue *operands[4];
+   uint8_t num_operands;
 };
 
 
@@ -1553,7 +1643,6 @@ public:
    {
       assert(callee->return_type != NULL);
       actual_parameters->move_nodes_to(& this->actual_parameters);
-      this->use_builtin = callee->is_builtin();
    }
 
    ir_call(ir_function_signature *callee,
@@ -1564,12 +1653,12 @@ public:
    {
       assert(callee->return_type != NULL);
       actual_parameters->move_nodes_to(& this->actual_parameters);
-      this->use_builtin = callee->is_builtin();
    }
 
    virtual ir_call *clone(void *mem_ctx, struct hash_table *ht) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
@@ -1606,9 +1695,6 @@ public:
    /* List of ir_rvalue of paramaters passed in this call. */
    exec_list actual_parameters;
 
-   /** Should this call only bind to a built-in function? */
-   bool use_builtin;
-
    /*
     * ARB_shader_subroutine support -
     * the subroutine uniform variable and array index
@@ -1738,6 +1824,28 @@ public:
 /*@}*/
 
 
+/**
+ * IR instruction representing demote statements from
+ * GL_EXT_demote_to_helper_invocation.
+ */
+class ir_demote : public ir_instruction {
+public:
+   ir_demote()
+      : ir_instruction(ir_type_demote)
+   {
+   }
+
+   virtual ir_demote *clone(void *mem_ctx, struct hash_table *ht) const;
+
+   virtual void accept(ir_visitor *v)
+   {
+      v->visit(this);
+   }
+
+   virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+};
+
+
 /**
  * Texture sampling opcodes used in ir_texture
  */
@@ -1766,7 +1874,7 @@ enum ir_texture_opcode {
  *
  *                                    Texel offset (0 or an expression)
  *                                    | Projection divisor
- *                                    | |  Shadow comparitor
+ *                                    | |  Shadow comparator
  *                                    | |  |
  *                                    v v  v
  * (tex <type> <sampler> <coordinate> 0 1 ( ))
@@ -1787,14 +1895,15 @@ public:
    ir_texture(enum ir_texture_opcode op)
       : ir_rvalue(ir_type_texture),
         op(op), sampler(NULL), coordinate(NULL), projector(NULL),
-        shadow_comparitor(NULL), offset(NULL)
+        shadow_comparator(NULL), offset(NULL)
    {
       memset(&lod_info, 0, sizeof(lod_info));
    }
 
    virtual ir_texture *clone(void *mem_ctx, struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
@@ -1842,7 +1951,7 @@ public:
     * 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;
+   ir_rvalue *shadow_comparator;
 
    /** Texel offset. */
    ir_rvalue *offset;
@@ -1891,7 +2000,8 @@ public:
 
    virtual ir_swizzle *clone(void *mem_ctx, struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    /**
     * Construct an ir_swizzle from the textual representation.  Can fail.
@@ -1908,9 +2018,9 @@ public:
    virtual bool equals(const ir_instruction *ir,
                        enum ir_node_type ignore = ir_type_unset) const;
 
-   bool is_lvalue() const
+   bool is_lvalue(const struct _mesa_glsl_parse_state *state) const
    {
-      return val->is_lvalue() && !mask.has_duplicates;
+      return val->is_lvalue(state) && !mask.has_duplicates;
    }
 
    /**
@@ -1935,13 +2045,19 @@ class ir_dereference : public ir_rvalue {
 public:
    virtual ir_dereference *clone(void *mem_ctx, struct hash_table *) const = 0;
 
-   bool is_lvalue() const;
+   bool is_lvalue(const struct _mesa_glsl_parse_state *state) const;
 
    /**
     * Get the variable that is ultimately referenced by an r-value
     */
    virtual ir_variable *variable_referenced() const = 0;
 
+   /**
+    * Get the precision. This can either come from the eventual variable that
+    * is dereferenced, or from a record member.
+    */
+   virtual int precision() const = 0;
+
 protected:
    ir_dereference(enum ir_node_type t)
       : ir_rvalue(t)
@@ -1957,7 +2073,8 @@ public:
    virtual ir_dereference_variable *clone(void *mem_ctx,
                                          struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual bool equals(const ir_instruction *ir,
                        enum ir_node_type ignore = ir_type_unset) const;
@@ -1970,6 +2087,11 @@ public:
       return this->var;
    }
 
+   virtual int precision() const
+   {
+      return this->var->data.precision;
+   }
+
    virtual ir_variable *whole_variable_referenced()
    {
       /* ir_dereference_variable objects always dereference the entire
@@ -2004,7 +2126,8 @@ public:
    virtual ir_dereference_array *clone(void *mem_ctx,
                                       struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual bool equals(const ir_instruction *ir,
                        enum ir_node_type ignore = ir_type_unset) const;
@@ -2017,6 +2140,16 @@ public:
       return this->array->variable_referenced();
    }
 
+   virtual int precision() const
+   {
+      ir_dereference *deref = this->array->as_dereference();
+
+      if (deref == NULL)
+         return GLSL_PRECISION_NONE;
+      else
+         return deref->precision();
+   }
+
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
@@ -2041,7 +2174,8 @@ public:
    virtual ir_dereference_record *clone(void *mem_ctx,
                                        struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    /**
     * Get the variable that is ultimately referenced by an r-value
@@ -2051,6 +2185,13 @@ public:
       return this->record->variable_referenced();
    }
 
+   virtual int precision() const
+   {
+      glsl_struct_field *field = record->type->fields.structure + field_idx;
+
+      return field->precision;
+   }
+
    virtual void accept(ir_visitor *v)
    {
       v->visit(this);
@@ -2059,7 +2200,7 @@ public:
    virtual ir_visitor_status accept(ir_hierarchical_visitor *);
 
    ir_rvalue *record;
-   const char *field;
+   int field_idx;
 };
 
 
@@ -2072,6 +2213,11 @@ union ir_constant_data {
       float f[16];
       bool b[16];
       double d[16];
+      uint16_t f16[16];
+      uint16_t u16[16];
+      int16_t i16[16];
+      uint64_t u64[16];
+      int64_t i64[16];
 };
 
 
@@ -2079,10 +2225,15 @@ class ir_constant : public ir_rvalue {
 public:
    ir_constant(const struct glsl_type *type, const ir_constant_data *data);
    ir_constant(bool b, unsigned vector_elements=1);
+   ir_constant(int16_t i16, unsigned vector_elements=1);
+   ir_constant(uint16_t u16, unsigned vector_elements=1);
    ir_constant(unsigned int u, unsigned vector_elements=1);
    ir_constant(int i, unsigned vector_elements=1);
+   ir_constant(float16_t f16, unsigned vector_elements=1);
    ir_constant(float f, unsigned vector_elements=1);
    ir_constant(double d, unsigned vector_elements=1);
+   ir_constant(uint64_t u64, unsigned vector_elements=1);
+   ir_constant(int64_t i64, unsigned vector_elements=1);
 
    /**
     * Construct an ir_constant from a list of ir_constant values
@@ -2108,7 +2259,8 @@ public:
 
    virtual ir_constant *clone(void *mem_ctx, struct hash_table *) const;
 
-   virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
+   virtual ir_constant *constant_expression_value(void *mem_ctx,
+                                                  struct hash_table *variable_context = NULL);
 
    virtual void accept(ir_visitor *v)
    {
@@ -2130,14 +2282,19 @@ public:
    /*@{*/
    bool get_bool_component(unsigned i) const;
    float get_float_component(unsigned i) const;
+   uint16_t get_float16_component(unsigned i) const;
    double get_double_component(unsigned i) const;
+   int16_t get_int16_component(unsigned i) const;
+   uint16_t get_uint16_component(unsigned i) const;
    int get_int_component(unsigned i) const;
    unsigned get_uint_component(unsigned i) const;
+   int64_t get_int64_component(unsigned i) const;
+   uint64_t get_uint64_component(unsigned i) const;
    /*@}*/
 
    ir_constant *get_array_element(unsigned i) const;
 
-   ir_constant *get_record_field(const char *name);
+   ir_constant *get_record_field(int idx);
 
    /**
     * Copy the values on another constant at a given offset.
@@ -2199,11 +2356,8 @@ public:
     */
    union ir_constant_data value;
 
-   /* Array elements */
-   ir_constant **array_elements;
-
-   /* Structure fields */
-   exec_list components;
+   /* Array elements and structure fields */
+   ir_constant **const_elements;
 
 private:
    /**
@@ -2352,47 +2506,9 @@ extern void
 _mesa_glsl_initialize_variables(exec_list *instructions,
                                struct _mesa_glsl_parse_state *state);
 
-extern void
-_mesa_glsl_initialize_derived_variables(struct gl_context *ctx,
-                                        gl_shader *shader);
-
-extern void
-_mesa_glsl_initialize_functions(_mesa_glsl_parse_state *state);
-
-extern void
-_mesa_glsl_initialize_builtin_functions();
-
-extern ir_function_signature *
-_mesa_glsl_find_builtin_function(_mesa_glsl_parse_state *state,
-                                 const char *name, exec_list *actual_parameters);
-
-extern ir_function *
-_mesa_glsl_find_builtin_function_by_name(const char *name);
-
-extern gl_shader *
-_mesa_glsl_get_builtin_function_shader(void);
-
-extern ir_function_signature *
-_mesa_get_main_function_signature(glsl_symbol_table *symbols);
-
-extern void
-_mesa_glsl_release_functions(void);
-
-extern void
-_mesa_glsl_release_builtin_functions(void);
-
 extern void
 reparent_ir(exec_list *list, void *mem_ctx);
 
-struct glsl_symbol_table;
-
-extern void
-import_prototypes(const exec_list *source, exec_list *dest,
-                 struct glsl_symbol_table *symbols, void *mem_ctx);
-
-extern bool
-ir_has_call(ir_instruction *ir);
-
 extern void
 do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
                       gl_shader_stage shader_stage);
@@ -2419,6 +2535,9 @@ extern "C" {
 extern void _mesa_print_ir(FILE *f, struct exec_list *instructions,
                            struct _mesa_glsl_parse_state *state);
 
+extern void
+ir_print_type(FILE *f, const struct glsl_type *t);
+
 extern void
 fprint_ir(FILE *f, const void *instruction);