#include <stdio.h>
#include <stdlib.h>
-#include "ralloc.h"
+#include "util/ralloc.h"
#include "glsl_types.h"
#include "list.h"
#include "ir_visitor.h"
* 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_max, /**< maximum ir_type enum number, for validation */
+ ir_type_unset = ir_type_max
};
+
/**
* Base class of all IR instructions
*/
/** 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;
* 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; }
+ 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_CHILD(TYPE) \
+ class ir_##TYPE * as_##TYPE() \
+ { \
+ return ir_type == ir_type_##TYPE ? (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(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+
protected:
+ ir_instruction(enum ir_node_type t)
+ : ir_type(t)
+ {
+ }
+
+private:
ir_instruction()
{
- ir_type = ir_type_unset;
+ assert(!"Should not get here.");
}
};
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
*/
virtual bool is_basis() const;
+ /**
+ * Determine if an r-value is an unsigned integer constant which can be
+ * stored in 16 bits.
+ *
+ * \sa ir_constant::is_uint16_constant.
+ */
+ virtual bool is_uint16_constant() const { return false; }
/**
* Return a generic value of error_type.
static ir_rvalue *error_value(void *mem_ctx);
protected:
- ir_rvalue();
+ ir_rvalue(enum ir_node_type t);
};
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,
+};
+
/**
* \brief Layout qualifiers for gl_FragDepth.
*
int swizzle;
};
+
+/**
+ * Get the string value for an interpolation qualifier
+ *
+ * \return The string that would be used in a shader to specify \c
+ * mode will be returned.
+ *
+ * This function is used to generate error messages of the form "shader
+ * uses %s interpolation qualifier", so in the case where there is no
+ * interpolation qualifier, it returns "no".
+ *
+ * This function should only be used on a shader input or output variable.
+ */
+const char *interpolation_string(unsigned interpolation);
+
+
class ir_variable : public ir_instruction {
public:
ir_variable(const struct glsl_type *, const char *, ir_variable_mode);
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);
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
- /**
- * Get the string value for the interpolation qualifier
- *
- * \return The string that would be used in a shader to specify \c
- * mode will be returned.
- *
- * This function is used to generate error messages of the form "shader
- * uses %s interpolation qualifier", so in the case where there is no
- * interpolation qualifier, it returns "no".
- *
- * This function should only be used on a shader input or output variable.
- */
- const char *interpolation_string() const;
-
/**
* Determine how this variable should be interpolated based on its
* interpolation qualifier (if present), whether it is gl_Color or
*/
inline bool is_in_uniform_block() const
{
- return this->mode == ir_var_uniform && this->interface_type != NULL;
+ return this->data.mode == ir_var_uniform && this->interface_type != NULL;
}
/**
}
/**
- * Declared type of the variable
+ * Set this->interface_type on a newly created variable.
*/
- const struct glsl_type *type;
+ void init_interface_type(const struct glsl_type *type)
+ {
+ assert(this->interface_type == NULL);
+ this->interface_type = type;
+ if (this->is_interface_instance()) {
+ this->max_ifc_array_access =
+ rzalloc_array(this, unsigned, type->length);
+ }
+ }
/**
- * Declared name of the variable
+ * Change this->interface_type on a variable that previously had a
+ * different, but compatible, interface_type. This is used during linking
+ * to set the size of arrays in interface blocks.
*/
- const char *name;
+ void change_interface_type(const struct glsl_type *type)
+ {
+ if (this->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.
+ */
+ assert(this->interface_type->length == type->length);
+ }
+ this->interface_type = type;
+ }
/**
- * Highest element accessed with a constant expression array index
- *
- * Not used for non-array variables.
+ * Change this->interface_type on a variable that previously had a
+ * different, and incompatible, interface_type. This is used during
+ * compilation to handle redeclaration of the built-in gl_PerVertex
+ * interface block.
*/
- unsigned max_array_access;
+ void reinit_interface_type(const struct glsl_type *type)
+ {
+ if (this->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);
+#endif
+ ralloc_free(this->max_ifc_array_access);
+ this->max_ifc_array_access = NULL;
+ }
+ this->interface_type = NULL;
+ init_interface_type(type);
+ }
- /**
- * 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;
+ const glsl_type *get_interface_type() const
+ {
+ return this->interface_type;
+ }
/**
- * 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.
+ * Declared type of the variable
*/
- unsigned used:1;
+ const struct glsl_type *type;
/**
- * 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.
+ * Declared name of the variable
*/
- unsigned assigned:1;
+ const char *name;
/**
- * Storage class of the variable.
+ * 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.
*
- * \sa ir_variable_mode
+ * For variables whose type is not an interface block, this pointer is
+ * NULL.
*/
- unsigned mode:4;
+ unsigned *max_ifc_array_access;
- /**
- * Interpolation mode for shader inputs / outputs
- *
- * \sa ir_variable_interpolation
- */
- unsigned interpolation:2;
+ struct ir_variable_data {
- /**
- * \name ARB_fragment_coord_conventions
- * @{
- */
- unsigned origin_upper_left:1;
- unsigned pixel_center_integer:1;
- /*@}*/
+ /**
+ * 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 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;
- /**
- * 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;
+ /**
+ * 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;
- /**
- * 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;
+ /**
+ * Storage class of the variable.
+ *
+ * \sa ir_variable_mode
+ */
+ unsigned mode:4;
- /**
- * Does this variable have an initializer?
- *
- * This is used by the linker to cross-validiate initializers of global
- * variables.
- */
- unsigned has_initializer:1;
+ /**
+ * Interpolation mode for shader inputs / outputs
+ *
+ * \sa ir_variable_interpolation
+ */
+ unsigned interpolation:2;
- /**
- * 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;
+ /**
+ * \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;
- /**
- * 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;
+ /**
+ * 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;
+
+ /**
+ * 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;
- /**
- * \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;
+ /**
+ * Non-zero if the variable must be a shader input. This is useful for
+ * constraints on function parameters.
+ */
+ unsigned must_be_shader_input: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;
+ /**
+ * \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;
+
+ /**
+ * 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;
- /**
- * output index for dual source blending.
- */
- int index;
+ /**
+ * Vertex stream output identifier.
+ */
+ unsigned stream;
- /**
- * Initial binding point for a sampler or UBO.
- *
- * For array types, this represents the binding point for the first element.
- */
- int binding;
+ /**
+ * 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
+ *
+ * Not used for non-array variables.
+ */
+ unsigned max_array_access;
+
+ } data;
/**
* Built-in state that backs this uniform
*/
ir_constant *constant_initializer;
+private:
/**
* 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.
*/
public:
ir_function_signature(const glsl_type *return_type,
- builtin_available_predicate builtin_info = NULL);
+ builtin_available_predicate builtin_avail = NULL);
virtual ir_function_signature *clone(void *mem_ctx,
struct hash_table *ht) const;
unsigned is_defined:1;
/** Whether or not this function signature is a built-in. */
- unsigned is_builtin:1;
+ 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;
/** Body of instructions in the function. */
struct exec_list body;
* A function pointer to a predicate that answers whether a built-in
* function is available in the current shader. NULL if not a built-in.
*/
- builtin_available_predicate builtin_info;
+ builtin_available_predicate builtin_avail;
/** Function of which this signature is one overload. */
class ir_function *_function;
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);
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(const exec_list *actual_param,
+ ir_function_signature *matching_signature(_mesa_glsl_parse_state *state,
+ const exec_list *actual_param,
bool *match_is_exact);
/**
* Find a signature that matches a set of actual parameters, taking implicit
* conversions into account.
*/
- ir_function_signature *matching_signature(const exec_list *actual_param);
+ ir_function_signature *matching_signature(_mesa_glsl_parse_state *state,
+ const exec_list *actual_param);
/**
* Find a signature that exactly matches a set of actual parameters without
* any implicit type conversions.
*/
- ir_function_signature *exact_matching_signature(const exec_list *actual_ps);
+ ir_function_signature *exact_matching_signature(_mesa_glsl_parse_state *state,
+ const exec_list *actual_ps);
/**
* Name of the function.
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);
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;
- /*@}*/
};
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
- virtual ir_assignment * as_assignment()
- {
- return this;
- }
-
/**
* Get a whole variable written by an assignment
*
ir_unop_noise,
+ /**
+ * 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_mul,
+ ir_binop_mul, /**< Floating-point or low 32-bit integer multiply. */
+ ir_binop_imul_high, /**< Calculates the high 32-bits of a 64-bit multiply. */
ir_binop_div,
+ /**
+ * Returns the carry resulting from the addition of the two arguments.
+ */
+ /*@{*/
+ ir_binop_carry,
+ /*@}*/
+
+ /**
+ * Returns the borrow resulting from the subtraction of the second argument
+ * from the first argument.
+ */
+ /*@{*/
+ ir_binop_borrow,
+ /*@}*/
+
/**
* Takes one of two combinations of arguments:
*
*/
ir_binop_ubo_load,
+ /**
+ * \name Multiplies a number by two to a power, part of ARB_gpu_shader5.
+ */
+ /*@{*/
+ ir_binop_ldexp,
+ /*@}*/
+
/**
* Extract a scalar from a vector
*
*/
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_triop_lrp,
+ /**
+ * \name Conditional Select
+ *
+ * A vector conditional select instruction (like ?:, but operating per-
+ * component on vectors).
+ *
+ * \see lower_instructions_visitor::ldexp_to_arith
+ */
+ /*@{*/
+ ir_triop_csel,
+ /*@}*/
+
/**
* \name Second half of a lowered bitfieldInsert() operation.
*
*/
ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1);
- virtual ir_expression *as_expression()
- {
- return this;
- }
+ /**
+ * Constructor for ternary operation expressions
+ */
+ 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 ir_expression *clone(void *mem_ctx, struct hash_table *ht) const;
? 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.
*/
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)
{
- ir_type = ir_type_call;
assert(callee->return_type != NULL);
actual_parameters->move_nodes_to(& this->actual_parameters);
- this->use_builtin = callee->is_builtin;
+ 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_call *as_call()
- {
- return this;
- }
-
virtual void accept(ir_visitor *v)
{
v->visit(this);
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.
*/
/*@{*/
class ir_jump : public ir_instruction {
protected:
- ir_jump()
- {
- ir_type = ir_type_unset;
- }
-
-public:
- virtual ir_jump *as_jump()
+ ir_jump(enum ir_node_type t)
+ : ir_instruction(t)
{
- 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;
};
ir_loop_jump(jump_mode mode)
+ : ir_jump(ir_type_loop_jump)
{
- this->ir_type = ir_type_loop_jump;
this->mode = mode;
}
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;
}
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
- virtual ir_discard *as_discard()
- {
- return this;
- }
-
ir_rvalue *condition;
};
/*@}*/
ir_txf, /**< Texel fetch with explicit LOD */
ir_txf_ms, /**< Multisample texture fetch */
ir_txs, /**< Texture size */
- ir_lod /**< Texture lod query */
+ ir_lod, /**< Texture lod query */
+ ir_tg4, /**< Texture gather */
+ ir_query_levels /**< Texture levels query */
};
* <type> <sampler> <coordinate> <sample_index>)
* (txs <type> <sampler> <lod>)
* (lod <type> <sampler> <coordinate>)
+ * (tg4 <type> <sampler> <coordinate> <offset> <component>)
+ * (query_levels <type> <sampler>)
*/
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));
}
virtual ir_texture *clone(void *mem_ctx, struct hash_table *) const;
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+ virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+
/**
* Return a string representing the ir_texture_opcode.
*/
ir_rvalue *lod; /**< Floating point LOD */
ir_rvalue *bias; /**< Floating point LOD bias */
ir_rvalue *sample_index; /**< MSAA sample index */
+ ir_rvalue *component; /**< Gather component selector */
struct {
ir_rvalue *dPdx; /**< Partial derivative of coordinate wrt X */
ir_rvalue *dPdy; /**< Partial derivative of coordinate wrt Y */
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.
*/
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+ virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+
bool is_lvalue() const
{
return val->is_lvalue() && !mask.has_duplicates;
public:
virtual ir_dereference *clone(void *mem_ctx, struct hash_table *) const = 0;
- virtual ir_dereference *as_dereference()
- {
- return this;
- }
-
bool is_lvalue() const;
/**
*/
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)
+ {
+ }
};
virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
- virtual ir_dereference_variable *as_dereference_variable()
- {
- return this;
- }
+ virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
/**
* Get the variable that is ultimately referenced by an r-value
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
virtual ir_constant *constant_expression_value(struct hash_table *variable_context = NULL);
- virtual ir_dereference_array *as_dereference_array()
- {
- return this;
- }
+ virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
/**
* Get the variable that is ultimately referenced by an r-value
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);
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
*/
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);
class ir_constant : public ir_rvalue {
public:
ir_constant(const struct glsl_type *type, const ir_constant_data *data);
- ir_constant(bool b);
- ir_constant(unsigned int u);
- ir_constant(int i);
- ir_constant(float f);
+ ir_constant(bool b, unsigned vector_elements=1);
+ 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);
/**
* Construct an ir_constant from a list of ir_constant values
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);
virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+ virtual bool equals(ir_instruction *ir, enum ir_node_type ignore = ir_type_unset);
+
/**
* Get a particular component of a constant as a specific type
*
*/
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.
*
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)
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;
};
/**
*/
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)
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;
};
+/*@}*/
+
/**
* Apply a visitor to each IR node in a list
*/
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 gl_shader *
+_mesa_glsl_get_builtin_function_shader(void);
+
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);
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