#include <stdio.h>
#include <stdlib.h>
-#include "ralloc.h"
+#include "util/ralloc.h"
#include "glsl_types.h"
#include "list.h"
#include "ir_visitor.h"
ir_type_discard,
ir_type_emit_vertex,
ir_type_end_primitive,
+ ir_type_barrier,
ir_type_max, /**< maximum ir_type enum number, for validation */
ir_type_unset = ir_type_max
};
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
*
* Additional downcast functions will be added as needed.
*/
/*@{*/
- class ir_rvalue *as_rvalue()
- {
- if (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)
- return (class ir_rvalue *) this;
- return NULL;
- }
-
- class ir_dereference *as_dereference()
- {
- if (ir_type == ir_type_dereference_array ||
- ir_type == ir_type_dereference_record ||
- ir_type == ir_type_dereference_variable)
- return (class ir_dereference *) this;
- return NULL;
- }
-
- class ir_jump *as_jump()
- {
- if (ir_type == ir_type_loop_jump ||
- ir_type == ir_type_return ||
- ir_type == ir_type_discard)
- return (class ir_jump *) this;
- 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)
* in particular. No support for other instruction types (assignments,
* jumps, calls, etc.) is planned.
*/
- virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+ virtual bool equals(const ir_instruction *ir,
+ enum ir_node_type ignore = ir_type_unset) const;
protected:
ir_instruction(enum ir_node_type t)
* 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;
* 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;
* 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
- *
- * 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
- */
- virtual bool is_basis() const;
-
/**
* Determine if an r-value is an unsigned integer constant which can be
* stored in 16 bits.
enum ir_variable_mode {
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_in,
ir_var_shader_out,
ir_var_function_in,
* 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,
};
/**
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->data.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;
}
/**
*/
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.
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);
}
}
*/
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.
*/
*/
void reinit_interface_type(const struct glsl_type *type)
{
- if (this->max_ifc_array_access != NULL) {
+ 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
* 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);
}
/**
- * 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;
+ }
+
+ inline unsigned get_num_state_slots() const
+ {
+ assert(!this->is_interface_instance()
+ || this->data._num_state_slots == 0);
+ return this->data._num_state_slots;
+ }
+
+ inline void set_num_state_slots(unsigned n)
+ {
+ assert(!this->is_interface_instance()
+ || n == 0);
+ this->data._num_state_slots = n;
+ }
+
+ inline ir_state_slot *get_state_slots()
+ {
+ return this->is_interface_instance() ? NULL : this->u.state_slots;
+ }
+
+ inline const ir_state_slot *get_state_slots() const
+ {
+ return this->is_interface_instance() ? NULL : this->u.state_slots;
+ }
+
+ inline ir_state_slot *allocate_state_slots(unsigned n)
+ {
+ assert(!this->is_interface_instance());
+
+ this->u.state_slots = ralloc_array(this, ir_state_slot, n);
+ this->data._num_state_slots = 0;
+
+ if (this->u.state_slots != NULL)
+ this->data._num_state_slots = n;
+
+ return this->u.state_slots;
+ }
+
+ inline bool is_name_ralloced() const
+ {
+ return this->name != ir_variable::tmp_name;
+ }
/**
- * Declared name of the variable
+ * Enable emitting extension warnings for this variable
*/
- const char *name;
+ void enable_extension_warning(const char *extension);
/**
- * 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.
+ * Get the extension warning string for this variable
*
- * For variables whose type is not an interface block, this pointer is
- * NULL.
+ * If warnings are not enabled, \c NULL is returned.
*/
- unsigned *max_ifc_array_access;
+ const char *get_extension_warning() const;
+
+ /**
+ * Declared type of the variable
+ */
+ const struct glsl_type *type;
+
+ /**
+ * Declared name of the variable
+ */
+ const char *name;
struct ir_variable_data {
unsigned read_only:1;
unsigned centroid:1;
unsigned sample:1;
+ unsigned patch:1;
unsigned invariant:1;
unsigned precise:1;
*/
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.
*/
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;
+
/**
* \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;
+ 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;
+
+ /**
+ * 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
*/
unsigned stream;
- /**
- * output index for dual source blending.
- */
- int index;
-
- /**
- * Initial binding point for a sampler or UBO.
- *
- * For array types, this represents the binding point for the first element.
- */
- int binding;
-
/**
* Location an atomic counter is stored at.
*/
struct {
- unsigned buffer_index;
unsigned offset;
} atomic;
- /**
- * ARB_shader_image_load_store qualifiers.
- */
- struct {
- bool read_only; /**< "readonly" qualifier. */
- bool write_only; /**< "writeonly" qualifier. */
- bool coherent;
- bool _volatile;
- bool restrict_flag;
-
- /** Image internal format if specified explicitly, otherwise GL_NONE. */
- GLenum format;
- } image;
-
/**
* Highest element accessed with a constant expression array index
*
*/
unsigned max_array_access;
+ /**
+ * Allow (only) ir_variable direct access private members.
+ */
+ friend class ir_variable;
} data;
- /**
- * 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. */
- /*@}*/
-
- /**
- * Emit a warning if this variable is accessed.
- */
- const char *warn_extension;
-
/**
* Value assigned in the initializer of a variable declared "const"
*/
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.
* \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;
};
/**
*/
ir_function_signature *matching_signature(_mesa_glsl_parse_state *state,
const exec_list *actual_param,
+ bool allow_builtins,
bool *match_is_exact);
/**
* 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
* 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;
};
inline const char *ir_function_signature::function_name() const
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" */
/*@{*/
ir_unop_sin,
ir_unop_cos,
- ir_unop_sin_reduced, /**< Reduced range sin. [-pi, pi] */
- ir_unop_cos_reduced, /**< Reduced range cos. [-pi, pi] */
/*@}*/
/**
*/
/*@{*/
ir_unop_dFdx,
+ ir_unop_dFdx_coarse,
+ ir_unop_dFdx_fine,
ir_unop_dFdy,
+ ir_unop_dFdy_coarse,
+ ir_unop_dFdy_fine,
/*@}*/
/**
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,
+
/**
* A sentinel marking the last of the unary operations.
*/
- ir_last_unop = ir_unop_noise,
+ ir_last_unop = ir_unop_interpolate_at_centroid,
ir_binop_add,
ir_binop_sub,
*/
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.
*/
ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1, ir_rvalue *op2);
- virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+ 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;
ir_call(ir_function_signature *callee,
ir_dereference_variable *return_deref,
exec_list *actual_parameters)
- : ir_instruction(ir_type_call), 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)
{
assert(callee->return_type != NULL);
actual_parameters->move_nodes_to(& this->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
+ * rvalue to be used in the lowering pass later.
+ */
+ ir_variable *sub_var;
+ ir_rvalue *array_idx;
};
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
- virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+ virtual bool equals(const ir_instruction *ir,
+ enum ir_node_type ignore = ir_type_unset) const;
/**
* Return a string representing the ir_texture_opcode.
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
- virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+ virtual bool equals(const ir_instruction *ir,
+ enum ir_node_type ignore = ir_type_unset) const;
bool is_lvalue() const
{
virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
- virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+ 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
virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
- virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+ 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
int i[16];
float f[16];
bool b[16];
+ double d[16];
};
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
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
- virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+ 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
/*@{*/
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;
/*@}*/
* 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;
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.
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 *);
+};
+
/*@}*/
/**
_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(_mesa_glsl_parse_state *state,
+ const char *name);
+
extern gl_shader *
_mesa_glsl_get_builtin_function_shader(void);