X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fir.h;h=e1109eec1d3da8649eadd947570d3c0b6d3ba831;hb=b9fc01aee75dcc2d56750ea430e32d74127faf69;hp=c4c00552ac31c2f138e0594ae497e3b3d90d3ce2;hpb=f65feb5335331ed0960d3fd62a70d0d0aaf23ab7;p=mesa.git diff --git a/src/glsl/ir.h b/src/glsl/ir.h index c4c00552ac3..e1109eec1d3 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -29,7 +29,7 @@ #include #include -#include "ralloc.h" +#include "util/ralloc.h" #include "glsl_types.h" #include "list.h" #include "ir_visitor.h" @@ -59,33 +59,31 @@ * types, this allows writing very straightforward, readable code. */ enum ir_node_type { - /** - * Zero is unused so that the IR validator can detect cases where - * \c ir_instruction::ir_type has not been initialized. - */ - ir_type_unset, - ir_type_variable, - ir_type_assignment, - ir_type_call, - ir_type_constant, ir_type_dereference_array, ir_type_dereference_record, ir_type_dereference_variable, - ir_type_discard, + ir_type_constant, ir_type_expression, + ir_type_swizzle, + ir_type_texture, + ir_type_variable, + ir_type_assignment, + ir_type_call, ir_type_function, ir_type_function_signature, ir_type_if, ir_type_loop, ir_type_loop_jump, ir_type_return, - ir_type_swizzle, - ir_type_texture, + ir_type_discard, ir_type_emit_vertex, ir_type_end_primitive, - ir_type_max /**< maximum ir_type enum number, for validation */ + ir_type_barrier, + ir_type_max, /**< maximum ir_type enum number, for validation */ + ir_type_unset = ir_type_max }; + /** * Base class of all IR instructions */ @@ -105,12 +103,38 @@ public: /** ir_print_visitor helper for debugging. */ void print(void) const; + void fprint(FILE *f) const; virtual void accept(ir_visitor *) = 0; virtual ir_visitor_status accept(ir_hierarchical_visitor *) = 0; virtual ir_instruction *clone(void *mem_ctx, struct hash_table *ht) const = 0; + bool is_rvalue() const + { + return ir_type == ir_type_dereference_array || + ir_type == ir_type_dereference_record || + ir_type == ir_type_dereference_variable || + ir_type == ir_type_constant || + ir_type == ir_type_expression || + ir_type == ir_type_swizzle || + ir_type == ir_type_texture; + } + + bool is_dereference() const + { + return ir_type == ir_type_dereference_array || + ir_type == ir_type_dereference_record || + ir_type == ir_type_dereference_variable; + } + + bool is_jump() const + { + return ir_type == ir_type_loop_jump || + ir_type == ir_type_return || + ir_type == ir_type_discard; + } + /** * \name IR instruction downcast functions * @@ -119,29 +143,73 @@ public: * Additional downcast functions will be added as needed. */ /*@{*/ - 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_dereference_variable *as_dereference_variable() { return NULL; } - virtual class ir_dereference_record *as_dereference_record() { return NULL; } - virtual class ir_expression * as_expression() { 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; } - virtual class ir_discard * as_discard() { return NULL; } - virtual class ir_jump * as_jump() { return NULL; } + #define AS_BASE(TYPE) \ + class ir_##TYPE *as_##TYPE() \ + { \ + assume(this != NULL); \ + return is_##TYPE() ? (ir_##TYPE *) this : NULL; \ + } \ + const class ir_##TYPE *as_##TYPE() const \ + { \ + assume(this != NULL); \ + return is_##TYPE() ? (ir_##TYPE *) this : NULL; \ + } + + AS_BASE(rvalue) + AS_BASE(dereference) + AS_BASE(jump) + #undef AS_BASE + + #define AS_CHILD(TYPE) \ + class ir_##TYPE * as_##TYPE() \ + { \ + assume(this != NULL); \ + return ir_type == ir_type_##TYPE ? (ir_##TYPE *) this : NULL; \ + } \ + const class ir_##TYPE * as_##TYPE() const \ + { \ + assume(this != NULL); \ + return ir_type == ir_type_##TYPE ? (const ir_##TYPE *) this : NULL; \ + } + AS_CHILD(variable) + AS_CHILD(function) + AS_CHILD(dereference_array) + AS_CHILD(dereference_variable) + AS_CHILD(dereference_record) + AS_CHILD(expression) + AS_CHILD(loop) + AS_CHILD(assignment) + AS_CHILD(call) + AS_CHILD(return) + AS_CHILD(if) + AS_CHILD(swizzle) + AS_CHILD(texture) + AS_CHILD(constant) + AS_CHILD(discard) + #undef AS_CHILD /*@}*/ + /** + * IR equality method: Return true if the referenced instruction would + * return the same value as this one. + * + * This intended to be used for CSE and algebraic optimizations, on rvalues + * in particular. No support for other instruction types (assignments, + * jumps, calls, etc.) is planned. + */ + virtual bool equals(const ir_instruction *ir, + enum ir_node_type ignore = ir_type_unset) const; + protected: + ir_instruction(enum ir_node_type t) + : ir_type(t) + { + } + +private: ir_instruction() { - ir_type = ir_type_unset; + assert(!"Should not get here."); } }; @@ -164,11 +232,6 @@ public: virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL); - virtual ir_rvalue * as_rvalue() - { - return this; - } - ir_rvalue *as_rvalue_to_saturate(); virtual bool is_lvalue() const @@ -207,8 +270,7 @@ public: * for vector and scalar types that have all elements set to the value * zero (or \c false for booleans). * - * \sa ir_constant::has_value, ir_rvalue::is_one, ir_rvalue::is_negative_one, - * ir_constant::is_basis + * \sa ir_constant::has_value, ir_rvalue::is_one, ir_rvalue::is_negative_one */ virtual bool is_zero() const; @@ -220,8 +282,7 @@ public: * for vector and scalar types that have all elements set to the value * one (or \c true for booleans). * - * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_negative_one, - * ir_constant::is_basis + * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_negative_one */ virtual bool is_one() const; @@ -234,24 +295,16 @@ public: * negative one. For boolean types, the result is always \c false. * * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_one - * ir_constant::is_basis */ virtual bool is_negative_one() const; /** - * Determine if an r-value is a basis vector + * Determine if an r-value is an unsigned integer constant which can be + * stored in 16 bits. * - * The base implementation of this function always returns \c false. The - * \c ir_constant class over-rides this function to return \c true \b only - * for vector and scalar types that have one element set to the value one, - * and the other elements set to the value zero. For boolean types, the - * result is always \c false. - * - * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_one, - * is_constant::is_negative_one + * \sa ir_constant::is_uint16_constant. */ - virtual bool is_basis() const; - + virtual bool is_uint16_constant() const { return false; } /** * Return a generic value of error_type. @@ -261,7 +314,7 @@ public: static ir_rvalue *error_value(void *mem_ctx); protected: - ir_rvalue(); + ir_rvalue(enum ir_node_type t); }; @@ -269,17 +322,53 @@ protected: * Variable storage classes */ enum ir_variable_mode { - ir_var_auto = 0, /**< Function local variables and globals. */ - ir_var_uniform, /**< Variable declared as a uniform. */ + ir_var_auto = 0, /**< Function local variables and globals. */ + ir_var_uniform, /**< Variable declared as a uniform. */ + ir_var_shader_storage, /**< Variable declared as an ssbo. */ + ir_var_shader_shared, /**< Variable declared as shared. */ ir_var_shader_in, ir_var_shader_out, ir_var_function_in, ir_var_function_out, ir_var_function_inout, - ir_var_const_in, /**< "in" param that must be a constant expression */ - ir_var_system_value, /**< Ex: front-face, instance-id, etc. */ - ir_var_temporary, /**< Temporary variable generated during compilation. */ - ir_var_mode_count /**< Number of variable modes */ + ir_var_const_in, /**< "in" param that must be a constant expression */ + ir_var_system_value, /**< Ex: front-face, instance-id, etc. */ + ir_var_temporary, /**< Temporary variable generated during compilation. */ + ir_var_mode_count /**< Number of variable modes */ +}; + +/** + * Enum keeping track of how a variable was declared. For error checking of + * the gl_PerVertex redeclaration rules. + */ +enum ir_var_declaration_type { + /** + * Normal declaration (for most variables, this means an explicit + * declaration. Exception: temporaries are always implicitly declared, but + * they still use ir_var_declared_normally). + * + * Note: an ir_variable that represents a named interface block uses + * ir_var_declared_normally. + */ + ir_var_declared_normally = 0, + + /** + * Variable was explicitly declared (or re-declared) in an unnamed + * interface block. + */ + ir_var_declared_in_block, + + /** + * Variable is an implicitly declared built-in that has not been explicitly + * re-declared by the shader. + */ + ir_var_declared_implicitly, + + /** + * Variable is implicitly generated by the compiler and should not be + * visible via the API. + */ + ir_var_hidden, }; /** @@ -334,11 +423,6 @@ public: virtual ir_variable *clone(void *mem_ctx, struct hash_table *ht) const; - virtual ir_variable *as_variable() - { - return this; - } - virtual void accept(ir_visitor *v) { v->visit(this); @@ -359,11 +443,23 @@ public: glsl_interp_qualifier determine_interpolation_mode(bool flat_shade); /** - * Determine whether or not a variable is part of a uniform block. + * Determine whether or not a variable is part of a uniform or + * shader storage block. */ - inline bool is_in_uniform_block() const + inline bool is_in_buffer_block() const { - return this->mode == ir_var_uniform && this->interface_type != NULL; + return (this->data.mode == ir_var_uniform || + this->data.mode == ir_var_shader_storage) && + this->interface_type != NULL; + } + + /** + * Determine whether or not a variable is part of a shader storage block. + */ + inline bool is_in_shader_storage_block() const + { + return this->data.mode == ir_var_shader_storage && + this->interface_type != NULL; } /** @@ -387,11 +483,8 @@ public: */ inline bool is_interface_instance() const { - const glsl_type *const t = this->type; - - return (t == this->interface_type) - || (t->is_array() && t->fields.array == this->interface_type); - } + return this->type->without_array() == this->interface_type; + } /** * Set this->interface_type on a newly created variable. @@ -401,7 +494,7 @@ public: assert(this->interface_type == NULL); this->interface_type = type; if (this->is_interface_instance()) { - this->max_ifc_array_access = + this->u.max_ifc_array_access = rzalloc_array(this, unsigned, type->length); } } @@ -413,7 +506,7 @@ public: */ void change_interface_type(const struct glsl_type *type) { - if (this->max_ifc_array_access != NULL) { + if (this->u.max_ifc_array_access != NULL) { /* max_ifc_array_access has already been allocated, so make sure the * new interface has the same number of fields as the old one. */ @@ -430,18 +523,18 @@ public: */ void reinit_interface_type(const struct glsl_type *type) { - if (this->max_ifc_array_access != NULL) { -#ifndef _NDEBUG + if (this->u.max_ifc_array_access != NULL) { +#ifndef NDEBUG /* Redeclaring gl_PerVertex is only allowed if none of the built-ins * it defines have been accessed yet; so it's safe to throw away the * old max_ifc_array_access pointer, since all of its values are * zero. */ for (unsigned i = 0; i < this->interface_type->length; i++) - assert(this->max_ifc_array_access[i] == 0); + assert(this->u.max_ifc_array_access[i] == 0); #endif - ralloc_free(this->max_ifc_array_access); - this->max_ifc_array_access = NULL; + ralloc_free(this->u.max_ifc_array_access); + this->u.max_ifc_array_access = NULL; } this->interface_type = NULL; init_interface_type(type); @@ -453,193 +546,340 @@ public: } /** - * Declared type of the variable + * Get the max_ifc_array_access pointer + * + * A "set" function is not needed because the array is dynmically allocated + * as necessary. */ - const struct glsl_type *type; + inline unsigned *get_max_ifc_array_access() + { + assert(this->data._num_state_slots == 0); + return this->u.max_ifc_array_access; + } - /** - * Declared name of the variable - */ - const char *name; + inline unsigned get_num_state_slots() const + { + assert(!this->is_interface_instance() + || this->data._num_state_slots == 0); + return this->data._num_state_slots; + } - /** - * Highest element accessed with a constant expression array index - * - * Not used for non-array variables. - */ - unsigned max_array_access; + inline void set_num_state_slots(unsigned n) + { + assert(!this->is_interface_instance() + || n == 0); + this->data._num_state_slots = n; + } - /** - * For variables which satisfy the is_interface_instance() predicate, this - * points to an array of integers such that if the ith member of the - * interface block is an array, max_ifc_array_access[i] is the maximum - * array element of that member that has been accessed. If the ith member - * of the interface block is not an array, max_ifc_array_access[i] is - * unused. - * - * For variables whose type is not an interface block, this pointer is - * NULL. - */ - unsigned *max_ifc_array_access; + inline ir_state_slot *get_state_slots() + { + return this->is_interface_instance() ? NULL : this->u.state_slots; + } - /** - * Is the variable read-only? - * - * This is set for variables declared as \c const, shader inputs, - * and uniforms. - */ - unsigned read_only:1; - unsigned centroid:1; - unsigned invariant:1; + inline const ir_state_slot *get_state_slots() const + { + return this->is_interface_instance() ? NULL : this->u.state_slots; + } - /** - * Has this variable been used for reading or writing? - * - * Several GLSL semantic checks require knowledge of whether or not a - * 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. - */ - unsigned used:1; + inline ir_state_slot *allocate_state_slots(unsigned n) + { + assert(!this->is_interface_instance()); - /** - * Has this variable been statically assigned? - * - * This answers whether the variable was assigned in any path of - * the shader during ast_to_hir. This doesn't answer whether it is - * still written after dead code removal, nor is it maintained in - * non-ast_to_hir.cpp (GLSL parsing) paths. - */ - unsigned assigned:1; + this->u.state_slots = ralloc_array(this, ir_state_slot, n); + this->data._num_state_slots = 0; - /** - * Storage class of the variable. - * - * \sa ir_variable_mode - */ - unsigned mode:4; + if (this->u.state_slots != NULL) + this->data._num_state_slots = n; - /** - * Interpolation mode for shader inputs / outputs - * - * \sa ir_variable_interpolation - */ - unsigned interpolation:2; + return this->u.state_slots; + } - /** - * \name ARB_fragment_coord_conventions - * @{ - */ - unsigned origin_upper_left:1; - unsigned pixel_center_integer:1; - /*@}*/ + inline bool is_name_ralloced() const + { + return this->name != ir_variable::tmp_name; + } /** - * Was the location explicitly set in the shader? - * - * If the location is explicitly set in the shader, it \b cannot be changed - * by the linker or by the API (e.g., calls to \c glBindAttribLocation have - * no effect). + * Enable emitting extension warnings for this variable */ - unsigned explicit_location:1; - unsigned explicit_index:1; + void enable_extension_warning(const char *extension); /** - * Was an initial binding explicitly set in the shader? + * Get the extension warning string for this variable * - * If so, constant_value contains an integer ir_constant representing the - * initial binding point. + * If warnings are not enabled, \c NULL is returned. */ - unsigned explicit_binding:1; + const char *get_extension_warning() const; /** - * Does this variable have an initializer? - * - * This is used by the linker to cross-validiate initializers of global - * variables. + * Declared type of the variable */ - unsigned has_initializer:1; + const struct glsl_type *type; /** - * Is this variable a generic output or input that has not yet been matched - * up to a variable in another stage of the pipeline? - * - * This is used by the linker as scratch storage while assigning locations - * to generic inputs and outputs. + * Declared name of the variable */ - unsigned is_unmatched_generic_inout:1; + const char *name; - /** - * If non-zero, then this variable may be packed along with other variables - * into a single varying slot, so this offset should be applied when - * accessing components. For example, an offset of 1 means that the x - * component of this variable is actually stored in component y of the - * location specified by \c location. - */ - unsigned location_frac:2; + struct ir_variable_data { - /** - * \brief Layout qualifier for gl_FragDepth. - * - * This is not equal to \c ir_depth_layout_none if and only if this - * variable is \c gl_FragDepth and a layout qualifier is specified. - */ - ir_depth_layout depth_layout; + /** + * Is the variable read-only? + * + * This is set for variables declared as \c const, shader inputs, + * and uniforms. + */ + unsigned read_only:1; + unsigned centroid:1; + unsigned sample:1; + unsigned patch:1; + unsigned invariant:1; + unsigned precise:1; + + /** + * Has this variable been used for reading or writing? + * + * Several GLSL semantic checks require knowledge of whether or not a + * 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. + */ + unsigned used:1; + + /** + * Has this variable been statically assigned? + * + * This answers whether the variable was assigned in any path of + * the shader during ast_to_hir. This doesn't answer whether it is + * still written after dead code removal, nor is it maintained in + * non-ast_to_hir.cpp (GLSL parsing) paths. + */ + unsigned assigned:1; - /** - * Storage location of the base of this variable - * - * The precise meaning of this field depends on the nature of the variable. - * - * - Vertex shader input: one of the values from \c gl_vert_attrib. - * - Vertex shader output: one of the values from \c gl_varying_slot. - * - Geometry shader input: one of the values from \c gl_varying_slot. - * - Geometry shader output: one of the values from \c gl_varying_slot. - * - Fragment shader input: one of the values from \c gl_varying_slot. - * - Fragment shader output: one of the values from \c gl_frag_result. - * - Uniforms: Per-stage uniform slot number for default uniform block. - * - Uniforms: Index within the uniform block definition for UBO members. - * - Other: This field is not currently used. - * - * If the variable is a uniform, shader input, or shader output, and the - * slot has not been assigned, the value will be -1. - */ - int location; + /** + * Enum indicating how the variable was declared. See + * ir_var_declaration_type. + * + * This is used to detect certain kinds of illegal variable redeclarations. + */ + unsigned how_declared:2; - /** - * output index for dual source blending. - */ - int index; + /** + * Storage class of the variable. + * + * \sa ir_variable_mode + */ + unsigned mode:4; - /** - * Initial binding point for a sampler or UBO. - * - * For array types, this represents the binding point for the first element. - */ - int binding; + /** + * Interpolation mode for shader inputs / outputs + * + * \sa ir_variable_interpolation + */ + unsigned interpolation:2; - /** - * Built-in state that backs this uniform - * - * Once set at variable creation, \c state_slots must remain invariant. - * This is because, ideally, this array would be shared by all clones of - * this variable in the IR tree. In other words, we'd really like for it - * to be a fly-weight. - * - * If the variable is not a uniform, \c num_state_slots will be zero and - * \c state_slots will be \c NULL. - */ - /*@{*/ - unsigned num_state_slots; /**< Number of state slots used */ - ir_state_slot *state_slots; /**< State descriptors. */ - /*@}*/ + /** + * \name ARB_fragment_coord_conventions + * @{ + */ + unsigned origin_upper_left:1; + unsigned pixel_center_integer:1; + /*@}*/ + + /** + * Was the location explicitly set in the shader? + * + * If the location is explicitly set in the shader, it \b cannot be changed + * by the linker or by the API (e.g., calls to \c glBindAttribLocation have + * no effect). + */ + unsigned explicit_location:1; + unsigned explicit_index:1; + + /** + * Was an initial binding explicitly set in the shader? + * + * If so, constant_value contains an integer ir_constant representing the + * initial binding point. + */ + unsigned explicit_binding:1; - /** - * Emit a warning if this variable is accessed. - */ - const char *warn_extension; + /** + * Does this variable have an initializer? + * + * This is used by the linker to cross-validiate initializers of global + * variables. + */ + unsigned has_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? + * + * This is used by the linker as scratch storage while assigning locations + * to generic inputs and outputs. + */ + unsigned is_unmatched_generic_inout:1; + + /** + * If non-zero, then this variable may be packed along with other variables + * into a single varying slot, so this offset should be applied when + * accessing components. For example, an offset of 1 means that the x + * component of this variable is actually stored in component y of the + * location specified by \c location. + */ + unsigned location_frac:2; + + /** + * Layout of the matrix. Uses glsl_matrix_layout values. + */ + unsigned matrix_layout:2; + + /** + * Non-zero if this variable was created by lowering a named interface + * block which was not an array. + * + * Note that this variable and \c from_named_ifc_block_array will never + * both be non-zero. + */ + unsigned from_named_ifc_block_nonarray:1; + + /** + * Non-zero if this variable was created by lowering a named interface + * block which was an array. + * + * Note that this variable and \c from_named_ifc_block_nonarray will never + * both be non-zero. + */ + unsigned from_named_ifc_block_array:1; + + /** + * Non-zero if the variable must be a shader input. This is useful for + * constraints on function parameters. + */ + unsigned must_be_shader_input:1; + + /** + * Output index for dual source blending. + * + * \note + * The GLSL spec only allows the values 0 or 1 for the index in \b dual + * source blending. + */ + unsigned index:1; + + /** + * Precision qualifier. + * + * In desktop GLSL we do not care about precision qualifiers at all, in + * fact, the spec says that precision qualifiers are ignored. + * + * To make things easy, we make it so that this field is always + * GLSL_PRECISION_NONE on desktop shaders. This way all the variables + * have the same precision value and the checks we add in the compiler + * for this field will never break a desktop shader compile. + */ + unsigned precision:2; + + /** + * \brief Layout qualifier for gl_FragDepth. + * + * This is not equal to \c ir_depth_layout_none if and only if this + * variable is \c gl_FragDepth and a layout qualifier is specified. + */ + ir_depth_layout depth_layout:3; + + /** + * ARB_shader_image_load_store 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; + + /** + * ARB_shader_storage_buffer_object + */ + unsigned from_ssbo_unsized_array:1; /**< unsized array buffer variable. */ + + /** + * Emit a warning if this variable is accessed. + */ + private: + uint8_t warn_extension_index; + + public: + /** Image internal format if specified explicitly, otherwise GL_NONE. */ + uint16_t image_format; + + private: + /** + * Number of state slots used + * + * \note + * This could be stored in as few as 7-bits, if necessary. If it is made + * smaller, add an assertion to \c ir_variable::allocate_state_slots to + * be safe. + */ + uint16_t _num_state_slots; + + public: + /** + * Initial binding point for a sampler, atomic, or UBO. + * + * For array types, this represents the binding point for the first element. + */ + int16_t binding; + + /** + * Storage location of the base of this variable + * + * The precise meaning of this field depends on the nature of the variable. + * + * - Vertex shader input: one of the values from \c gl_vert_attrib. + * - Vertex shader output: one of the values from \c gl_varying_slot. + * - Geometry shader input: one of the values from \c gl_varying_slot. + * - Geometry shader output: one of the values from \c gl_varying_slot. + * - Fragment shader input: one of the values from \c gl_varying_slot. + * - Fragment shader output: one of the values from \c gl_frag_result. + * - Uniforms: Per-stage uniform slot number for default uniform block. + * - Uniforms: Index within the uniform block definition for UBO members. + * - Non-UBO Uniforms: explicit location until linking then reused to + * store uniform slot number. + * - Other: This field is not currently used. + * + * If the variable is a uniform, shader input, or shader output, and the + * slot has not been assigned, the value will be -1. + */ + int location; + + /** + * Vertex stream output identifier. + */ + unsigned stream; + + /** + * Location an atomic counter is stored at. + */ + struct { + unsigned offset; + } atomic; + + /** + * Highest element accessed with a constant expression array index + * + * Not used for non-array variables. + */ + unsigned max_array_access; + + /** + * Allow (only) ir_variable direct access private members. + */ + friend class ir_variable; + } data; /** * Value assigned in the initializer of a variable declared "const" @@ -657,6 +897,33 @@ public: ir_constant *constant_initializer; private: + static const char *const warn_extension_table[]; + + union { + /** + * For variables which satisfy the is_interface_instance() predicate, + * this points to an array of integers such that if the ith member of + * the interface block is an array, max_ifc_array_access[i] is the + * maximum array element of that member that has been accessed. If the + * ith member of the interface block is not an array, + * max_ifc_array_access[i] is unused. + * + * For variables whose type is not an interface block, this pointer is + * NULL. + */ + unsigned *max_ifc_array_access; + + /** + * Built-in state that backs this uniform + * + * Once set at variable creation, \c state_slots must remain invariant. + * + * If the variable is not a uniform, \c _num_state_slots will be zero + * and \c state_slots will be \c NULL. + */ + ir_state_slot *state_slots; + } u; + /** * For variables that are in an interface block or are an instance of an * interface block, this is the \c GLSL_TYPE_INTERFACE type for that block. @@ -664,6 +931,30 @@ private: * \sa ir_variable::location */ const glsl_type *interface_type; + + /** + * Name used for anonymous compiler temporaries + */ + static const char tmp_name[]; + +public: + /** + * Should the construct keep names for ir_var_temporary variables? + * + * When this global is false, names passed to the constructor for + * \c ir_var_temporary variables will be dropped. Instead, the variable will + * be named "compiler_temp". This name will be in static storage. + * + * \warning + * \b NEVER change the mode of an \c ir_var_temporary. + * + * \warning + * This variable is \b not thread-safe. It is global, \b not + * per-context. It begins life false. A context can, at some point, make + * it true. From that point on, it will be true forever. This should be + * okay since it will only be set true while debugging. + */ + static bool temporaries_allocate_names; }; /** @@ -761,6 +1052,12 @@ public: /** Whether or not this function signature is a built-in. */ bool is_builtin() const; + /** + * Whether or not this function is an intrinsic to be implemented + * by the driver. + */ + bool is_intrinsic; + /** Whether or not a built-in is available for this shader. */ bool is_builtin_available(const _mesa_glsl_parse_state *state) const; @@ -810,11 +1107,6 @@ public: virtual ir_function *clone(void *mem_ctx, struct hash_table *ht) const; - virtual ir_function *as_function() - { - return this; - } - virtual void accept(ir_visitor *v) { v->visit(this); @@ -828,20 +1120,13 @@ public: this->signatures.push_tail(sig); } - /** - * Get an iterator for the set of function signatures - */ - exec_list_iterator iterator() - { - return signatures.iterator(); - } - /** * Find a signature that matches a set of actual parameters, taking implicit * conversions into account. Also flags whether the match was exact. */ ir_function_signature *matching_signature(_mesa_glsl_parse_state *state, const exec_list *actual_param, + bool allow_builtins, bool *match_is_exact); /** @@ -849,7 +1134,8 @@ public: * conversions into account. */ ir_function_signature *matching_signature(_mesa_glsl_parse_state *state, - const exec_list *actual_param); + const exec_list *actual_param, + bool allow_builtins); /** * Find a signature that exactly matches a set of actual parameters without @@ -870,6 +1156,23 @@ public: * List of ir_function_signature for each overloaded function with this name. */ struct exec_list signatures; + + /** + * is this function a subroutine type declaration + * e.g. subroutine void type1(float arg1); + */ + bool is_subroutine; + + /** + * is this function associated to a subroutine type + * e.g. subroutine (type1, type2) function_name { function_body }; + * would have num_subroutine_types 2, + * and pointers to the type1 and type2 types. + */ + int num_subroutine_types; + const struct glsl_type **subroutine_types; + + int subroutine_index; }; inline const char *ir_function_signature::function_name() const @@ -885,18 +1188,12 @@ inline const char *ir_function_signature::function_name() const class ir_if : public ir_instruction { public: ir_if(ir_rvalue *condition) - : condition(condition) + : ir_instruction(ir_type_if), condition(condition) { - ir_type = ir_type_if; } virtual ir_if *clone(void *mem_ctx, struct hash_table *ht) const; - virtual ir_if *as_if() - { - return this; - } - virtual void accept(ir_visitor *v) { v->visit(this); @@ -928,49 +1225,8 @@ public: 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 - */ - exec_list_iterator iterator() - { - return body_instructions.iterator(); - } - /** List of ir_instruction that make up the body of the loop. */ exec_list body_instructions; - - /** - * \name Loop counter and controls - * - * Represents a loop like a FORTRAN \c do-loop. - * - * \note - * If \c from and \c to are the same value, the loop will execute once. - */ - /*@{*/ - ir_rvalue *from; /** Value of the loop counter on the first - * iteration of the loop. - */ - ir_rvalue *to; /** Value of the loop counter on the last - * iteration of the loop. - */ - ir_rvalue *increment; - ir_variable *counter; - - /** - * Comparison operation in the loop terminator. - * - * If any of the loop control fields are non-\c NULL, this field must be - * one of \c ir_binop_less, \c ir_binop_greater, \c ir_binop_lequal, - * \c ir_binop_gequal, \c ir_binop_equal, or \c ir_binop_nequal. - */ - int cmp; - /*@}*/ }; @@ -999,11 +1255,6 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); - virtual ir_assignment * as_assignment() - { - return this; - } - /** * Get a whole variable written by an assignment * @@ -1086,6 +1337,13 @@ enum ir_expression_operation { ir_unop_u2f, /**< Unsigned-to-float conversion. */ ir_unop_i2u, /**< Integer-to-unsigned conversion. */ ir_unop_u2i, /**< Unsigned-to-integer conversion. */ + ir_unop_d2f, /**< Double-to-float conversion. */ + ir_unop_f2d, /**< Float-to-double conversion. */ + ir_unop_d2i, /**< Double-to-integer conversion. */ + ir_unop_i2d, /**< Integer-to-double conversion. */ + ir_unop_d2u, /**< Double-to-unsigned conversion. */ + ir_unop_u2d, /**< Unsigned-to-double conversion. */ + ir_unop_d2b, /**< Double-to-boolean conversion. */ ir_unop_bitcast_i2f, /**< Bit-identical int-to-float "conversion" */ ir_unop_bitcast_f2i, /**< Bit-identical float-to-int "conversion" */ ir_unop_bitcast_u2f, /**< Bit-identical uint-to-float "conversion" */ @@ -1109,8 +1367,6 @@ enum ir_expression_operation { /*@{*/ ir_unop_sin, ir_unop_cos, - ir_unop_sin_reduced, /**< Reduced range sin. [-pi, pi] */ - ir_unop_cos_reduced, /**< Reduced range cos. [-pi, pi] */ /*@}*/ /** @@ -1118,7 +1374,11 @@ enum ir_expression_operation { */ /*@{*/ ir_unop_dFdx, + ir_unop_dFdx_coarse, + ir_unop_dFdx_fine, ir_unop_dFdy, + ir_unop_dFdy_coarse, + ir_unop_dFdy_fine, /*@}*/ /** @@ -1157,12 +1417,50 @@ enum ir_expression_operation { ir_unop_find_lsb, /*@}*/ + ir_unop_saturate, + + /** + * \name Double packing, part of ARB_gpu_shader_fp64. + */ + /*@{*/ + ir_unop_pack_double_2x32, + ir_unop_unpack_double_2x32, + /*@}*/ + + ir_unop_frexp_sig, + ir_unop_frexp_exp, + ir_unop_noise, + ir_unop_subroutine_to_int, + /** + * Interpolate fs input at centroid + * + * operand0 is the fs input. + */ + ir_unop_interpolate_at_centroid, + + /** + * Ask the driver for the total size of a buffer block. + * + * operand0 is the ir_constant buffer block index in the linked shader. + */ + ir_unop_get_buffer_size, + + /** + * Calculate length of an unsized array inside a buffer block. + * This opcode is going to be replaced in a lowering pass inside + * the linker. + * + * operand0 is the unsized array's ir_value for the calculation + * of its length. + */ + ir_unop_ssbo_unsized_array_length, + /** * A sentinel marking the last of the unary operations. */ - ir_last_unop = ir_unop_noise, + ir_last_unop = ir_unop_ssbo_unsized_array_length, ir_binop_add, ir_binop_sub, @@ -1280,10 +1578,26 @@ enum ir_expression_operation { */ ir_binop_vector_extract, + /** + * Interpolate fs input at offset + * + * operand0 is the fs input + * operand1 is the offset from the pixel center + */ + ir_binop_interpolate_at_offset, + + /** + * Interpolate fs input at sample position + * + * operand0 is the fs input + * operand1 is the sample ID + */ + ir_binop_interpolate_at_sample, + /** * A sentinel marking the last of the binary operations. */ - ir_last_binop = ir_binop_vector_extract, + ir_last_binop = ir_binop_interpolate_at_sample, /** * \name Fused floating-point multiply-add, part of ARB_gpu_shader5. @@ -1367,10 +1681,8 @@ public: */ ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1, ir_rvalue *op2); - virtual ir_expression *as_expression() - { - return this; - } + virtual bool equals(const ir_instruction *ir, + enum ir_node_type ignore = ir_type_unset) const; virtual ir_expression *clone(void *mem_ctx, struct hash_table *ht) const; @@ -1400,6 +1712,18 @@ public: ? this->type->vector_elements : get_num_operands(operation); } + /** + * Return whether the expression operates on vectors horizontally. + */ + bool is_horizontal() const + { + return operation == ir_binop_all_equal || + operation == ir_binop_any_nequal || + operation == ir_unop_any || + operation == ir_binop_dot || + operation == ir_quadop_vector; + } + /** * Return a string representing this expression's operator. */ @@ -1423,6 +1747,8 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); + virtual ir_variable *variable_referenced() const; + ir_expression_operation operation; ir_rvalue *operands[4]; }; @@ -1437,9 +1763,19 @@ public: ir_call(ir_function_signature *callee, ir_dereference_variable *return_deref, exec_list *actual_parameters) - : return_deref(return_deref), callee(callee) + : ir_instruction(ir_type_call), return_deref(return_deref), callee(callee), sub_var(NULL), array_idx(NULL) + { + 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, + ir_dereference_variable *return_deref, + exec_list *actual_parameters, + ir_variable *var, ir_rvalue *array_idx) + : ir_instruction(ir_type_call), return_deref(return_deref), callee(callee), sub_var(var), array_idx(array_idx) { - ir_type = ir_type_call; assert(callee->return_type != NULL); actual_parameters->move_nodes_to(& this->actual_parameters); this->use_builtin = callee->is_builtin(); @@ -1449,11 +1785,6 @@ public: virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL); - virtual ir_call *as_call() - { - return this; - } - virtual void accept(ir_visitor *v) { v->visit(this); @@ -1461,14 +1792,6 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); - /** - * Get an iterator for the set of acutal parameters - */ - exec_list_iterator iterator() - { - return actual_parameters.iterator(); - } - /** * Get the name of the function being called. */ @@ -1499,6 +1822,14 @@ public: /** Should this call only bind to a built-in function? */ bool use_builtin; + + /* + * ARB_shader_subroutine support - + * the subroutine uniform variable and array index + * rvalue to be used in the lowering pass later. + */ + ir_variable *sub_var; + ir_rvalue *array_idx; }; @@ -1510,39 +1841,26 @@ public: /*@{*/ class ir_jump : public ir_instruction { protected: - ir_jump() + ir_jump(enum ir_node_type t) + : ir_instruction(t) { - ir_type = ir_type_unset; - } - -public: - virtual ir_jump *as_jump() - { - return this; } }; class ir_return : public ir_jump { public: ir_return() - : value(NULL) + : ir_jump(ir_type_return), value(NULL) { - this->ir_type = ir_type_return; } ir_return(ir_rvalue *value) - : value(value) + : ir_jump(ir_type_return), value(value) { - this->ir_type = ir_type_return; } virtual ir_return *clone(void *mem_ctx, struct hash_table *) const; - virtual ir_return *as_return() - { - return this; - } - ir_rvalue *get_value() const { return value; @@ -1575,8 +1893,8 @@ public: }; ir_loop_jump(jump_mode mode) + : ir_jump(ir_type_loop_jump) { - this->ir_type = ir_type_loop_jump; this->mode = mode; } @@ -1609,14 +1927,14 @@ public: class ir_discard : public ir_jump { public: ir_discard() + : ir_jump(ir_type_discard) { - this->ir_type = ir_type_discard; this->condition = NULL; } ir_discard(ir_rvalue *cond) + : ir_jump(ir_type_discard) { - this->ir_type = ir_type_discard; this->condition = cond; } @@ -1629,11 +1947,6 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); - virtual ir_discard *as_discard() - { - return this; - } - ir_rvalue *condition; }; /*@}*/ @@ -1652,7 +1965,9 @@ enum ir_texture_opcode { ir_txs, /**< Texture size */ ir_lod, /**< Texture lod query */ ir_tg4, /**< Texture gather */ - ir_query_levels /**< Texture levels query */ + ir_query_levels, /**< Texture levels query */ + ir_texture_samples, /**< Texture samples query */ + ir_samples_identical, /**< Query whether all samples are definitely identical. */ }; @@ -1679,14 +1994,15 @@ enum ir_texture_opcode { * (lod ) * (tg4 ) * (query_levels ) + * (samples_identical ) */ class ir_texture : public ir_rvalue { public: ir_texture(enum ir_texture_opcode op) - : op(op), sampler(NULL), coordinate(NULL), projector(NULL), + : ir_rvalue(ir_type_texture), + op(op), sampler(NULL), coordinate(NULL), projector(NULL), shadow_comparitor(NULL), offset(NULL) { - this->ir_type = ir_type_texture; memset(&lod_info, 0, sizeof(lod_info)); } @@ -1701,6 +2017,9 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); + virtual bool equals(const ir_instruction *ir, + enum ir_node_type ignore = ir_type_unset) const; + /** * Return a string representing the ir_texture_opcode. */ @@ -1788,11 +2107,6 @@ public: virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL); - virtual ir_swizzle *as_swizzle() - { - return this; - } - /** * Construct an ir_swizzle from the textual representation. Can fail. */ @@ -1805,6 +2119,9 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); + virtual bool equals(const ir_instruction *ir, + enum ir_node_type ignore = ir_type_unset) const; + bool is_lvalue() const { return val->is_lvalue() && !mask.has_duplicates; @@ -1832,11 +2149,6 @@ class ir_dereference : public ir_rvalue { public: virtual ir_dereference *clone(void *mem_ctx, struct hash_table *) const = 0; - virtual ir_dereference *as_dereference() - { - return this; - } - bool is_lvalue() const; /** @@ -1844,14 +2156,11 @@ public: */ virtual ir_variable *variable_referenced() const = 0; - /** - * Get the constant that is ultimately referenced by an r-value, - * in a constant expression evaluation context. - * - * The offset is used when the reference is to a specific column of - * a matrix. - */ - virtual void constant_referenced(struct hash_table *variable_context, ir_constant *&store, int &offset) const = 0; +protected: + ir_dereference(enum ir_node_type t) + : ir_rvalue(t) + { + } }; @@ -1864,10 +2173,8 @@ public: virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL); - virtual ir_dereference_variable *as_dereference_variable() - { - return this; - } + virtual bool equals(const ir_instruction *ir, + enum ir_node_type ignore = ir_type_unset) const; /** * Get the variable that is ultimately referenced by an r-value @@ -1877,15 +2184,6 @@ public: return this->var; } - /** - * Get the constant that is ultimately referenced by an r-value, - * in a constant expression evaluation context. - * - * The offset is used when the reference is to a specific column of - * a matrix. - */ - virtual void constant_referenced(struct hash_table *variable_context, ir_constant *&store, int &offset) const; - virtual ir_variable *whole_variable_referenced() { /* ir_dereference_variable objects always dereference the entire @@ -1922,10 +2220,8 @@ public: virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL); - virtual ir_dereference_array *as_dereference_array() - { - return this; - } + virtual bool equals(const ir_instruction *ir, + enum ir_node_type ignore = ir_type_unset) const; /** * Get the variable that is ultimately referenced by an r-value @@ -1935,15 +2231,6 @@ public: return this->array->variable_referenced(); } - /** - * Get the constant that is ultimately referenced by an r-value, - * in a constant expression evaluation context. - * - * The offset is used when the reference is to a specific column of - * a matrix. - */ - virtual void constant_referenced(struct hash_table *variable_context, ir_constant *&store, int &offset) const; - virtual void accept(ir_visitor *v) { v->visit(this); @@ -1970,11 +2257,6 @@ public: virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL); - virtual ir_dereference_record *as_dereference_record() - { - return this; - } - /** * Get the variable that is ultimately referenced by an r-value */ @@ -1983,15 +2265,6 @@ public: return this->record->variable_referenced(); } - /** - * Get the constant that is ultimately referenced by an r-value, - * in a constant expression evaluation context. - * - * The offset is used when the reference is to a specific column of - * a matrix. - */ - virtual void constant_referenced(struct hash_table *variable_context, ir_constant *&store, int &offset) const; - virtual void accept(ir_visitor *v) { v->visit(this); @@ -2012,6 +2285,7 @@ union ir_constant_data { int i[16]; float f[16]; bool b[16]; + double d[16]; }; @@ -2022,6 +2296,7 @@ public: ir_constant(unsigned int u, unsigned vector_elements=1); ir_constant(int i, unsigned vector_elements=1); ir_constant(float f, unsigned vector_elements=1); + ir_constant(double d, unsigned vector_elements=1); /** * Construct an ir_constant from a list of ir_constant values @@ -2049,11 +2324,6 @@ public: virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL); - virtual ir_constant *as_constant() - { - return this; - } - virtual void accept(ir_visitor *v) { v->visit(this); @@ -2061,6 +2331,9 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); + virtual bool equals(const ir_instruction *ir, + enum ir_node_type ignore = ir_type_unset) const; + /** * Get a particular component of a constant as a specific type * @@ -2071,6 +2344,7 @@ public: /*@{*/ bool get_bool_component(unsigned i) const; float get_float_component(unsigned i) const; + double get_double_component(unsigned i) const; int get_int_component(unsigned i) const; unsigned get_uint_component(unsigned i) const; /*@}*/ @@ -2108,14 +2382,27 @@ public: * Determine whether a constant has the same value as another constant * * \sa ir_constant::is_zero, ir_constant::is_one, - * ir_constant::is_negative_one, ir_constant::is_basis + * ir_constant::is_negative_one */ bool has_value(const ir_constant *) const; + /** + * Return true if this ir_constant represents the given value. + * + * For vectors, this checks that each component is the given value. + */ + virtual bool is_value(float f, int i) const; virtual bool is_zero() const; virtual bool is_one() const; virtual bool is_negative_one() const; - virtual bool is_basis() const; + + /** + * Return true for constants that could be stored as 16-bit unsigned values. + * + * Note that this will return true even for signed integer ir_constants, as + * long as the value is non-negative and fits in 16-bits. + */ + virtual bool is_uint16_constant() const; /** * Value of the constant. @@ -2139,16 +2426,16 @@ private: ir_constant(void); }; -/*@}*/ - /** * IR instruction to emit a vertex in a geometry shader. */ class ir_emit_vertex : public ir_instruction { public: - ir_emit_vertex() + ir_emit_vertex(ir_rvalue *stream) + : ir_instruction(ir_type_emit_vertex), + stream(stream) { - ir_type = ir_type_emit_vertex; + assert(stream); } virtual void accept(ir_visitor *v) @@ -2156,12 +2443,19 @@ public: v->visit(this); } - virtual ir_emit_vertex *clone(void *mem_ctx, struct hash_table *) const + virtual ir_emit_vertex *clone(void *mem_ctx, struct hash_table *ht) const { - return new(mem_ctx) ir_emit_vertex(); + return new(mem_ctx) ir_emit_vertex(this->stream->clone(mem_ctx, ht)); } virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + int stream_id() const + { + return stream->as_constant()->value.i[0]; + } + + ir_rvalue *stream; }; /** @@ -2170,9 +2464,11 @@ public: */ class ir_end_primitive : public ir_instruction { public: - ir_end_primitive() + ir_end_primitive(ir_rvalue *stream) + : ir_instruction(ir_type_end_primitive), + stream(stream) { - ir_type = ir_type_end_primitive; + assert(stream); } virtual void accept(ir_visitor *v) @@ -2180,14 +2476,46 @@ public: v->visit(this); } - virtual ir_end_primitive *clone(void *mem_ctx, struct hash_table *) const + virtual ir_end_primitive *clone(void *mem_ctx, struct hash_table *ht) const { - return new(mem_ctx) ir_end_primitive(); + return new(mem_ctx) ir_end_primitive(this->stream->clone(mem_ctx, ht)); } virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + int stream_id() const + { + return stream->as_constant()->value.i[0]; + } + + ir_rvalue *stream; }; +/** + * IR instruction for tessellation control and compute shader barrier. + */ +class ir_barrier : public ir_instruction { +public: + ir_barrier() + : ir_instruction(ir_type_barrier) + { + } + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } + + virtual ir_barrier *clone(void *mem_ctx, struct hash_table *) const + { + return new(mem_ctx) ir_barrier(); + } + + virtual ir_visitor_status accept(ir_hierarchical_visitor *); +}; + +/*@}*/ + /** * Apply a visitor to each IR node in a list */ @@ -2238,6 +2566,9 @@ extern void _mesa_glsl_initialize_variables(exec_list *instructions, struct _mesa_glsl_parse_state *state); +extern void +_mesa_glsl_initialize_derived_variables(gl_shader *shader); + extern void _mesa_glsl_initialize_functions(_mesa_glsl_parse_state *state); @@ -2248,6 +2579,15 @@ 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(gl_shader *sh); + extern void _mesa_glsl_release_functions(void); @@ -2268,18 +2608,33 @@ ir_has_call(ir_instruction *ir); extern void do_set_program_inouts(exec_list *instructions, struct gl_program *prog, - GLenum shader_type); + gl_shader_stage shader_stage); extern char * prototype_string(const glsl_type *return_type, const char *name, exec_list *parameters); +const char * +mode_string(const ir_variable *var); + +/** + * Built-in / reserved GL variables names start with "gl_" + */ +static inline bool +is_gl_identifier(const char *s) +{ + return s && s[0] == 'g' && s[1] == 'l' && s[2] == '_'; +} + extern "C" { #endif /* __cplusplus */ -extern void _mesa_print_ir(struct exec_list *instructions, +extern void _mesa_print_ir(FILE *f, struct exec_list *instructions, struct _mesa_glsl_parse_state *state); +extern void +fprint_ir(FILE *f, const void *instruction); + #ifdef __cplusplus } /* extern "C" */ #endif