diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/SConscript | 9 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.cpp | 3148 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.h | 3280 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_print_visitor.cpp | 945 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_reader.cpp | 2001 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_dead_functions.cpp | 317 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_discard_simplification.cpp | 10 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_if_simplification.cpp | 10 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_redundant_jumps.cpp | 231 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_structure_splitting.cpp | 728 |
10 files changed, 5369 insertions, 5310 deletions
diff --git a/mesalib/src/glsl/SConscript b/mesalib/src/glsl/SConscript index d7c3459f2..5d97756e1 100644 --- a/mesalib/src/glsl/SConscript +++ b/mesalib/src/glsl/SConscript @@ -105,11 +105,16 @@ if env['msvc']: if env['crosscompile'] and env['platform'] != 'embedded':
Import('builtin_glsl_function')
else:
+ # Copy these files to avoid generation object files into src/mesa/program
+ env.Prepend(CPPPATH = ['#src/mesa/program'])
+ env.Command('hash_table.c', '#src/mesa/program/hash_table.c', Copy('$TARGET', '$SOURCE'))
+ env.Command('symbol_table.c', '#src/mesa/program/symbol_table.c', Copy('$TARGET', '$SOURCE'))
+
main_obj = env.StaticObject('main.cpp')
mesa_objs = env.StaticObject([
- '#src/mesa/program/hash_table.c',
- '#src/mesa/program/symbol_table.c',
+ 'hash_table.c',
+ 'symbol_table.c',
])
builtin_compiler = env.Program(
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index fc356ba52..ceb989110 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1,1576 +1,1572 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include <string.h> -#include "main/core.h" /* for MAX2 */ -#include "ir.h" -#include "ir_visitor.h" -#include "glsl_types.h" - -ir_rvalue::ir_rvalue() -{ - this->type = glsl_type::error_type; -} - -bool ir_rvalue::is_zero() const -{ - return false; -} - -bool ir_rvalue::is_one() const -{ - return false; -} - -bool ir_rvalue::is_negative_one() const -{ - return false; -} - -/** - * Modify the swizzle make to move one component to another - * - * \param m IR swizzle to be modified - * \param from Component in the RHS that is to be swizzled - * \param to Desired swizzle location of \c from - */ -static void -update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to) -{ - switch (to) { - case 0: m.x = from; break; - case 1: m.y = from; break; - case 2: m.z = from; break; - case 3: m.w = from; break; - default: assert(!"Should not get here."); - } - - m.num_components = MAX2(m.num_components, (to + 1)); -} - -void -ir_assignment::set_lhs(ir_rvalue *lhs) -{ - void *mem_ctx = this; - bool swizzled = false; - - while (lhs != NULL) { - ir_swizzle *swiz = lhs->as_swizzle(); - - if (swiz == NULL) - break; - - unsigned write_mask = 0; - ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 }; - - for (unsigned i = 0; i < swiz->mask.num_components; i++) { - unsigned c = 0; - - switch (i) { - case 0: c = swiz->mask.x; break; - case 1: c = swiz->mask.y; break; - case 2: c = swiz->mask.z; break; - case 3: c = swiz->mask.w; break; - default: assert(!"Should not get here."); - } - - write_mask |= (((this->write_mask >> i) & 1) << c); - update_rhs_swizzle(rhs_swiz, i, c); - } - - this->write_mask = write_mask; - lhs = swiz->val; - - this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz); - swizzled = true; - } - - if (swizzled) { - /* Now, RHS channels line up with the LHS writemask. Collapse it - * to just the channels that will be written. - */ - ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 }; - int rhs_chan = 0; - for (int i = 0; i < 4; i++) { - if (write_mask & (1 << i)) - update_rhs_swizzle(rhs_swiz, i, rhs_chan++); - } - this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz); - } - - assert((lhs == NULL) || lhs->as_dereference()); - - this->lhs = (ir_dereference *) lhs; -} - -ir_variable * -ir_assignment::whole_variable_written() -{ - ir_variable *v = this->lhs->whole_variable_referenced(); - - if (v == NULL) - return NULL; - - if (v->type->is_scalar()) - return v; - - if (v->type->is_vector()) { - const unsigned mask = (1U << v->type->vector_elements) - 1; - - if (mask != this->write_mask) - return NULL; - } - - /* Either all the vector components are assigned or the variable is some - * composite type (and the whole thing is assigned. - */ - return v; -} - -ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, - ir_rvalue *condition, unsigned write_mask) -{ - this->ir_type = ir_type_assignment; - this->condition = condition; - this->rhs = rhs; - this->lhs = lhs; - this->write_mask = write_mask; - - if (lhs->type->is_scalar() || lhs->type->is_vector()) { - int lhs_components = 0; - for (int i = 0; i < 4; i++) { - if (write_mask & (1 << i)) - lhs_components++; - } - - assert(lhs_components == this->rhs->type->vector_elements); - } -} - -ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, - ir_rvalue *condition) -{ - this->ir_type = ir_type_assignment; - this->condition = condition; - this->rhs = rhs; - - /* If the RHS is a vector type, assume that all components of the vector - * type are being written to the LHS. The write mask comes from the RHS - * because we can have a case where the LHS is a vec4 and the RHS is a - * vec3. In that case, the assignment is: - * - * (assign (...) (xyz) (var_ref lhs) (var_ref rhs)) - */ - if (rhs->type->is_vector()) - this->write_mask = (1U << rhs->type->vector_elements) - 1; - else if (rhs->type->is_scalar()) - this->write_mask = 1; - else - this->write_mask = 0; - - this->set_lhs(lhs); -} - - -ir_expression::ir_expression(int op, const struct glsl_type *type, - ir_rvalue *op0) -{ - assert(get_num_operands(ir_expression_operation(op)) == 1); - this->ir_type = ir_type_expression; - this->type = type; - this->operation = ir_expression_operation(op); - this->operands[0] = op0; - this->operands[1] = NULL; - this->operands[2] = NULL; - this->operands[3] = NULL; -} - -ir_expression::ir_expression(int op, const struct glsl_type *type, - ir_rvalue *op0, ir_rvalue *op1) -{ - assert(((op1 == NULL) && (get_num_operands(ir_expression_operation(op)) == 1)) - || (get_num_operands(ir_expression_operation(op)) == 2)); - this->ir_type = ir_type_expression; - this->type = type; - this->operation = ir_expression_operation(op); - this->operands[0] = op0; - this->operands[1] = op1; - this->operands[2] = NULL; - this->operands[3] = NULL; -} - -ir_expression::ir_expression(int op, const struct glsl_type *type, - ir_rvalue *op0, ir_rvalue *op1, - ir_rvalue *op2, ir_rvalue *op3) -{ - this->ir_type = ir_type_expression; - this->type = type; - this->operation = ir_expression_operation(op); - this->operands[0] = op0; - this->operands[1] = op1; - this->operands[2] = op2; - this->operands[3] = op3; -} - -ir_expression::ir_expression(int op, ir_rvalue *op0) -{ - this->ir_type = ir_type_expression; - - this->operation = ir_expression_operation(op); - this->operands[0] = op0; - this->operands[1] = NULL; - this->operands[2] = NULL; - this->operands[3] = NULL; - - assert(op <= ir_last_unop); - - switch (this->operation) { - case ir_unop_bit_not: - case ir_unop_logic_not: - case ir_unop_neg: - case ir_unop_abs: - case ir_unop_sign: - case ir_unop_rcp: - case ir_unop_rsq: - case ir_unop_sqrt: - case ir_unop_exp: - case ir_unop_log: - case ir_unop_exp2: - case ir_unop_log2: - case ir_unop_trunc: - case ir_unop_ceil: - case ir_unop_floor: - case ir_unop_fract: - case ir_unop_round_even: - case ir_unop_sin: - case ir_unop_cos: - case ir_unop_sin_reduced: - case ir_unop_cos_reduced: - case ir_unop_dFdx: - case ir_unop_dFdy: - this->type = op0->type; - break; - - case ir_unop_f2i: - case ir_unop_b2i: - this->type = glsl_type::get_instance(GLSL_TYPE_INT, - op0->type->vector_elements, 1); - break; - - case ir_unop_b2f: - case ir_unop_i2f: - case ir_unop_u2f: - this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT, - op0->type->vector_elements, 1); - break; - - case ir_unop_f2b: - case ir_unop_i2b: - this->type = glsl_type::get_instance(GLSL_TYPE_BOOL, - op0->type->vector_elements, 1); - break; - - case ir_unop_noise: - this->type = glsl_type::float_type; - break; - - case ir_unop_any: - this->type = glsl_type::bool_type; - break; - - default: - assert(!"not reached: missing automatic type setup for ir_expression"); - this->type = op0->type; - break; - } -} - -ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1) -{ - this->ir_type = ir_type_expression; - - this->operation = ir_expression_operation(op); - this->operands[0] = op0; - this->operands[1] = op1; - this->operands[2] = NULL; - this->operands[3] = NULL; - - assert(op > ir_last_unop); - - switch (this->operation) { - case ir_binop_all_equal: - case ir_binop_any_nequal: - this->type = glsl_type::bool_type; - break; - - case ir_binop_add: - case ir_binop_sub: - case ir_binop_min: - case ir_binop_max: - case ir_binop_pow: - case ir_binop_mul: - case ir_binop_div: - case ir_binop_mod: - if (op0->type->is_scalar()) { - this->type = op1->type; - } else if (op1->type->is_scalar()) { - this->type = op0->type; - } else { - /* FINISHME: matrix types */ - assert(!op0->type->is_matrix() && !op1->type->is_matrix()); - assert(op0->type == op1->type); - this->type = op0->type; - } - break; - - case ir_binop_logic_and: - case ir_binop_logic_xor: - case ir_binop_logic_or: - case ir_binop_bit_and: - case ir_binop_bit_xor: - case ir_binop_bit_or: - if (op0->type->is_scalar()) { - this->type = op1->type; - } else if (op1->type->is_scalar()) { - this->type = op0->type; - } - break; - - case ir_binop_equal: - case ir_binop_nequal: - case ir_binop_lequal: - case ir_binop_gequal: - case ir_binop_less: - case ir_binop_greater: - assert(op0->type == op1->type); - this->type = glsl_type::get_instance(GLSL_TYPE_BOOL, - op0->type->vector_elements, 1); - break; - - case ir_binop_dot: - this->type = glsl_type::float_type; - break; - - case ir_binop_lshift: - case ir_binop_rshift: - this->type = op0->type; - break; - - default: - assert(!"not reached: missing automatic type setup for ir_expression"); - this->type = glsl_type::float_type; - } -} - -unsigned int -ir_expression::get_num_operands(ir_expression_operation op) -{ - assert(op <= ir_last_opcode); - - if (op <= ir_last_unop) - return 1; - - if (op <= ir_last_binop) - return 2; - - if (op == ir_quadop_vector) - return 4; - - assert(false); - return 0; -} - -static const char *const operator_strs[] = { - "~", - "!", - "neg", - "abs", - "sign", - "rcp", - "rsq", - "sqrt", - "exp", - "log", - "exp2", - "log2", - "f2i", - "i2f", - "f2b", - "b2f", - "i2b", - "b2i", - "u2f", - "any", - "trunc", - "ceil", - "floor", - "fract", - "round_even", - "sin", - "cos", - "sin_reduced", - "cos_reduced", - "dFdx", - "dFdy", - "noise", - "+", - "-", - "*", - "/", - "%", - "<", - ">", - "<=", - ">=", - "==", - "!=", - "all_equal", - "any_nequal", - "<<", - ">>", - "&", - "^", - "|", - "&&", - "^^", - "||", - "dot", - "min", - "max", - "pow", - "vector", -}; - -const char *ir_expression::operator_string(ir_expression_operation op) -{ - assert((unsigned int) op < Elements(operator_strs)); - assert(Elements(operator_strs) == (ir_quadop_vector + 1)); - return operator_strs[op]; -} - -const char *ir_expression::operator_string() -{ - return operator_string(this->operation); -} - -const char* -depth_layout_string(ir_depth_layout layout) -{ - switch(layout) { - case ir_depth_layout_none: return ""; - case ir_depth_layout_any: return "depth_any"; - case ir_depth_layout_greater: return "depth_greater"; - case ir_depth_layout_less: return "depth_less"; - case ir_depth_layout_unchanged: return "depth_unchanged"; - - default: - assert(0); - return ""; - } -} - -ir_expression_operation -ir_expression::get_operator(const char *str) -{ - const int operator_count = sizeof(operator_strs) / sizeof(operator_strs[0]); - for (int op = 0; op < operator_count; op++) { - if (strcmp(str, operator_strs[op]) == 0) - return (ir_expression_operation) op; - } - return (ir_expression_operation) -1; -} - -ir_constant::ir_constant() -{ - this->ir_type = ir_type_constant; -} - -ir_constant::ir_constant(const struct glsl_type *type, - const ir_constant_data *data) -{ - assert((type->base_type >= GLSL_TYPE_UINT) - && (type->base_type <= GLSL_TYPE_BOOL)); - - this->ir_type = ir_type_constant; - this->type = type; - memcpy(& this->value, data, sizeof(this->value)); -} - -ir_constant::ir_constant(float f) -{ - this->ir_type = ir_type_constant; - this->type = glsl_type::float_type; - this->value.f[0] = f; - for (int i = 1; i < 16; i++) { - this->value.f[i] = 0; - } -} - -ir_constant::ir_constant(unsigned int u) -{ - this->ir_type = ir_type_constant; - this->type = glsl_type::uint_type; - this->value.u[0] = u; - for (int i = 1; i < 16; i++) { - this->value.u[i] = 0; - } -} - -ir_constant::ir_constant(int i) -{ - this->ir_type = ir_type_constant; - this->type = glsl_type::int_type; - this->value.i[0] = i; - for (int i = 1; i < 16; i++) { - this->value.i[i] = 0; - } -} - -ir_constant::ir_constant(bool b) -{ - this->ir_type = ir_type_constant; - this->type = glsl_type::bool_type; - this->value.b[0] = b; - for (int i = 1; i < 16; i++) { - this->value.b[i] = false; - } -} - -ir_constant::ir_constant(const ir_constant *c, unsigned i) -{ - this->ir_type = ir_type_constant; - this->type = c->type->get_base_type(); - - switch (this->type->base_type) { - case GLSL_TYPE_UINT: this->value.u[0] = c->value.u[i]; break; - case GLSL_TYPE_INT: this->value.i[0] = c->value.i[i]; break; - case GLSL_TYPE_FLOAT: this->value.f[0] = c->value.f[i]; break; - case GLSL_TYPE_BOOL: this->value.b[0] = c->value.b[i]; break; - default: assert(!"Should not get here."); break; - } -} - -ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list) -{ - this->ir_type = ir_type_constant; - this->type = type; - - assert(type->is_scalar() || type->is_vector() || type->is_matrix() - || type->is_record() || type->is_array()); - - if (type->is_array()) { - this->array_elements = ralloc_array(this, ir_constant *, type->length); - unsigned i = 0; - foreach_list(node, value_list) { - ir_constant *value = (ir_constant *) node; - assert(value->as_constant() != NULL); - - this->array_elements[i++] = value; - } - return; - } - - /* If the constant is a record, the types of each of the entries in - * value_list must be a 1-for-1 match with the structure components. Each - * entry must also be a constant. Just move the nodes from the value_list - * to the list in the ir_constant. - */ - /* FINISHME: Should there be some type checking and / or assertions here? */ - /* FINISHME: Should the new constant take ownership of the nodes from - * FINISHME: value_list, or should it make copies? - */ - if (type->is_record()) { - value_list->move_nodes_to(& this->components); - return; - } - - for (unsigned i = 0; i < 16; i++) { - this->value.u[i] = 0; - } - - ir_constant *value = (ir_constant *) (value_list->head); - - /* Constructors with exactly one scalar argument are special for vectors - * and matrices. For vectors, the scalar value is replicated to fill all - * the components. For matrices, the scalar fills the components of the - * diagonal while the rest is filled with 0. - */ - if (value->type->is_scalar() && value->next->is_tail_sentinel()) { - if (type->is_matrix()) { - /* Matrix - fill diagonal (rest is already set to 0) */ - assert(type->base_type == GLSL_TYPE_FLOAT); - for (unsigned i = 0; i < type->matrix_columns; i++) - this->value.f[i * type->vector_elements + i] = value->value.f[0]; - } else { - /* Vector or scalar - fill all components */ - switch (type->base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - for (unsigned i = 0; i < type->components(); i++) - this->value.u[i] = value->value.u[0]; - break; - case GLSL_TYPE_FLOAT: - for (unsigned i = 0; i < type->components(); i++) - this->value.f[i] = value->value.f[0]; - break; - case GLSL_TYPE_BOOL: - for (unsigned i = 0; i < type->components(); i++) - this->value.b[i] = value->value.b[0]; - break; - default: - assert(!"Should not get here."); - break; - } - } - return; - } - - if (type->is_matrix() && value->type->is_matrix()) { - assert(value->next->is_tail_sentinel()); - - /* From section 5.4.2 of the GLSL 1.20 spec: - * "If a matrix is constructed from a matrix, then each component - * (column i, row j) in the result that has a corresponding component - * (column i, row j) in the argument will be initialized from there." - */ - unsigned cols = MIN2(type->matrix_columns, value->type->matrix_columns); - unsigned rows = MIN2(type->vector_elements, value->type->vector_elements); - for (unsigned i = 0; i < cols; i++) { - for (unsigned j = 0; j < rows; j++) { - const unsigned src = i * value->type->vector_elements + j; - const unsigned dst = i * type->vector_elements + j; - this->value.f[dst] = value->value.f[src]; - } - } - - /* "All other components will be initialized to the identity matrix." */ - for (unsigned i = cols; i < type->matrix_columns; i++) - this->value.f[i * type->vector_elements + i] = 1.0; - - return; - } - - /* Use each component from each entry in the value_list to initialize one - * component of the constant being constructed. - */ - for (unsigned i = 0; i < type->components(); /* empty */) { - assert(value->as_constant() != NULL); - assert(!value->is_tail_sentinel()); - - for (unsigned j = 0; j < value->type->components(); j++) { - switch (type->base_type) { - case GLSL_TYPE_UINT: - this->value.u[i] = value->get_uint_component(j); - break; - case GLSL_TYPE_INT: - this->value.i[i] = value->get_int_component(j); - break; - case GLSL_TYPE_FLOAT: - this->value.f[i] = value->get_float_component(j); - break; - case GLSL_TYPE_BOOL: - this->value.b[i] = value->get_bool_component(j); - break; - default: - /* FINISHME: What to do? Exceptions are not the answer. - */ - break; - } - - i++; - if (i >= type->components()) - break; - } - - value = (ir_constant *) value->next; - } -} - -ir_constant * -ir_constant::zero(void *mem_ctx, const glsl_type *type) -{ - assert(type->is_numeric() || type->is_boolean()); - - ir_constant *c = new(mem_ctx) ir_constant; - c->type = type; - memset(&c->value, 0, sizeof(c->value)); - - return c; -} - -bool -ir_constant::get_bool_component(unsigned i) const -{ - switch (this->type->base_type) { - case GLSL_TYPE_UINT: return this->value.u[i] != 0; - case GLSL_TYPE_INT: return this->value.i[i] != 0; - case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0; - case GLSL_TYPE_BOOL: return this->value.b[i]; - default: assert(!"Should not get here."); break; - } - - /* Must return something to make the compiler happy. This is clearly an - * error case. - */ - return false; -} - -float -ir_constant::get_float_component(unsigned i) const -{ - switch (this->type->base_type) { - case GLSL_TYPE_UINT: return (float) this->value.u[i]; - case GLSL_TYPE_INT: return (float) this->value.i[i]; - case GLSL_TYPE_FLOAT: return this->value.f[i]; - case GLSL_TYPE_BOOL: return this->value.b[i] ? 1.0 : 0.0; - default: assert(!"Should not get here."); break; - } - - /* Must return something to make the compiler happy. This is clearly an - * error case. - */ - return 0.0; -} - -int -ir_constant::get_int_component(unsigned i) const -{ - switch (this->type->base_type) { - case GLSL_TYPE_UINT: return this->value.u[i]; - case GLSL_TYPE_INT: return this->value.i[i]; - case GLSL_TYPE_FLOAT: return (int) this->value.f[i]; - case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0; - default: assert(!"Should not get here."); break; - } - - /* Must return something to make the compiler happy. This is clearly an - * error case. - */ - return 0; -} - -unsigned -ir_constant::get_uint_component(unsigned i) const -{ - switch (this->type->base_type) { - case GLSL_TYPE_UINT: return this->value.u[i]; - case GLSL_TYPE_INT: return this->value.i[i]; - case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i]; - case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0; - default: assert(!"Should not get here."); break; - } - - /* Must return something to make the compiler happy. This is clearly an - * error case. - */ - return 0; -} - -ir_constant * -ir_constant::get_array_element(unsigned i) const -{ - assert(this->type->is_array()); - - /* From page 35 (page 41 of the PDF) of the GLSL 1.20 spec: - * - * "Behavior is undefined if a shader subscripts an array with an index - * less than 0 or greater than or equal to the size the array was - * declared with." - * - * Most out-of-bounds accesses are removed before things could get this far. - * There are cases where non-constant array index values can get constant - * folded. - */ - if (int(i) < 0) - i = 0; - else if (i >= this->type->length) - i = this->type->length - 1; - - return array_elements[i]; -} - -ir_constant * -ir_constant::get_record_field(const char *name) -{ - int idx = this->type->field_index(name); - - if (idx < 0) - return NULL; - - if (this->components.is_empty()) - return NULL; - - exec_node *node = this->components.head; - for (int i = 0; i < idx; i++) { - node = node->next; - - /* If the end of the list is encountered before the element matching the - * requested field is found, return NULL. - */ - if (node->is_tail_sentinel()) - return NULL; - } - - return (ir_constant *) node; -} - - -bool -ir_constant::has_value(const ir_constant *c) const -{ - if (this->type != c->type) - return false; - - if (this->type->is_array()) { - for (unsigned i = 0; i < this->type->length; i++) { - if (!this->array_elements[i]->has_value(c->array_elements[i])) - return false; - } - return true; - } - - if (this->type->base_type == GLSL_TYPE_STRUCT) { - const exec_node *a_node = this->components.head; - const exec_node *b_node = c->components.head; - - while (!a_node->is_tail_sentinel()) { - assert(!b_node->is_tail_sentinel()); - - const ir_constant *const a_field = (ir_constant *) a_node; - const ir_constant *const b_field = (ir_constant *) b_node; - - if (!a_field->has_value(b_field)) - return false; - - a_node = a_node->next; - b_node = b_node->next; - } - - return true; - } - - for (unsigned i = 0; i < this->type->components(); i++) { - switch (this->type->base_type) { - case GLSL_TYPE_UINT: - if (this->value.u[i] != c->value.u[i]) - return false; - break; - case GLSL_TYPE_INT: - if (this->value.i[i] != c->value.i[i]) - return false; - break; - case GLSL_TYPE_FLOAT: - if (this->value.f[i] != c->value.f[i]) - return false; - break; - case GLSL_TYPE_BOOL: - if (this->value.b[i] != c->value.b[i]) - return false; - break; - default: - assert(!"Should not get here."); - return false; - } - } - - return true; -} - -bool -ir_constant::is_zero() const -{ - if (!this->type->is_scalar() && !this->type->is_vector()) - return false; - - for (unsigned c = 0; c < this->type->vector_elements; c++) { - switch (this->type->base_type) { - case GLSL_TYPE_FLOAT: - if (this->value.f[c] != 0.0) - return false; - break; - case GLSL_TYPE_INT: - if (this->value.i[c] != 0) - return false; - break; - case GLSL_TYPE_UINT: - if (this->value.u[c] != 0) - return false; - break; - case GLSL_TYPE_BOOL: - if (this->value.b[c] != false) - return false; - break; - default: - /* The only other base types are structures, arrays, and samplers. - * Samplers cannot be constants, and the others should have been - * filtered out above. - */ - assert(!"Should not get here."); - return false; - } - } - - return true; -} - -bool -ir_constant::is_one() const -{ - if (!this->type->is_scalar() && !this->type->is_vector()) - return false; - - for (unsigned c = 0; c < this->type->vector_elements; c++) { - switch (this->type->base_type) { - case GLSL_TYPE_FLOAT: - if (this->value.f[c] != 1.0) - return false; - break; - case GLSL_TYPE_INT: - if (this->value.i[c] != 1) - return false; - break; - case GLSL_TYPE_UINT: - if (this->value.u[c] != 1) - return false; - break; - case GLSL_TYPE_BOOL: - if (this->value.b[c] != true) - return false; - break; - default: - /* The only other base types are structures, arrays, and samplers. - * Samplers cannot be constants, and the others should have been - * filtered out above. - */ - assert(!"Should not get here."); - return false; - } - } - - return true; -} - -bool -ir_constant::is_negative_one() const -{ - if (!this->type->is_scalar() && !this->type->is_vector()) - return false; - - if (this->type->is_boolean()) - return false; - - for (unsigned c = 0; c < this->type->vector_elements; c++) { - switch (this->type->base_type) { - case GLSL_TYPE_FLOAT: - if (this->value.f[c] != -1.0) - return false; - break; - case GLSL_TYPE_INT: - if (this->value.i[c] != -1) - return false; - break; - case GLSL_TYPE_UINT: - if (int(this->value.u[c]) != -1) - return false; - break; - default: - /* The only other base types are structures, arrays, samplers, and - * booleans. Samplers cannot be constants, and the others should - * have been filtered out above. - */ - assert(!"Should not get here."); - return false; - } - } - - return true; -} - -ir_loop::ir_loop() -{ - this->ir_type = ir_type_loop; - this->cmp = ir_unop_neg; - this->from = NULL; - this->to = NULL; - this->increment = NULL; - this->counter = NULL; -} - - -ir_dereference_variable::ir_dereference_variable(ir_variable *var) -{ - this->ir_type = ir_type_dereference_variable; - this->var = var; - this->type = (var != NULL) ? var->type : glsl_type::error_type; -} - - -ir_dereference_array::ir_dereference_array(ir_rvalue *value, - ir_rvalue *array_index) -{ - this->ir_type = ir_type_dereference_array; - this->array_index = array_index; - this->set_array(value); -} - - -ir_dereference_array::ir_dereference_array(ir_variable *var, - ir_rvalue *array_index) -{ - void *ctx = ralloc_parent(var); - - this->ir_type = ir_type_dereference_array; - this->array_index = array_index; - this->set_array(new(ctx) ir_dereference_variable(var)); -} - - -void -ir_dereference_array::set_array(ir_rvalue *value) -{ - this->array = value; - this->type = glsl_type::error_type; - - if (this->array != NULL) { - const glsl_type *const vt = this->array->type; - - if (vt->is_array()) { - type = vt->element_type(); - } else if (vt->is_matrix()) { - type = vt->column_type(); - } else if (vt->is_vector()) { - type = vt->get_base_type(); - } - } -} - - -ir_dereference_record::ir_dereference_record(ir_rvalue *value, - const char *field) -{ - this->ir_type = ir_type_dereference_record; - this->record = value; - this->field = ralloc_strdup(this, field); - this->type = (this->record != NULL) - ? this->record->type->field_type(field) : glsl_type::error_type; -} - - -ir_dereference_record::ir_dereference_record(ir_variable *var, - const char *field) -{ - void *ctx = ralloc_parent(var); - - this->ir_type = ir_type_dereference_record; - this->record = new(ctx) ir_dereference_variable(var); - this->field = ralloc_strdup(this, field); - this->type = (this->record != NULL) - ? this->record->type->field_type(field) : glsl_type::error_type; -} - -bool type_contains_sampler(const glsl_type *type) -{ - if (type->is_array()) { - return type_contains_sampler(type->fields.array); - } else if (type->is_record()) { - for (unsigned int i = 0; i < type->length; i++) { - if (type_contains_sampler(type->fields.structure[i].type)) - return true; - } - return false; - } else { - return type->is_sampler(); - } -} - -bool -ir_dereference::is_lvalue() -{ - ir_variable *var = this->variable_referenced(); - - /* Every l-value derference chain eventually ends in a variable. - */ - if ((var == NULL) || var->read_only) - return false; - - if (this->type->is_array() && !var->array_lvalue) - return false; - - /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec: - * - * "Samplers cannot be treated as l-values; hence cannot be used - * as out or inout function parameters, nor can they be - * assigned into." - */ - if (type_contains_sampler(this->type)) - return false; - - return true; -} - - -const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf" }; - -const char *ir_texture::opcode_string() -{ - assert((unsigned int) op <= - sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0])); - return tex_opcode_strs[op]; -} - -ir_texture_opcode -ir_texture::get_opcode(const char *str) -{ - const int count = sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]); - for (int op = 0; op < count; op++) { - if (strcmp(str, tex_opcode_strs[op]) == 0) - return (ir_texture_opcode) op; - } - return (ir_texture_opcode) -1; -} - - -void -ir_texture::set_sampler(ir_dereference *sampler) -{ - assert(sampler != NULL); - this->sampler = sampler; - - switch (sampler->type->sampler_type) { - case GLSL_TYPE_FLOAT: - this->type = glsl_type::vec4_type; - break; - case GLSL_TYPE_INT: - this->type = glsl_type::ivec4_type; - break; - case GLSL_TYPE_UINT: - this->type = glsl_type::uvec4_type; - break; - } -} - - -void -ir_swizzle::init_mask(const unsigned *comp, unsigned count) -{ - assert((count >= 1) && (count <= 4)); - - memset(&this->mask, 0, sizeof(this->mask)); - this->mask.num_components = count; - - unsigned dup_mask = 0; - switch (count) { - case 4: - assert(comp[3] <= 3); - dup_mask |= (1U << comp[3]) - & ((1U << comp[0]) | (1U << comp[1]) | (1U << comp[2])); - this->mask.w = comp[3]; - - case 3: - assert(comp[2] <= 3); - dup_mask |= (1U << comp[2]) - & ((1U << comp[0]) | (1U << comp[1])); - this->mask.z = comp[2]; - - case 2: - assert(comp[1] <= 3); - dup_mask |= (1U << comp[1]) - & ((1U << comp[0])); - this->mask.y = comp[1]; - - case 1: - assert(comp[0] <= 3); - this->mask.x = comp[0]; - } - - this->mask.has_duplicates = dup_mask != 0; - - /* Based on the number of elements in the swizzle and the base type - * (i.e., float, int, unsigned, or bool) of the vector being swizzled, - * generate the type of the resulting value. - */ - type = glsl_type::get_instance(val->type->base_type, mask.num_components, 1); -} - -ir_swizzle::ir_swizzle(ir_rvalue *val, unsigned x, unsigned y, unsigned z, - unsigned w, unsigned count) - : val(val) -{ - const unsigned components[4] = { x, y, z, w }; - this->ir_type = ir_type_swizzle; - this->init_mask(components, count); -} - -ir_swizzle::ir_swizzle(ir_rvalue *val, const unsigned *comp, - unsigned count) - : val(val) -{ - this->ir_type = ir_type_swizzle; - this->init_mask(comp, count); -} - -ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask) -{ - this->ir_type = ir_type_swizzle; - this->val = val; - this->mask = mask; - this->type = glsl_type::get_instance(val->type->base_type, - mask.num_components, 1); -} - -#define X 1 -#define R 5 -#define S 9 -#define I 13 - -ir_swizzle * -ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length) -{ - void *ctx = ralloc_parent(val); - - /* For each possible swizzle character, this table encodes the value in - * \c idx_map that represents the 0th element of the vector. For invalid - * swizzle characters (e.g., 'k'), a special value is used that will allow - * detection of errors. - */ - static const unsigned char base_idx[26] = { - /* a b c d e f g h i j k l m */ - R, R, I, I, I, I, R, I, I, I, I, I, I, - /* n o p q r s t u v w x y z */ - I, I, S, S, R, S, S, I, I, X, X, X, X - }; - - /* Each valid swizzle character has an entry in the previous table. This - * table encodes the base index encoded in the previous table plus the actual - * index of the swizzle character. When processing swizzles, the first - * character in the string is indexed in the previous table. Each character - * in the string is indexed in this table, and the value found there has the - * value form the first table subtracted. The result must be on the range - * [0,3]. - * - * For example, the string "wzyx" will get X from the first table. Each of - * the charcaters will get X+3, X+2, X+1, and X+0 from this table. After - * subtraction, the swizzle values are { 3, 2, 1, 0 }. - * - * The string "wzrg" will get X from the first table. Each of the characters - * will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the - * swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range - * [0,3], the error is detected. - */ - static const unsigned char idx_map[26] = { - /* a b c d e f g h i j k l m */ - R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0, - /* n o p q r s t u v w x y z */ - 0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2 - }; - - int swiz_idx[4] = { 0, 0, 0, 0 }; - unsigned i; - - - /* Validate the first character in the swizzle string and look up the base - * index value as described above. - */ - if ((str[0] < 'a') || (str[0] > 'z')) - return NULL; - - const unsigned base = base_idx[str[0] - 'a']; - - - for (i = 0; (i < 4) && (str[i] != '\0'); i++) { - /* Validate the next character, and, as described above, convert it to a - * swizzle index. - */ - if ((str[i] < 'a') || (str[i] > 'z')) - return NULL; - - swiz_idx[i] = idx_map[str[i] - 'a'] - base; - if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length)) - return NULL; - } - - if (str[i] != '\0') - return NULL; - - return new(ctx) ir_swizzle(val, swiz_idx[0], swiz_idx[1], swiz_idx[2], - swiz_idx[3], i); -} - -#undef X -#undef R -#undef S -#undef I - -ir_variable * -ir_swizzle::variable_referenced() -{ - return this->val->variable_referenced(); -} - - -ir_variable::ir_variable(const struct glsl_type *type, const char *name, - ir_variable_mode mode) - : max_array_access(0), read_only(false), centroid(false), invariant(false), - mode(mode), interpolation(ir_var_smooth), array_lvalue(false) -{ - this->ir_type = ir_type_variable; - this->type = type; - this->name = ralloc_strdup(this, name); - this->explicit_location = false; - this->location = -1; - this->warn_extension = NULL; - this->constant_value = NULL; - this->origin_upper_left = false; - this->pixel_center_integer = false; - this->depth_layout = ir_depth_layout_none; - this->used = false; - - if (type && type->base_type == GLSL_TYPE_SAMPLER) - this->read_only = true; -} - - -const char * -ir_variable::interpolation_string() const -{ - switch (this->interpolation) { - case ir_var_smooth: return "smooth"; - case ir_var_flat: return "flat"; - case ir_var_noperspective: return "noperspective"; - } - - assert(!"Should not get here."); - return ""; -} - - -unsigned -ir_variable::component_slots() const -{ - /* FINISHME: Sparsely accessed arrays require fewer slots. */ - return this->type->component_slots(); -} - - -ir_function_signature::ir_function_signature(const glsl_type *return_type) - : return_type(return_type), is_defined(false), _function(NULL) -{ - this->ir_type = ir_type_function_signature; - this->is_builtin = false; -} - - -static bool -modes_match(unsigned a, unsigned b) -{ - if (a == b) - return true; - - /* Accept "in" vs. "const in" */ - if ((a == ir_var_const_in && b == ir_var_in) || - (b == ir_var_const_in && a == ir_var_in)) - return true; - - return false; -} - - -const char * -ir_function_signature::qualifiers_match(exec_list *params) -{ - exec_list_iterator iter_a = parameters.iterator(); - exec_list_iterator iter_b = params->iterator(); - - /* check that the qualifiers match. */ - while (iter_a.has_next()) { - ir_variable *a = (ir_variable *)iter_a.get(); - ir_variable *b = (ir_variable *)iter_b.get(); - - if (a->read_only != b->read_only || - !modes_match(a->mode, b->mode) || - a->interpolation != b->interpolation || - a->centroid != b->centroid) { - - /* parameter a's qualifiers don't match */ - return a->name; - } - - iter_a.next(); - iter_b.next(); - } - return NULL; -} - - -void -ir_function_signature::replace_parameters(exec_list *new_params) -{ - /* Destroy all of the previous parameter information. If the previous - * parameter information comes from the function prototype, it may either - * specify incorrect parameter names or not have names at all. - */ - foreach_iter(exec_list_iterator, iter, parameters) { - assert(((ir_instruction *) iter.get())->as_variable() != NULL); - - iter.remove(); - } - - new_params->move_nodes_to(¶meters); -} - - -ir_function::ir_function(const char *name) -{ - this->ir_type = ir_type_function; - this->name = ralloc_strdup(this, name); -} - - -bool -ir_function::has_user_signature() -{ - foreach_list(n, &this->signatures) { - ir_function_signature *const sig = (ir_function_signature *) n; - if (!sig->is_builtin) - return true; - } - return false; -} - - -ir_call * -ir_call::get_error_instruction(void *ctx) -{ - ir_call *call = new(ctx) ir_call; - - call->type = glsl_type::error_type; - return call; -} - -void -ir_call::set_callee(ir_function_signature *sig) -{ - assert((this->type == NULL) || (this->type == sig->return_type)); - - this->callee = sig; -} - -void -visit_exec_list(exec_list *list, ir_visitor *visitor) -{ - foreach_iter(exec_list_iterator, iter, *list) { - ((ir_instruction *)iter.get())->accept(visitor); - } -} - - -static void -steal_memory(ir_instruction *ir, void *new_ctx) -{ - ir_variable *var = ir->as_variable(); - ir_constant *constant = ir->as_constant(); - if (var != NULL && var->constant_value != NULL) - steal_memory(var->constant_value, ir); - - /* The components of aggregate constants are not visited by the normal - * visitor, so steal their values by hand. - */ - if (constant != NULL) { - if (constant->type->is_record()) { - foreach_iter(exec_list_iterator, iter, constant->components) { - ir_constant *field = (ir_constant *)iter.get(); - steal_memory(field, ir); - } - } else if (constant->type->is_array()) { - for (unsigned int i = 0; i < constant->type->length; i++) { - steal_memory(constant->array_elements[i], ir); - } - } - } - - ralloc_steal(new_ctx, ir); -} - - -void -reparent_ir(exec_list *list, void *mem_ctx) -{ - foreach_list(node, list) { - visit_tree((ir_instruction *) node, steal_memory, mem_ctx); - } -} - - -static ir_rvalue * -try_min_one(ir_rvalue *ir) -{ - ir_expression *expr = ir->as_expression(); - - if (!expr || expr->operation != ir_binop_min) - return NULL; - - if (expr->operands[0]->is_one()) - return expr->operands[1]; - - if (expr->operands[1]->is_one()) - return expr->operands[0]; - - return NULL; -} - -static ir_rvalue * -try_max_zero(ir_rvalue *ir) -{ - ir_expression *expr = ir->as_expression(); - - if (!expr || expr->operation != ir_binop_max) - return NULL; - - if (expr->operands[0]->is_zero()) - return expr->operands[1]; - - if (expr->operands[1]->is_zero()) - return expr->operands[0]; - - return NULL; -} - -ir_rvalue * -ir_rvalue::as_rvalue_to_saturate() -{ - ir_expression *expr = this->as_expression(); - - if (!expr) - return NULL; - - ir_rvalue *max_zero = try_max_zero(expr); - if (max_zero) { - return try_min_one(max_zero); - } else { - ir_rvalue *min_one = try_min_one(expr); - if (min_one) { - return try_max_zero(min_one); - } - } - - return NULL; -} +/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <string.h>
+#include "main/core.h" /* for MAX2 */
+#include "ir.h"
+#include "ir_visitor.h"
+#include "glsl_types.h"
+
+ir_rvalue::ir_rvalue()
+{
+ this->type = glsl_type::error_type;
+}
+
+bool ir_rvalue::is_zero() const
+{
+ return false;
+}
+
+bool ir_rvalue::is_one() const
+{
+ return false;
+}
+
+bool ir_rvalue::is_negative_one() const
+{
+ return false;
+}
+
+/**
+ * Modify the swizzle make to move one component to another
+ *
+ * \param m IR swizzle to be modified
+ * \param from Component in the RHS that is to be swizzled
+ * \param to Desired swizzle location of \c from
+ */
+static void
+update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to)
+{
+ switch (to) {
+ case 0: m.x = from; break;
+ case 1: m.y = from; break;
+ case 2: m.z = from; break;
+ case 3: m.w = from; break;
+ default: assert(!"Should not get here.");
+ }
+
+ m.num_components = MAX2(m.num_components, (to + 1));
+}
+
+void
+ir_assignment::set_lhs(ir_rvalue *lhs)
+{
+ void *mem_ctx = this;
+ bool swizzled = false;
+
+ while (lhs != NULL) {
+ ir_swizzle *swiz = lhs->as_swizzle();
+
+ if (swiz == NULL)
+ break;
+
+ unsigned write_mask = 0;
+ ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
+
+ for (unsigned i = 0; i < swiz->mask.num_components; i++) {
+ unsigned c = 0;
+
+ switch (i) {
+ case 0: c = swiz->mask.x; break;
+ case 1: c = swiz->mask.y; break;
+ case 2: c = swiz->mask.z; break;
+ case 3: c = swiz->mask.w; break;
+ default: assert(!"Should not get here.");
+ }
+
+ write_mask |= (((this->write_mask >> i) & 1) << c);
+ update_rhs_swizzle(rhs_swiz, i, c);
+ }
+
+ this->write_mask = write_mask;
+ lhs = swiz->val;
+
+ this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
+ swizzled = true;
+ }
+
+ if (swizzled) {
+ /* Now, RHS channels line up with the LHS writemask. Collapse it
+ * to just the channels that will be written.
+ */
+ ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 };
+ int rhs_chan = 0;
+ for (int i = 0; i < 4; i++) {
+ if (write_mask & (1 << i))
+ update_rhs_swizzle(rhs_swiz, i, rhs_chan++);
+ }
+ this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz);
+ }
+
+ assert((lhs == NULL) || lhs->as_dereference());
+
+ this->lhs = (ir_dereference *) lhs;
+}
+
+ir_variable *
+ir_assignment::whole_variable_written()
+{
+ ir_variable *v = this->lhs->whole_variable_referenced();
+
+ if (v == NULL)
+ return NULL;
+
+ if (v->type->is_scalar())
+ return v;
+
+ if (v->type->is_vector()) {
+ const unsigned mask = (1U << v->type->vector_elements) - 1;
+
+ if (mask != this->write_mask)
+ return NULL;
+ }
+
+ /* Either all the vector components are assigned or the variable is some
+ * composite type (and the whole thing is assigned.
+ */
+ return v;
+}
+
+ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs,
+ ir_rvalue *condition, unsigned write_mask)
+{
+ this->ir_type = ir_type_assignment;
+ this->condition = condition;
+ this->rhs = rhs;
+ this->lhs = lhs;
+ this->write_mask = write_mask;
+
+ if (lhs->type->is_scalar() || lhs->type->is_vector()) {
+ int lhs_components = 0;
+ for (int i = 0; i < 4; i++) {
+ if (write_mask & (1 << i))
+ lhs_components++;
+ }
+
+ assert(lhs_components == this->rhs->type->vector_elements);
+ }
+}
+
+ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs,
+ ir_rvalue *condition)
+{
+ this->ir_type = ir_type_assignment;
+ this->condition = condition;
+ this->rhs = rhs;
+
+ /* If the RHS is a vector type, assume that all components of the vector
+ * type are being written to the LHS. The write mask comes from the RHS
+ * because we can have a case where the LHS is a vec4 and the RHS is a
+ * vec3. In that case, the assignment is:
+ *
+ * (assign (...) (xyz) (var_ref lhs) (var_ref rhs))
+ */
+ if (rhs->type->is_vector())
+ this->write_mask = (1U << rhs->type->vector_elements) - 1;
+ else if (rhs->type->is_scalar())
+ this->write_mask = 1;
+ else
+ this->write_mask = 0;
+
+ this->set_lhs(lhs);
+}
+
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0)
+{
+ assert(get_num_operands(ir_expression_operation(op)) == 1);
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = NULL;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+}
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0, ir_rvalue *op1)
+{
+ assert(((op1 == NULL) && (get_num_operands(ir_expression_operation(op)) == 1))
+ || (get_num_operands(ir_expression_operation(op)) == 2));
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = op1;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+}
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *op0, ir_rvalue *op1,
+ ir_rvalue *op2, ir_rvalue *op3)
+{
+ this->ir_type = ir_type_expression;
+ this->type = type;
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = op1;
+ this->operands[2] = op2;
+ this->operands[3] = op3;
+}
+
+ir_expression::ir_expression(int op, ir_rvalue *op0)
+{
+ this->ir_type = ir_type_expression;
+
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = NULL;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+
+ assert(op <= ir_last_unop);
+
+ switch (this->operation) {
+ case ir_unop_bit_not:
+ case ir_unop_logic_not:
+ case ir_unop_neg:
+ case ir_unop_abs:
+ case ir_unop_sign:
+ case ir_unop_rcp:
+ case ir_unop_rsq:
+ case ir_unop_sqrt:
+ case ir_unop_exp:
+ case ir_unop_log:
+ case ir_unop_exp2:
+ case ir_unop_log2:
+ case ir_unop_trunc:
+ case ir_unop_ceil:
+ case ir_unop_floor:
+ case ir_unop_fract:
+ case ir_unop_round_even:
+ case ir_unop_sin:
+ case ir_unop_cos:
+ case ir_unop_sin_reduced:
+ case ir_unop_cos_reduced:
+ case ir_unop_dFdx:
+ case ir_unop_dFdy:
+ this->type = op0->type;
+ break;
+
+ case ir_unop_f2i:
+ case ir_unop_b2i:
+ this->type = glsl_type::get_instance(GLSL_TYPE_INT,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_unop_b2f:
+ case ir_unop_i2f:
+ case ir_unop_u2f:
+ this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_unop_f2b:
+ case ir_unop_i2b:
+ this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_unop_noise:
+ this->type = glsl_type::float_type;
+ break;
+
+ case ir_unop_any:
+ this->type = glsl_type::bool_type;
+ break;
+
+ default:
+ assert(!"not reached: missing automatic type setup for ir_expression");
+ this->type = op0->type;
+ break;
+ }
+}
+
+ir_expression::ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1)
+{
+ this->ir_type = ir_type_expression;
+
+ this->operation = ir_expression_operation(op);
+ this->operands[0] = op0;
+ this->operands[1] = op1;
+ this->operands[2] = NULL;
+ this->operands[3] = NULL;
+
+ assert(op > ir_last_unop);
+
+ switch (this->operation) {
+ case ir_binop_all_equal:
+ case ir_binop_any_nequal:
+ this->type = glsl_type::bool_type;
+ break;
+
+ case ir_binop_add:
+ case ir_binop_sub:
+ case ir_binop_min:
+ case ir_binop_max:
+ case ir_binop_pow:
+ case ir_binop_mul:
+ case ir_binop_div:
+ case ir_binop_mod:
+ if (op0->type->is_scalar()) {
+ this->type = op1->type;
+ } else if (op1->type->is_scalar()) {
+ this->type = op0->type;
+ } else {
+ /* FINISHME: matrix types */
+ assert(!op0->type->is_matrix() && !op1->type->is_matrix());
+ assert(op0->type == op1->type);
+ this->type = op0->type;
+ }
+ break;
+
+ case ir_binop_logic_and:
+ case ir_binop_logic_xor:
+ case ir_binop_logic_or:
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ if (op0->type->is_scalar()) {
+ this->type = op1->type;
+ } else if (op1->type->is_scalar()) {
+ this->type = op0->type;
+ }
+ break;
+
+ case ir_binop_equal:
+ case ir_binop_nequal:
+ case ir_binop_lequal:
+ case ir_binop_gequal:
+ case ir_binop_less:
+ case ir_binop_greater:
+ assert(op0->type == op1->type);
+ this->type = glsl_type::get_instance(GLSL_TYPE_BOOL,
+ op0->type->vector_elements, 1);
+ break;
+
+ case ir_binop_dot:
+ this->type = glsl_type::float_type;
+ break;
+
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ this->type = op0->type;
+ break;
+
+ default:
+ assert(!"not reached: missing automatic type setup for ir_expression");
+ this->type = glsl_type::float_type;
+ }
+}
+
+unsigned int
+ir_expression::get_num_operands(ir_expression_operation op)
+{
+ assert(op <= ir_last_opcode);
+
+ if (op <= ir_last_unop)
+ return 1;
+
+ if (op <= ir_last_binop)
+ return 2;
+
+ if (op == ir_quadop_vector)
+ return 4;
+
+ assert(false);
+ return 0;
+}
+
+static const char *const operator_strs[] = {
+ "~",
+ "!",
+ "neg",
+ "abs",
+ "sign",
+ "rcp",
+ "rsq",
+ "sqrt",
+ "exp",
+ "log",
+ "exp2",
+ "log2",
+ "f2i",
+ "i2f",
+ "f2b",
+ "b2f",
+ "i2b",
+ "b2i",
+ "u2f",
+ "any",
+ "trunc",
+ "ceil",
+ "floor",
+ "fract",
+ "round_even",
+ "sin",
+ "cos",
+ "sin_reduced",
+ "cos_reduced",
+ "dFdx",
+ "dFdy",
+ "noise",
+ "+",
+ "-",
+ "*",
+ "/",
+ "%",
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "==",
+ "!=",
+ "all_equal",
+ "any_nequal",
+ "<<",
+ ">>",
+ "&",
+ "^",
+ "|",
+ "&&",
+ "^^",
+ "||",
+ "dot",
+ "min",
+ "max",
+ "pow",
+ "vector",
+};
+
+const char *ir_expression::operator_string(ir_expression_operation op)
+{
+ assert((unsigned int) op < Elements(operator_strs));
+ assert(Elements(operator_strs) == (ir_quadop_vector + 1));
+ return operator_strs[op];
+}
+
+const char *ir_expression::operator_string()
+{
+ return operator_string(this->operation);
+}
+
+const char*
+depth_layout_string(ir_depth_layout layout)
+{
+ switch(layout) {
+ case ir_depth_layout_none: return "";
+ case ir_depth_layout_any: return "depth_any";
+ case ir_depth_layout_greater: return "depth_greater";
+ case ir_depth_layout_less: return "depth_less";
+ case ir_depth_layout_unchanged: return "depth_unchanged";
+
+ default:
+ assert(0);
+ return "";
+ }
+}
+
+ir_expression_operation
+ir_expression::get_operator(const char *str)
+{
+ const int operator_count = sizeof(operator_strs) / sizeof(operator_strs[0]);
+ for (int op = 0; op < operator_count; op++) {
+ if (strcmp(str, operator_strs[op]) == 0)
+ return (ir_expression_operation) op;
+ }
+ return (ir_expression_operation) -1;
+}
+
+ir_constant::ir_constant()
+{
+ this->ir_type = ir_type_constant;
+}
+
+ir_constant::ir_constant(const struct glsl_type *type,
+ const ir_constant_data *data)
+{
+ assert((type->base_type >= GLSL_TYPE_UINT)
+ && (type->base_type <= GLSL_TYPE_BOOL));
+
+ this->ir_type = ir_type_constant;
+ this->type = type;
+ memcpy(& this->value, data, sizeof(this->value));
+}
+
+ir_constant::ir_constant(float f)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::float_type;
+ this->value.f[0] = f;
+ for (int i = 1; i < 16; i++) {
+ this->value.f[i] = 0;
+ }
+}
+
+ir_constant::ir_constant(unsigned int u)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::uint_type;
+ this->value.u[0] = u;
+ for (int i = 1; i < 16; i++) {
+ this->value.u[i] = 0;
+ }
+}
+
+ir_constant::ir_constant(int i)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::int_type;
+ this->value.i[0] = i;
+ for (int i = 1; i < 16; i++) {
+ this->value.i[i] = 0;
+ }
+}
+
+ir_constant::ir_constant(bool b)
+{
+ this->ir_type = ir_type_constant;
+ this->type = glsl_type::bool_type;
+ this->value.b[0] = b;
+ for (int i = 1; i < 16; i++) {
+ this->value.b[i] = false;
+ }
+}
+
+ir_constant::ir_constant(const ir_constant *c, unsigned i)
+{
+ this->ir_type = ir_type_constant;
+ this->type = c->type->get_base_type();
+
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: this->value.u[0] = c->value.u[i]; break;
+ case GLSL_TYPE_INT: this->value.i[0] = c->value.i[i]; break;
+ case GLSL_TYPE_FLOAT: this->value.f[0] = c->value.f[i]; break;
+ case GLSL_TYPE_BOOL: this->value.b[0] = c->value.b[i]; break;
+ default: assert(!"Should not get here."); break;
+ }
+}
+
+ir_constant::ir_constant(const struct glsl_type *type, exec_list *value_list)
+{
+ this->ir_type = ir_type_constant;
+ this->type = type;
+
+ assert(type->is_scalar() || type->is_vector() || type->is_matrix()
+ || type->is_record() || type->is_array());
+
+ if (type->is_array()) {
+ this->array_elements = ralloc_array(this, ir_constant *, type->length);
+ unsigned i = 0;
+ foreach_list(node, value_list) {
+ ir_constant *value = (ir_constant *) node;
+ assert(value->as_constant() != NULL);
+
+ this->array_elements[i++] = value;
+ }
+ return;
+ }
+
+ /* If the constant is a record, the types of each of the entries in
+ * value_list must be a 1-for-1 match with the structure components. Each
+ * entry must also be a constant. Just move the nodes from the value_list
+ * to the list in the ir_constant.
+ */
+ /* FINISHME: Should there be some type checking and / or assertions here? */
+ /* FINISHME: Should the new constant take ownership of the nodes from
+ * FINISHME: value_list, or should it make copies?
+ */
+ if (type->is_record()) {
+ value_list->move_nodes_to(& this->components);
+ return;
+ }
+
+ for (unsigned i = 0; i < 16; i++) {
+ this->value.u[i] = 0;
+ }
+
+ ir_constant *value = (ir_constant *) (value_list->head);
+
+ /* Constructors with exactly one scalar argument are special for vectors
+ * and matrices. For vectors, the scalar value is replicated to fill all
+ * the components. For matrices, the scalar fills the components of the
+ * diagonal while the rest is filled with 0.
+ */
+ if (value->type->is_scalar() && value->next->is_tail_sentinel()) {
+ if (type->is_matrix()) {
+ /* Matrix - fill diagonal (rest is already set to 0) */
+ assert(type->base_type == GLSL_TYPE_FLOAT);
+ for (unsigned i = 0; i < type->matrix_columns; i++)
+ this->value.f[i * type->vector_elements + i] = value->value.f[0];
+ } else {
+ /* Vector or scalar - fill all components */
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ for (unsigned i = 0; i < type->components(); i++)
+ this->value.u[i] = value->value.u[0];
+ break;
+ case GLSL_TYPE_FLOAT:
+ for (unsigned i = 0; i < type->components(); i++)
+ this->value.f[i] = value->value.f[0];
+ break;
+ case GLSL_TYPE_BOOL:
+ for (unsigned i = 0; i < type->components(); i++)
+ this->value.b[i] = value->value.b[0];
+ break;
+ default:
+ assert(!"Should not get here.");
+ break;
+ }
+ }
+ return;
+ }
+
+ if (type->is_matrix() && value->type->is_matrix()) {
+ assert(value->next->is_tail_sentinel());
+
+ /* From section 5.4.2 of the GLSL 1.20 spec:
+ * "If a matrix is constructed from a matrix, then each component
+ * (column i, row j) in the result that has a corresponding component
+ * (column i, row j) in the argument will be initialized from there."
+ */
+ unsigned cols = MIN2(type->matrix_columns, value->type->matrix_columns);
+ unsigned rows = MIN2(type->vector_elements, value->type->vector_elements);
+ for (unsigned i = 0; i < cols; i++) {
+ for (unsigned j = 0; j < rows; j++) {
+ const unsigned src = i * value->type->vector_elements + j;
+ const unsigned dst = i * type->vector_elements + j;
+ this->value.f[dst] = value->value.f[src];
+ }
+ }
+
+ /* "All other components will be initialized to the identity matrix." */
+ for (unsigned i = cols; i < type->matrix_columns; i++)
+ this->value.f[i * type->vector_elements + i] = 1.0;
+
+ return;
+ }
+
+ /* Use each component from each entry in the value_list to initialize one
+ * component of the constant being constructed.
+ */
+ for (unsigned i = 0; i < type->components(); /* empty */) {
+ assert(value->as_constant() != NULL);
+ assert(!value->is_tail_sentinel());
+
+ for (unsigned j = 0; j < value->type->components(); j++) {
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ this->value.u[i] = value->get_uint_component(j);
+ break;
+ case GLSL_TYPE_INT:
+ this->value.i[i] = value->get_int_component(j);
+ break;
+ case GLSL_TYPE_FLOAT:
+ this->value.f[i] = value->get_float_component(j);
+ break;
+ case GLSL_TYPE_BOOL:
+ this->value.b[i] = value->get_bool_component(j);
+ break;
+ default:
+ /* FINISHME: What to do? Exceptions are not the answer.
+ */
+ break;
+ }
+
+ i++;
+ if (i >= type->components())
+ break;
+ }
+
+ value = (ir_constant *) value->next;
+ }
+}
+
+ir_constant *
+ir_constant::zero(void *mem_ctx, const glsl_type *type)
+{
+ assert(type->is_numeric() || type->is_boolean());
+
+ ir_constant *c = new(mem_ctx) ir_constant;
+ c->type = type;
+ memset(&c->value, 0, sizeof(c->value));
+
+ return c;
+}
+
+bool
+ir_constant::get_bool_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return this->value.u[i] != 0;
+ case GLSL_TYPE_INT: return this->value.i[i] != 0;
+ case GLSL_TYPE_FLOAT: return ((int)this->value.f[i]) != 0;
+ case GLSL_TYPE_BOOL: return this->value.b[i];
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return false;
+}
+
+float
+ir_constant::get_float_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return (float) this->value.u[i];
+ case GLSL_TYPE_INT: return (float) this->value.i[i];
+ case GLSL_TYPE_FLOAT: return this->value.f[i];
+ case GLSL_TYPE_BOOL: return this->value.b[i] ? 1.0 : 0.0;
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return 0.0;
+}
+
+int
+ir_constant::get_int_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return this->value.u[i];
+ case GLSL_TYPE_INT: return this->value.i[i];
+ case GLSL_TYPE_FLOAT: return (int) this->value.f[i];
+ case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return 0;
+}
+
+unsigned
+ir_constant::get_uint_component(unsigned i) const
+{
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT: return this->value.u[i];
+ case GLSL_TYPE_INT: return this->value.i[i];
+ case GLSL_TYPE_FLOAT: return (unsigned) this->value.f[i];
+ case GLSL_TYPE_BOOL: return this->value.b[i] ? 1 : 0;
+ default: assert(!"Should not get here."); break;
+ }
+
+ /* Must return something to make the compiler happy. This is clearly an
+ * error case.
+ */
+ return 0;
+}
+
+ir_constant *
+ir_constant::get_array_element(unsigned i) const
+{
+ assert(this->type->is_array());
+
+ /* From page 35 (page 41 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Behavior is undefined if a shader subscripts an array with an index
+ * less than 0 or greater than or equal to the size the array was
+ * declared with."
+ *
+ * Most out-of-bounds accesses are removed before things could get this far.
+ * There are cases where non-constant array index values can get constant
+ * folded.
+ */
+ if (int(i) < 0)
+ i = 0;
+ else if (i >= this->type->length)
+ i = this->type->length - 1;
+
+ return array_elements[i];
+}
+
+ir_constant *
+ir_constant::get_record_field(const char *name)
+{
+ int idx = this->type->field_index(name);
+
+ if (idx < 0)
+ return NULL;
+
+ if (this->components.is_empty())
+ return NULL;
+
+ exec_node *node = this->components.head;
+ for (int i = 0; i < idx; i++) {
+ node = node->next;
+
+ /* If the end of the list is encountered before the element matching the
+ * requested field is found, return NULL.
+ */
+ if (node->is_tail_sentinel())
+ return NULL;
+ }
+
+ return (ir_constant *) node;
+}
+
+
+bool
+ir_constant::has_value(const ir_constant *c) const
+{
+ if (this->type != c->type)
+ return false;
+
+ if (this->type->is_array()) {
+ for (unsigned i = 0; i < this->type->length; i++) {
+ if (!this->array_elements[i]->has_value(c->array_elements[i]))
+ return false;
+ }
+ return true;
+ }
+
+ if (this->type->base_type == GLSL_TYPE_STRUCT) {
+ const exec_node *a_node = this->components.head;
+ const exec_node *b_node = c->components.head;
+
+ while (!a_node->is_tail_sentinel()) {
+ assert(!b_node->is_tail_sentinel());
+
+ const ir_constant *const a_field = (ir_constant *) a_node;
+ const ir_constant *const b_field = (ir_constant *) b_node;
+
+ if (!a_field->has_value(b_field))
+ return false;
+
+ a_node = a_node->next;
+ b_node = b_node->next;
+ }
+
+ return true;
+ }
+
+ for (unsigned i = 0; i < this->type->components(); i++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_UINT:
+ if (this->value.u[i] != c->value.u[i])
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[i] != c->value.i[i])
+ return false;
+ break;
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[i] != c->value.f[i])
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[i] != c->value.b[i])
+ return false;
+ break;
+ default:
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+ir_constant::is_zero() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != 0.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != 0)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (this->value.u[c] != 0)
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[c] != false)
+ return false;
+ break;
+ default:
+ /* The only other base types are structures, arrays, and samplers.
+ * Samplers cannot be constants, and the others should have been
+ * filtered out above.
+ */
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+ir_constant::is_one() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != 1.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != 1)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (this->value.u[c] != 1)
+ return false;
+ break;
+ case GLSL_TYPE_BOOL:
+ if (this->value.b[c] != true)
+ return false;
+ break;
+ default:
+ /* The only other base types are structures, arrays, and samplers.
+ * Samplers cannot be constants, and the others should have been
+ * filtered out above.
+ */
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+ir_constant::is_negative_one() const
+{
+ if (!this->type->is_scalar() && !this->type->is_vector())
+ return false;
+
+ if (this->type->is_boolean())
+ return false;
+
+ for (unsigned c = 0; c < this->type->vector_elements; c++) {
+ switch (this->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ if (this->value.f[c] != -1.0)
+ return false;
+ break;
+ case GLSL_TYPE_INT:
+ if (this->value.i[c] != -1)
+ return false;
+ break;
+ case GLSL_TYPE_UINT:
+ if (int(this->value.u[c]) != -1)
+ return false;
+ break;
+ default:
+ /* The only other base types are structures, arrays, samplers, and
+ * booleans. Samplers cannot be constants, and the others should
+ * have been filtered out above.
+ */
+ assert(!"Should not get here.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+ir_loop::ir_loop()
+{
+ this->ir_type = ir_type_loop;
+ this->cmp = ir_unop_neg;
+ this->from = NULL;
+ this->to = NULL;
+ this->increment = NULL;
+ this->counter = NULL;
+}
+
+
+ir_dereference_variable::ir_dereference_variable(ir_variable *var)
+{
+ this->ir_type = ir_type_dereference_variable;
+ this->var = var;
+ this->type = (var != NULL) ? var->type : glsl_type::error_type;
+}
+
+
+ir_dereference_array::ir_dereference_array(ir_rvalue *value,
+ ir_rvalue *array_index)
+{
+ this->ir_type = ir_type_dereference_array;
+ this->array_index = array_index;
+ this->set_array(value);
+}
+
+
+ir_dereference_array::ir_dereference_array(ir_variable *var,
+ ir_rvalue *array_index)
+{
+ void *ctx = ralloc_parent(var);
+
+ this->ir_type = ir_type_dereference_array;
+ this->array_index = array_index;
+ this->set_array(new(ctx) ir_dereference_variable(var));
+}
+
+
+void
+ir_dereference_array::set_array(ir_rvalue *value)
+{
+ this->array = value;
+ this->type = glsl_type::error_type;
+
+ if (this->array != NULL) {
+ const glsl_type *const vt = this->array->type;
+
+ if (vt->is_array()) {
+ type = vt->element_type();
+ } else if (vt->is_matrix()) {
+ type = vt->column_type();
+ } else if (vt->is_vector()) {
+ type = vt->get_base_type();
+ }
+ }
+}
+
+
+ir_dereference_record::ir_dereference_record(ir_rvalue *value,
+ const char *field)
+{
+ this->ir_type = ir_type_dereference_record;
+ this->record = value;
+ this->field = ralloc_strdup(this, field);
+ this->type = (this->record != NULL)
+ ? this->record->type->field_type(field) : glsl_type::error_type;
+}
+
+
+ir_dereference_record::ir_dereference_record(ir_variable *var,
+ const char *field)
+{
+ void *ctx = ralloc_parent(var);
+
+ this->ir_type = ir_type_dereference_record;
+ this->record = new(ctx) ir_dereference_variable(var);
+ this->field = ralloc_strdup(this, field);
+ this->type = (this->record != NULL)
+ ? this->record->type->field_type(field) : glsl_type::error_type;
+}
+
+bool type_contains_sampler(const glsl_type *type)
+{
+ if (type->is_array()) {
+ return type_contains_sampler(type->fields.array);
+ } else if (type->is_record()) {
+ for (unsigned int i = 0; i < type->length; i++) {
+ if (type_contains_sampler(type->fields.structure[i].type))
+ return true;
+ }
+ return false;
+ } else {
+ return type->is_sampler();
+ }
+}
+
+bool
+ir_dereference::is_lvalue()
+{
+ ir_variable *var = this->variable_referenced();
+
+ /* Every l-value derference chain eventually ends in a variable.
+ */
+ if ((var == NULL) || var->read_only)
+ return false;
+
+ if (this->type->is_array() && !var->array_lvalue)
+ return false;
+
+ /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Samplers cannot be treated as l-values; hence cannot be used
+ * as out or inout function parameters, nor can they be
+ * assigned into."
+ */
+ if (type_contains_sampler(this->type))
+ return false;
+
+ return true;
+}
+
+
+const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf" };
+
+const char *ir_texture::opcode_string()
+{
+ assert((unsigned int) op <=
+ sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]));
+ return tex_opcode_strs[op];
+}
+
+ir_texture_opcode
+ir_texture::get_opcode(const char *str)
+{
+ const int count = sizeof(tex_opcode_strs) / sizeof(tex_opcode_strs[0]);
+ for (int op = 0; op < count; op++) {
+ if (strcmp(str, tex_opcode_strs[op]) == 0)
+ return (ir_texture_opcode) op;
+ }
+ return (ir_texture_opcode) -1;
+}
+
+
+void
+ir_texture::set_sampler(ir_dereference *sampler, const glsl_type *type)
+{
+ assert(sampler != NULL);
+ assert(type != NULL);
+ this->sampler = sampler;
+ this->type = type;
+
+ assert(sampler->type->sampler_type == type->base_type);
+ if (sampler->type->sampler_shadow)
+ assert(type->vector_elements == 4 || type->vector_elements == 1);
+ else
+ assert(type->vector_elements == 4);
+}
+
+
+void
+ir_swizzle::init_mask(const unsigned *comp, unsigned count)
+{
+ assert((count >= 1) && (count <= 4));
+
+ memset(&this->mask, 0, sizeof(this->mask));
+ this->mask.num_components = count;
+
+ unsigned dup_mask = 0;
+ switch (count) {
+ case 4:
+ assert(comp[3] <= 3);
+ dup_mask |= (1U << comp[3])
+ & ((1U << comp[0]) | (1U << comp[1]) | (1U << comp[2]));
+ this->mask.w = comp[3];
+
+ case 3:
+ assert(comp[2] <= 3);
+ dup_mask |= (1U << comp[2])
+ & ((1U << comp[0]) | (1U << comp[1]));
+ this->mask.z = comp[2];
+
+ case 2:
+ assert(comp[1] <= 3);
+ dup_mask |= (1U << comp[1])
+ & ((1U << comp[0]));
+ this->mask.y = comp[1];
+
+ case 1:
+ assert(comp[0] <= 3);
+ this->mask.x = comp[0];
+ }
+
+ this->mask.has_duplicates = dup_mask != 0;
+
+ /* Based on the number of elements in the swizzle and the base type
+ * (i.e., float, int, unsigned, or bool) of the vector being swizzled,
+ * generate the type of the resulting value.
+ */
+ type = glsl_type::get_instance(val->type->base_type, mask.num_components, 1);
+}
+
+ir_swizzle::ir_swizzle(ir_rvalue *val, unsigned x, unsigned y, unsigned z,
+ unsigned w, unsigned count)
+ : val(val)
+{
+ const unsigned components[4] = { x, y, z, w };
+ this->ir_type = ir_type_swizzle;
+ this->init_mask(components, count);
+}
+
+ir_swizzle::ir_swizzle(ir_rvalue *val, const unsigned *comp,
+ unsigned count)
+ : val(val)
+{
+ this->ir_type = ir_type_swizzle;
+ this->init_mask(comp, count);
+}
+
+ir_swizzle::ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask)
+{
+ this->ir_type = ir_type_swizzle;
+ this->val = val;
+ this->mask = mask;
+ this->type = glsl_type::get_instance(val->type->base_type,
+ mask.num_components, 1);
+}
+
+#define X 1
+#define R 5
+#define S 9
+#define I 13
+
+ir_swizzle *
+ir_swizzle::create(ir_rvalue *val, const char *str, unsigned vector_length)
+{
+ void *ctx = ralloc_parent(val);
+
+ /* For each possible swizzle character, this table encodes the value in
+ * \c idx_map that represents the 0th element of the vector. For invalid
+ * swizzle characters (e.g., 'k'), a special value is used that will allow
+ * detection of errors.
+ */
+ static const unsigned char base_idx[26] = {
+ /* a b c d e f g h i j k l m */
+ R, R, I, I, I, I, R, I, I, I, I, I, I,
+ /* n o p q r s t u v w x y z */
+ I, I, S, S, R, S, S, I, I, X, X, X, X
+ };
+
+ /* Each valid swizzle character has an entry in the previous table. This
+ * table encodes the base index encoded in the previous table plus the actual
+ * index of the swizzle character. When processing swizzles, the first
+ * character in the string is indexed in the previous table. Each character
+ * in the string is indexed in this table, and the value found there has the
+ * value form the first table subtracted. The result must be on the range
+ * [0,3].
+ *
+ * For example, the string "wzyx" will get X from the first table. Each of
+ * the charcaters will get X+3, X+2, X+1, and X+0 from this table. After
+ * subtraction, the swizzle values are { 3, 2, 1, 0 }.
+ *
+ * The string "wzrg" will get X from the first table. Each of the characters
+ * will get X+3, X+2, R+0, and R+1 from this table. After subtraction, the
+ * swizzle values are { 3, 2, 4, 5 }. Since 4 and 5 are outside the range
+ * [0,3], the error is detected.
+ */
+ static const unsigned char idx_map[26] = {
+ /* a b c d e f g h i j k l m */
+ R+3, R+2, 0, 0, 0, 0, R+1, 0, 0, 0, 0, 0, 0,
+ /* n o p q r s t u v w x y z */
+ 0, 0, S+2, S+3, R+0, S+0, S+1, 0, 0, X+3, X+0, X+1, X+2
+ };
+
+ int swiz_idx[4] = { 0, 0, 0, 0 };
+ unsigned i;
+
+
+ /* Validate the first character in the swizzle string and look up the base
+ * index value as described above.
+ */
+ if ((str[0] < 'a') || (str[0] > 'z'))
+ return NULL;
+
+ const unsigned base = base_idx[str[0] - 'a'];
+
+
+ for (i = 0; (i < 4) && (str[i] != '\0'); i++) {
+ /* Validate the next character, and, as described above, convert it to a
+ * swizzle index.
+ */
+ if ((str[i] < 'a') || (str[i] > 'z'))
+ return NULL;
+
+ swiz_idx[i] = idx_map[str[i] - 'a'] - base;
+ if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length))
+ return NULL;
+ }
+
+ if (str[i] != '\0')
+ return NULL;
+
+ return new(ctx) ir_swizzle(val, swiz_idx[0], swiz_idx[1], swiz_idx[2],
+ swiz_idx[3], i);
+}
+
+#undef X
+#undef R
+#undef S
+#undef I
+
+ir_variable *
+ir_swizzle::variable_referenced()
+{
+ return this->val->variable_referenced();
+}
+
+
+ir_variable::ir_variable(const struct glsl_type *type, const char *name,
+ ir_variable_mode mode)
+ : max_array_access(0), read_only(false), centroid(false), invariant(false),
+ mode(mode), interpolation(ir_var_smooth), array_lvalue(false)
+{
+ this->ir_type = ir_type_variable;
+ this->type = type;
+ this->name = ralloc_strdup(this, name);
+ this->explicit_location = false;
+ this->location = -1;
+ this->warn_extension = NULL;
+ this->constant_value = NULL;
+ this->origin_upper_left = false;
+ this->pixel_center_integer = false;
+ this->depth_layout = ir_depth_layout_none;
+ this->used = false;
+
+ if (type && type->base_type == GLSL_TYPE_SAMPLER)
+ this->read_only = true;
+}
+
+
+const char *
+ir_variable::interpolation_string() const
+{
+ switch (this->interpolation) {
+ case ir_var_smooth: return "smooth";
+ case ir_var_flat: return "flat";
+ case ir_var_noperspective: return "noperspective";
+ }
+
+ assert(!"Should not get here.");
+ return "";
+}
+
+
+unsigned
+ir_variable::component_slots() const
+{
+ /* FINISHME: Sparsely accessed arrays require fewer slots. */
+ return this->type->component_slots();
+}
+
+
+ir_function_signature::ir_function_signature(const glsl_type *return_type)
+ : return_type(return_type), is_defined(false), _function(NULL)
+{
+ this->ir_type = ir_type_function_signature;
+ this->is_builtin = false;
+}
+
+
+static bool
+modes_match(unsigned a, unsigned b)
+{
+ if (a == b)
+ return true;
+
+ /* Accept "in" vs. "const in" */
+ if ((a == ir_var_const_in && b == ir_var_in) ||
+ (b == ir_var_const_in && a == ir_var_in))
+ return true;
+
+ return false;
+}
+
+
+const char *
+ir_function_signature::qualifiers_match(exec_list *params)
+{
+ exec_list_iterator iter_a = parameters.iterator();
+ exec_list_iterator iter_b = params->iterator();
+
+ /* check that the qualifiers match. */
+ while (iter_a.has_next()) {
+ ir_variable *a = (ir_variable *)iter_a.get();
+ ir_variable *b = (ir_variable *)iter_b.get();
+
+ if (a->read_only != b->read_only ||
+ !modes_match(a->mode, b->mode) ||
+ a->interpolation != b->interpolation ||
+ a->centroid != b->centroid) {
+
+ /* parameter a's qualifiers don't match */
+ return a->name;
+ }
+
+ iter_a.next();
+ iter_b.next();
+ }
+ return NULL;
+}
+
+
+void
+ir_function_signature::replace_parameters(exec_list *new_params)
+{
+ /* Destroy all of the previous parameter information. If the previous
+ * parameter information comes from the function prototype, it may either
+ * specify incorrect parameter names or not have names at all.
+ */
+ foreach_iter(exec_list_iterator, iter, parameters) {
+ assert(((ir_instruction *) iter.get())->as_variable() != NULL);
+
+ iter.remove();
+ }
+
+ new_params->move_nodes_to(¶meters);
+}
+
+
+ir_function::ir_function(const char *name)
+{
+ this->ir_type = ir_type_function;
+ this->name = ralloc_strdup(this, name);
+}
+
+
+bool
+ir_function::has_user_signature()
+{
+ foreach_list(n, &this->signatures) {
+ ir_function_signature *const sig = (ir_function_signature *) n;
+ if (!sig->is_builtin)
+ return true;
+ }
+ return false;
+}
+
+
+ir_call *
+ir_call::get_error_instruction(void *ctx)
+{
+ ir_call *call = new(ctx) ir_call;
+
+ call->type = glsl_type::error_type;
+ return call;
+}
+
+void
+ir_call::set_callee(ir_function_signature *sig)
+{
+ assert((this->type == NULL) || (this->type == sig->return_type));
+
+ this->callee = sig;
+}
+
+void
+visit_exec_list(exec_list *list, ir_visitor *visitor)
+{
+ foreach_iter(exec_list_iterator, iter, *list) {
+ ((ir_instruction *)iter.get())->accept(visitor);
+ }
+}
+
+
+static void
+steal_memory(ir_instruction *ir, void *new_ctx)
+{
+ ir_variable *var = ir->as_variable();
+ ir_constant *constant = ir->as_constant();
+ if (var != NULL && var->constant_value != NULL)
+ steal_memory(var->constant_value, ir);
+
+ /* The components of aggregate constants are not visited by the normal
+ * visitor, so steal their values by hand.
+ */
+ if (constant != NULL) {
+ if (constant->type->is_record()) {
+ foreach_iter(exec_list_iterator, iter, constant->components) {
+ ir_constant *field = (ir_constant *)iter.get();
+ steal_memory(field, ir);
+ }
+ } else if (constant->type->is_array()) {
+ for (unsigned int i = 0; i < constant->type->length; i++) {
+ steal_memory(constant->array_elements[i], ir);
+ }
+ }
+ }
+
+ ralloc_steal(new_ctx, ir);
+}
+
+
+void
+reparent_ir(exec_list *list, void *mem_ctx)
+{
+ foreach_list(node, list) {
+ visit_tree((ir_instruction *) node, steal_memory, mem_ctx);
+ }
+}
+
+
+static ir_rvalue *
+try_min_one(ir_rvalue *ir)
+{
+ ir_expression *expr = ir->as_expression();
+
+ if (!expr || expr->operation != ir_binop_min)
+ return NULL;
+
+ if (expr->operands[0]->is_one())
+ return expr->operands[1];
+
+ if (expr->operands[1]->is_one())
+ return expr->operands[0];
+
+ return NULL;
+}
+
+static ir_rvalue *
+try_max_zero(ir_rvalue *ir)
+{
+ ir_expression *expr = ir->as_expression();
+
+ if (!expr || expr->operation != ir_binop_max)
+ return NULL;
+
+ if (expr->operands[0]->is_zero())
+ return expr->operands[1];
+
+ if (expr->operands[1]->is_zero())
+ return expr->operands[0];
+
+ return NULL;
+}
+
+ir_rvalue *
+ir_rvalue::as_rvalue_to_saturate()
+{
+ ir_expression *expr = this->as_expression();
+
+ if (!expr)
+ return NULL;
+
+ ir_rvalue *max_zero = try_max_zero(expr);
+ if (max_zero) {
+ return try_min_one(max_zero);
+ } else {
+ ir_rvalue *min_one = try_min_one(expr);
+ if (min_one) {
+ return try_max_zero(min_one);
+ }
+ }
+
+ return NULL;
+}
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index f2f902c0a..72e3e35c4 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -1,1640 +1,1640 @@ -/* -*- c++ -*- */ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#pragma once -#ifndef IR_H -#define IR_H - -#include <stdio.h> -#include <stdlib.h> - -#include "ralloc.h" -#include "glsl_types.h" -#include "list.h" -#include "ir_visitor.h" -#include "ir_hierarchical_visitor.h" - -/** - * \defgroup IR Intermediate representation nodes - * - * @{ - */ - -/** - * Class tags - * - * Each concrete class derived from \c ir_instruction has a value in this - * enumerant. The value for the type is stored in \c ir_instruction::ir_type - * by the constructor. While using type tags is not very C++, it is extremely - * convenient. For example, during debugging you can simply inspect - * \c ir_instruction::ir_type to find out the actual type of the object. - * - * In addition, it is possible to use a switch-statement based on \c - * \c ir_instruction::ir_type to select different behavior for different object - * types. For functions that have only slight differences for several object - * 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_expression, - 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_max /**< maximum ir_type enum number, for validation */ -}; - -/** - * Base class of all IR instructions - */ -class ir_instruction : public exec_node { -public: - enum ir_node_type ir_type; - const struct glsl_type *type; - - /** ir_print_visitor helper for debugging. */ - void print(void) 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; - - /** - * \name IR instruction downcast functions - * - * These functions either cast the object to a derived class or return - * \c NULL if the object's type does not match the specified derived class. - * 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_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; } - /*@}*/ - -protected: - ir_instruction() - { - ir_type = ir_type_unset; - type = NULL; - } -}; - - -class ir_rvalue : public ir_instruction { -public: - virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const = 0; - - virtual ir_constant *constant_expression_value() = 0; - - virtual ir_rvalue * as_rvalue() - { - return this; - } - - ir_rvalue *as_rvalue_to_saturate(); - - virtual bool is_lvalue() - { - return false; - } - - /** - * Get the variable that is ultimately referenced by an r-value - */ - virtual ir_variable *variable_referenced() - { - return NULL; - } - - - /** - * If an r-value is a reference to a whole variable, get that variable - * - * \return - * Pointer to a variable that is completely dereferenced by the r-value. If - * the r-value is not a dereference or the dereference does not access the - * entire variable (i.e., it's just one array element, struct field), \c NULL - * is returned. - */ - virtual ir_variable *whole_variable_referenced() - { - return NULL; - } - - /** - * Determine if an r-value has the value zero - * - * 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 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 - */ - virtual bool is_zero() const; - - /** - * Determine if an r-value has the value one - * - * 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 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 - */ - virtual bool is_one() const; - - /** - * Determine if an r-value has the value negative one - * - * 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 all elements set to the value - * negative one. For boolean times, the result is always \c false. - * - * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_one - */ - virtual bool is_negative_one() const; - -protected: - ir_rvalue(); -}; - - -/** - * 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_in, - ir_var_out, - ir_var_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. */ -}; - -enum ir_variable_interpolation { - ir_var_smooth = 0, - ir_var_flat, - ir_var_noperspective -}; - -/** - * \brief Layout qualifiers for gl_FragDepth. - * - * The AMD_conservative_depth extension allows gl_FragDepth to be redeclared - * with a layout qualifier. - */ -enum ir_depth_layout { - ir_depth_layout_none, /**< No depth layout is specified. */ - ir_depth_layout_any, - ir_depth_layout_greater, - ir_depth_layout_less, - ir_depth_layout_unchanged -}; - -/** - * \brief Convert depth layout qualifier to string. - */ -const char* -depth_layout_string(ir_depth_layout layout); - -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 should only be used on a shader input or output variable. - */ - const char *interpolation_string() const; - - /** - * Calculate the number of slots required to hold this variable - * - * This is used to determine how many uniform or varying locations a variable - * occupies. The count is in units of floating point components. - */ - unsigned component_slots() const; - - /** - * Delcared name of the variable - */ - const char *name; - - /** - * Highest element accessed with a constant expression array index - * - * Not used for non-array variables. - */ - unsigned max_array_access; - - /** - * 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; - - /** - * 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. - */ - unsigned used:1; - - /** - * Storage class of the variable. - * - * \sa ir_variable_mode - */ - unsigned mode:3; - - /** - * Interpolation mode for shader inputs / outputs - * - * \sa ir_variable_interpolation - */ - unsigned interpolation:2; - - /** - * Flag that the whole array is assignable - * - * In GLSL 1.20 and later whole arrays are assignable (and comparable for - * equality). This flag enables this behavior. - */ - unsigned array_lvalue:1; - - /** - * \name ARB_fragment_coord_conventions - * @{ - */ - unsigned origin_upper_left:1; - unsigned pixel_center_integer: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; - - /** - * 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; - - /** - * 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_vert_result. - * - Fragment shader input: one of the values from \c gl_frag_attrib. - * - Fragment shader output: one of the values from \c gl_frag_result. - * - Uniforms: Per-stage 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; - - /** - * 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_value; -}; - - -/*@{*/ -/** - * The representation of a function instance; may be the full definition or - * simply a prototype. - */ -class ir_function_signature : public ir_instruction { - /* An ir_function_signature will be part of the list of signatures in - * an ir_function. - */ -public: - ir_function_signature(const glsl_type *return_type); - - virtual ir_function_signature *clone(void *mem_ctx, - struct hash_table *ht) const; - ir_function_signature *clone_prototype(void *mem_ctx, - struct hash_table *ht) const; - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - /** - * Get the name of the function for which this is a signature - */ - const char *function_name() const; - - /** - * Get a handle to the function for which this is a signature - * - * There is no setter function, this function returns a \c const pointer, - * and \c ir_function_signature::_function is private for a reason. The - * only way to make a connection between a function and function signature - * is via \c ir_function::add_signature. This helps ensure that certain - * invariants (i.e., a function signature is in the list of signatures for - * its \c _function) are met. - * - * \sa ir_function::add_signature - */ - inline const class ir_function *function() const - { - return this->_function; - } - - /** - * Check whether the qualifiers match between this signature's parameters - * and the supplied parameter list. If not, returns the name of the first - * parameter with mismatched qualifiers (for use in error messages). - */ - const char *qualifiers_match(exec_list *params); - - /** - * Replace the current parameter list with the given one. This is useful - * if the current information came from a prototype, and either has invalid - * or missing parameter names. - */ - void replace_parameters(exec_list *new_params); - - /** - * Function return type. - * - * \note This discards the optional precision qualifier. - */ - const struct glsl_type *return_type; - - /** - * List of ir_variable of function parameters. - * - * This represents the storage. The paramaters passed in a particular - * call will be in ir_call::actual_paramaters. - */ - struct exec_list parameters; - - /** Whether or not this function has a body (which may be empty). */ - unsigned is_defined:1; - - /** Whether or not this function signature is a built-in. */ - unsigned is_builtin:1; - - /** Body of instructions in the function. */ - struct exec_list body; - -private: - /** Function of which this signature is one overload. */ - class ir_function *_function; - - friend class ir_function; -}; - - -/** - * Header for tracking multiple overloaded functions with the same name. - * Contains a list of ir_function_signatures representing each of the - * actual functions. - */ -class ir_function : public ir_instruction { -public: - ir_function(const char *name); - - virtual ir_function *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); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - void add_signature(ir_function_signature *sig) - { - sig->_function = 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. - */ - ir_function_signature *matching_signature(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); - - /** - * Name of the function. - */ - const char *name; - - /** Whether or not this function has a signature that isn't a built-in. */ - bool has_user_signature(); - - /** - * List of ir_function_signature for each overloaded function with this name. - */ - struct exec_list signatures; -}; - -inline const char *ir_function_signature::function_name() const -{ - return this->_function->name; -} -/*@}*/ - - -/** - * IR instruction representing high-level if-statements - */ -class ir_if : public ir_instruction { -public: - ir_if(ir_rvalue *condition) - : 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 *); - - ir_rvalue *condition; - /** List of ir_instruction for the body of the then branch */ - exec_list then_instructions; - /** List of ir_instruction for the body of the else branch */ - exec_list else_instructions; -}; - - -/** - * IR instruction representing a high-level loop structure. - */ -class ir_loop : public ir_instruction { -public: - ir_loop(); - - virtual ir_loop *clone(void *mem_ctx, struct hash_table *ht) const; - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - 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; - /*@}*/ -}; - - -class ir_assignment : public ir_instruction { -public: - ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, ir_rvalue *condition); - - /** - * Construct an assignment with an explicit write mask - * - * \note - * Since a write mask is supplied, the LHS must already be a bare - * \c ir_dereference. The cannot be any swizzles in the LHS. - */ - ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, ir_rvalue *condition, - unsigned write_mask); - - virtual ir_assignment *clone(void *mem_ctx, struct hash_table *ht) const; - - virtual ir_constant *constant_expression_value(); - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - virtual ir_assignment * as_assignment() - { - return this; - } - - /** - * Get a whole variable written by an assignment - * - * If the LHS of the assignment writes a whole variable, the variable is - * returned. Otherwise \c NULL is returned. Examples of whole-variable - * assignment are: - * - * - Assigning to a scalar - * - Assigning to all components of a vector - * - Whole array (or matrix) assignment - * - Whole structure assignment - */ - ir_variable *whole_variable_written(); - - /** - * Set the LHS of an assignment - */ - void set_lhs(ir_rvalue *lhs); - - /** - * Left-hand side of the assignment. - * - * This should be treated as read only. If you need to set the LHS of an - * assignment, use \c ir_assignment::set_lhs. - */ - ir_dereference *lhs; - - /** - * Value being assigned - */ - ir_rvalue *rhs; - - /** - * Optional condition for the assignment. - */ - ir_rvalue *condition; - - - /** - * Component mask written - * - * For non-vector types in the LHS, this field will be zero. For vector - * types, a bit will be set for each component that is written. Note that - * for \c vec2 and \c vec3 types only the lower bits will ever be set. - * - * A partially-set write mask means that each enabled channel gets - * the value from a consecutive channel of the rhs. For example, - * to write just .xyw of gl_FrontColor with color: - * - * (assign (constant bool (1)) (xyw) - * (var_ref gl_FragColor) - * (swiz xyw (var_ref color))) - */ - unsigned write_mask:4; -}; - -/* Update ir_expression::num_operands() and operator_strs when - * updating this list. - */ -enum ir_expression_operation { - ir_unop_bit_not, - ir_unop_logic_not, - ir_unop_neg, - ir_unop_abs, - ir_unop_sign, - ir_unop_rcp, - ir_unop_rsq, - ir_unop_sqrt, - ir_unop_exp, /**< Log base e on gentype */ - ir_unop_log, /**< Natural log on gentype */ - ir_unop_exp2, - ir_unop_log2, - ir_unop_f2i, /**< Float-to-integer conversion. */ - ir_unop_i2f, /**< Integer-to-float conversion. */ - ir_unop_f2b, /**< Float-to-boolean conversion */ - ir_unop_b2f, /**< Boolean-to-float conversion */ - ir_unop_i2b, /**< int-to-boolean conversion */ - ir_unop_b2i, /**< Boolean-to-int conversion */ - ir_unop_u2f, /**< Unsigned-to-float conversion. */ - ir_unop_any, - - /** - * \name Unary floating-point rounding operations. - */ - /*@{*/ - ir_unop_trunc, - ir_unop_ceil, - ir_unop_floor, - ir_unop_fract, - ir_unop_round_even, - /*@}*/ - - /** - * \name Trigonometric operations. - */ - /*@{*/ - ir_unop_sin, - ir_unop_cos, - ir_unop_sin_reduced, /**< Reduced range sin. [-pi, pi] */ - ir_unop_cos_reduced, /**< Reduced range cos. [-pi, pi] */ - /*@}*/ - - /** - * \name Partial derivatives. - */ - /*@{*/ - ir_unop_dFdx, - ir_unop_dFdy, - /*@}*/ - - ir_unop_noise, - - /** - * A sentinel marking the last of the unary operations. - */ - ir_last_unop = ir_unop_noise, - - ir_binop_add, - ir_binop_sub, - ir_binop_mul, - ir_binop_div, - - /** - * Takes one of two combinations of arguments: - * - * - mod(vecN, vecN) - * - mod(vecN, float) - * - * Does not take integer types. - */ - ir_binop_mod, - - /** - * \name Binary comparison operators which return a boolean vector. - * The type of both operands must be equal. - */ - /*@{*/ - ir_binop_less, - ir_binop_greater, - ir_binop_lequal, - ir_binop_gequal, - ir_binop_equal, - ir_binop_nequal, - /** - * Returns single boolean for whether all components of operands[0] - * equal the components of operands[1]. - */ - ir_binop_all_equal, - /** - * Returns single boolean for whether any component of operands[0] - * is not equal to the corresponding component of operands[1]. - */ - ir_binop_any_nequal, - /*@}*/ - - /** - * \name Bit-wise binary operations. - */ - /*@{*/ - ir_binop_lshift, - ir_binop_rshift, - ir_binop_bit_and, - ir_binop_bit_xor, - ir_binop_bit_or, - /*@}*/ - - ir_binop_logic_and, - ir_binop_logic_xor, - ir_binop_logic_or, - - ir_binop_dot, - ir_binop_min, - ir_binop_max, - - ir_binop_pow, - - /** - * A sentinel marking the last of the binary operations. - */ - ir_last_binop = ir_binop_pow, - - ir_quadop_vector, - - /** - * A sentinel marking the last of all operations. - */ - ir_last_opcode = ir_last_binop -}; - -class ir_expression : public ir_rvalue { -public: - /** - * Constructor for unary operation expressions - */ - ir_expression(int op, const struct glsl_type *type, ir_rvalue *); - ir_expression(int op, ir_rvalue *); - - /** - * Constructor for binary operation expressions - */ - ir_expression(int op, const struct glsl_type *type, - ir_rvalue *, ir_rvalue *); - ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1); - - /** - * Constructor for quad operator expressions - */ - ir_expression(int op, const struct glsl_type *type, - ir_rvalue *, ir_rvalue *, ir_rvalue *, ir_rvalue *); - - virtual ir_expression *as_expression() - { - return this; - } - - virtual ir_expression *clone(void *mem_ctx, struct hash_table *ht) const; - - /** - * Attempt to constant-fold the expression - * - * If the expression cannot be constant folded, this method will return - * \c NULL. - */ - virtual ir_constant *constant_expression_value(); - - /** - * Determine the number of operands used by an expression - */ - static unsigned int get_num_operands(ir_expression_operation); - - /** - * Determine the number of operands used by an expression - */ - unsigned int get_num_operands() const - { - return (this->operation == ir_quadop_vector) - ? this->type->vector_elements : get_num_operands(operation); - } - - /** - * Return a string representing this expression's operator. - */ - const char *operator_string(); - - /** - * Return a string representing this expression's operator. - */ - static const char *operator_string(ir_expression_operation); - - - /** - * Do a reverse-lookup to translate the given string into an operator. - */ - static ir_expression_operation get_operator(const char *); - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - ir_expression_operation operation; - ir_rvalue *operands[4]; -}; - - -/** - * IR instruction representing a function call - */ -class ir_call : public ir_rvalue { -public: - ir_call(ir_function_signature *callee, exec_list *actual_parameters) - : callee(callee) - { - ir_type = ir_type_call; - assert(callee->return_type != NULL); - type = callee->return_type; - actual_parameters->move_nodes_to(& this->actual_parameters); - } - - virtual ir_call *clone(void *mem_ctx, struct hash_table *ht) const; - - virtual ir_constant *constant_expression_value(); - - virtual ir_call *as_call() - { - return this; - } - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - /** - * Get a generic ir_call object when an error occurs - * - * Any allocation will be performed with 'ctx' as ralloc owner. - */ - static ir_call *get_error_instruction(void *ctx); - - /** - * 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. - */ - const char *callee_name() const - { - return callee->function_name(); - } - - /** - * Get the function signature bound to this function call - */ - ir_function_signature *get_callee() - { - return callee; - } - - /** - * Set the function call target - */ - void set_callee(ir_function_signature *sig); - - /** - * Generates an inline version of the function before @ir, - * returning the return value of the function. - */ - ir_rvalue *generate_inline(ir_instruction *ir); - - /* List of ir_rvalue of paramaters passed in this call. */ - exec_list actual_parameters; - -private: - ir_call() - : callee(NULL) - { - this->ir_type = ir_type_call; - } - - ir_function_signature *callee; -}; - - -/** - * \name Jump-like IR instructions. - * - * These include \c break, \c continue, \c return, and \c discard. - */ -/*@{*/ -class ir_jump : public ir_instruction { -protected: - ir_jump() - { - ir_type = ir_type_unset; - } -}; - -class ir_return : public ir_jump { -public: - ir_return() - : value(NULL) - { - this->ir_type = ir_type_return; - } - - ir_return(ir_rvalue *value) - : 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; - } - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - ir_rvalue *value; -}; - - -/** - * Jump instructions used inside loops - * - * These include \c break and \c continue. The \c break within a loop is - * different from the \c break within a switch-statement. - * - * \sa ir_switch_jump - */ -class ir_loop_jump : public ir_jump { -public: - enum jump_mode { - jump_break, - jump_continue - }; - - ir_loop_jump(jump_mode mode) - { - this->ir_type = ir_type_loop_jump; - this->mode = mode; - this->loop = loop; - } - - virtual ir_loop_jump *clone(void *mem_ctx, struct hash_table *) const; - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - bool is_break() const - { - return mode == jump_break; - } - - bool is_continue() const - { - return mode == jump_continue; - } - - /** Mode selector for the jump instruction. */ - enum jump_mode mode; -private: - /** Loop containing this break instruction. */ - ir_loop *loop; -}; - -/** - * IR instruction representing discard statements. - */ -class ir_discard : public ir_jump { -public: - ir_discard() - { - this->ir_type = ir_type_discard; - this->condition = NULL; - } - - ir_discard(ir_rvalue *cond) - { - this->ir_type = ir_type_discard; - this->condition = cond; - } - - virtual ir_discard *clone(void *mem_ctx, struct hash_table *ht) const; - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - virtual ir_discard *as_discard() - { - return this; - } - - ir_rvalue *condition; -}; -/*@}*/ - - -/** - * Texture sampling opcodes used in ir_texture - */ -enum ir_texture_opcode { - ir_tex, /**< Regular texture look-up */ - ir_txb, /**< Texture look-up with LOD bias */ - ir_txl, /**< Texture look-up with explicit LOD */ - ir_txd, /**< Texture look-up with partial derivatvies */ - ir_txf /**< Texel fetch with explicit LOD */ -}; - - -/** - * IR instruction to sample a texture - * - * The specific form of the IR instruction depends on the \c mode value - * selected from \c ir_texture_opcodes. In the printed IR, these will - * appear as: - * - * Texel offset (0 or an expression) - * | Projection divisor - * | | Shadow comparitor - * | | | - * v v v - * (tex <sampler> <coordinate> 0 1 ( )) - * (txb <sampler> <coordinate> 0 1 ( ) <bias>) - * (txl <sampler> <coordinate> 0 1 ( ) <lod>) - * (txd <sampler> <coordinate> 0 1 ( ) (dPdx dPdy)) - * (txf <sampler> <coordinate> 0 <lod>) - */ -class ir_texture : public ir_rvalue { -public: - ir_texture(enum ir_texture_opcode op) - : op(op), projector(NULL), shadow_comparitor(NULL), offset(NULL) - { - this->ir_type = ir_type_texture; - } - - virtual ir_texture *clone(void *mem_ctx, struct hash_table *) const; - - virtual ir_constant *constant_expression_value(); - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - /** - * Return a string representing the ir_texture_opcode. - */ - const char *opcode_string(); - - /** Set the sampler and infer the type. */ - void set_sampler(ir_dereference *sampler); - - /** - * Do a reverse-lookup to translate a string into an ir_texture_opcode. - */ - static ir_texture_opcode get_opcode(const char *); - - enum ir_texture_opcode op; - - /** Sampler to use for the texture access. */ - ir_dereference *sampler; - - /** Texture coordinate to sample */ - ir_rvalue *coordinate; - - /** - * Value used for projective divide. - * - * If there is no projective divide (the common case), this will be - * \c NULL. Optimization passes should check for this to point to a constant - * of 1.0 and replace that with \c NULL. - */ - ir_rvalue *projector; - - /** - * Coordinate used for comparison on shadow look-ups. - * - * If there is no shadow comparison, this will be \c NULL. For the - * \c ir_txf opcode, this *must* be \c NULL. - */ - ir_rvalue *shadow_comparitor; - - /** Texel offset. */ - ir_rvalue *offset; - - union { - ir_rvalue *lod; /**< Floating point LOD */ - ir_rvalue *bias; /**< Floating point LOD bias */ - struct { - ir_rvalue *dPdx; /**< Partial derivative of coordinate wrt X */ - ir_rvalue *dPdy; /**< Partial derivative of coordinate wrt Y */ - } grad; - } lod_info; -}; - - -struct ir_swizzle_mask { - unsigned x:2; - unsigned y:2; - unsigned z:2; - unsigned w:2; - - /** - * Number of components in the swizzle. - */ - unsigned num_components:3; - - /** - * Does the swizzle contain duplicate components? - * - * L-value swizzles cannot contain duplicate components. - */ - unsigned has_duplicates:1; -}; - - -class ir_swizzle : public ir_rvalue { -public: - ir_swizzle(ir_rvalue *, unsigned x, unsigned y, unsigned z, unsigned w, - unsigned count); - - ir_swizzle(ir_rvalue *val, const unsigned *components, unsigned count); - - ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask); - - virtual ir_swizzle *clone(void *mem_ctx, struct hash_table *) const; - - virtual ir_constant *constant_expression_value(); - - virtual ir_swizzle *as_swizzle() - { - return this; - } - - /** - * Construct an ir_swizzle from the textual representation. Can fail. - */ - static ir_swizzle *create(ir_rvalue *, const char *, unsigned vector_length); - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - bool is_lvalue() - { - return val->is_lvalue() && !mask.has_duplicates; - } - - /** - * Get the variable that is ultimately referenced by an r-value - */ - virtual ir_variable *variable_referenced(); - - ir_rvalue *val; - ir_swizzle_mask mask; - -private: - /** - * Initialize the mask component of a swizzle - * - * This is used by the \c ir_swizzle constructors. - */ - void init_mask(const unsigned *components, unsigned count); -}; - - -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(); - - /** - * Get the variable that is ultimately referenced by an r-value - */ - virtual ir_variable *variable_referenced() = 0; -}; - - -class ir_dereference_variable : public ir_dereference { -public: - ir_dereference_variable(ir_variable *var); - - virtual ir_dereference_variable *clone(void *mem_ctx, - struct hash_table *) const; - - virtual ir_constant *constant_expression_value(); - - virtual ir_dereference_variable *as_dereference_variable() - { - return this; - } - - /** - * Get the variable that is ultimately referenced by an r-value - */ - virtual ir_variable *variable_referenced() - { - return this->var; - } - - virtual ir_variable *whole_variable_referenced() - { - /* ir_dereference_variable objects always dereference the entire - * variable. However, if this dereference is dereferenced by anything - * else, the complete deferefernce chain is not a whole-variable - * dereference. This method should only be called on the top most - * ir_rvalue in a dereference chain. - */ - return this->var; - } - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - /** - * Object being dereferenced. - */ - ir_variable *var; -}; - - -class ir_dereference_array : public ir_dereference { -public: - ir_dereference_array(ir_rvalue *value, ir_rvalue *array_index); - - ir_dereference_array(ir_variable *var, ir_rvalue *array_index); - - virtual ir_dereference_array *clone(void *mem_ctx, - struct hash_table *) const; - - virtual ir_constant *constant_expression_value(); - - virtual ir_dereference_array *as_dereference_array() - { - return this; - } - - /** - * Get the variable that is ultimately referenced by an r-value - */ - virtual ir_variable *variable_referenced() - { - return this->array->variable_referenced(); - } - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - ir_rvalue *array; - ir_rvalue *array_index; - -private: - void set_array(ir_rvalue *value); -}; - - -class ir_dereference_record : public ir_dereference { -public: - ir_dereference_record(ir_rvalue *value, const char *field); - - ir_dereference_record(ir_variable *var, const char *field); - - virtual ir_dereference_record *clone(void *mem_ctx, - struct hash_table *) const; - - virtual ir_constant *constant_expression_value(); - - /** - * Get the variable that is ultimately referenced by an r-value - */ - virtual ir_variable *variable_referenced() - { - return this->record->variable_referenced(); - } - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - ir_rvalue *record; - const char *field; -}; - - -/** - * Data stored in an ir_constant - */ -union ir_constant_data { - unsigned u[16]; - int i[16]; - float f[16]; - bool b[16]; -}; - - -class ir_constant : public ir_rvalue { -public: - ir_constant(const struct glsl_type *type, const ir_constant_data *data); - ir_constant(bool b); - ir_constant(unsigned int u); - ir_constant(int i); - ir_constant(float f); - - /** - * Construct an ir_constant from a list of ir_constant values - */ - ir_constant(const struct glsl_type *type, exec_list *values); - - /** - * Construct an ir_constant from a scalar component of another ir_constant - * - * The new \c ir_constant inherits the type of the component from the - * source constant. - * - * \note - * In the case of a matrix constant, the new constant is a scalar, \b not - * a vector. - */ - ir_constant(const ir_constant *c, unsigned i); - - /** - * Return a new ir_constant of the specified type containing all zeros. - */ - static ir_constant *zero(void *mem_ctx, const glsl_type *type); - - virtual ir_constant *clone(void *mem_ctx, struct hash_table *) const; - - virtual ir_constant *constant_expression_value(); - - virtual ir_constant *as_constant() - { - return this; - } - - virtual void accept(ir_visitor *v) - { - v->visit(this); - } - - virtual ir_visitor_status accept(ir_hierarchical_visitor *); - - /** - * Get a particular component of a constant as a specific type - * - * This is useful, for example, to get a value from an integer constant - * as a float or bool. This appears frequently when constructors are - * called with all constant parameters. - */ - /*@{*/ - bool get_bool_component(unsigned i) const; - float get_float_component(unsigned i) const; - int get_int_component(unsigned i) const; - unsigned get_uint_component(unsigned i) const; - /*@}*/ - - ir_constant *get_array_element(unsigned i) const; - - ir_constant *get_record_field(const char *name); - - /** - * 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 - */ - bool has_value(const ir_constant *) const; - - virtual bool is_zero() const; - virtual bool is_one() const; - virtual bool is_negative_one() const; - - /** - * Value of the constant. - * - * The field used to back the values supplied by the constant is determined - * by the type associated with the \c ir_instruction. Constants may be - * scalars, vectors, or matrices. - */ - union ir_constant_data value; - - /* Array elements */ - ir_constant **array_elements; - - /* Structure fields */ - exec_list components; - -private: - /** - * Parameterless constructor only used by the clone method - */ - ir_constant(void); -}; - -/*@}*/ - -/** - * Apply a visitor to each IR node in a list - */ -void -visit_exec_list(exec_list *list, ir_visitor *visitor); - -/** - * Validate invariants on each IR node in a list - */ -void validate_ir_tree(exec_list *instructions); - -/** - * Make a clone of each IR instruction in a list - * - * \param in List of IR instructions that are to be cloned - * \param out List to hold the cloned instructions - */ -void -clone_ir_list(void *mem_ctx, exec_list *out, const exec_list *in); - -extern void -_mesa_glsl_initialize_variables(exec_list *instructions, - struct _mesa_glsl_parse_state *state); - -extern void -_mesa_glsl_initialize_functions(_mesa_glsl_parse_state *state); - -extern void -_mesa_glsl_release_functions(void); - -extern void -reparent_ir(exec_list *list, void *mem_ctx); - -struct glsl_symbol_table; - -extern void -import_prototypes(const exec_list *source, exec_list *dest, - struct glsl_symbol_table *symbols, void *mem_ctx); - -extern bool -ir_has_call(ir_instruction *ir); - -extern void -do_set_program_inouts(exec_list *instructions, struct gl_program *prog); - -#endif /* IR_H */ +/* -*- c++ -*- */
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+#ifndef IR_H
+#define IR_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ralloc.h"
+#include "glsl_types.h"
+#include "list.h"
+#include "ir_visitor.h"
+#include "ir_hierarchical_visitor.h"
+
+/**
+ * \defgroup IR Intermediate representation nodes
+ *
+ * @{
+ */
+
+/**
+ * Class tags
+ *
+ * Each concrete class derived from \c ir_instruction has a value in this
+ * enumerant. The value for the type is stored in \c ir_instruction::ir_type
+ * by the constructor. While using type tags is not very C++, it is extremely
+ * convenient. For example, during debugging you can simply inspect
+ * \c ir_instruction::ir_type to find out the actual type of the object.
+ *
+ * In addition, it is possible to use a switch-statement based on \c
+ * \c ir_instruction::ir_type to select different behavior for different object
+ * types. For functions that have only slight differences for several object
+ * 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_expression,
+ 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_max /**< maximum ir_type enum number, for validation */
+};
+
+/**
+ * Base class of all IR instructions
+ */
+class ir_instruction : public exec_node {
+public:
+ enum ir_node_type ir_type;
+ const struct glsl_type *type;
+
+ /** ir_print_visitor helper for debugging. */
+ void print(void) 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;
+
+ /**
+ * \name IR instruction downcast functions
+ *
+ * These functions either cast the object to a derived class or return
+ * \c NULL if the object's type does not match the specified derived class.
+ * 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_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; }
+ /*@}*/
+
+protected:
+ ir_instruction()
+ {
+ ir_type = ir_type_unset;
+ type = NULL;
+ }
+};
+
+
+class ir_rvalue : public ir_instruction {
+public:
+ virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const = 0;
+
+ virtual ir_constant *constant_expression_value() = 0;
+
+ virtual ir_rvalue * as_rvalue()
+ {
+ return this;
+ }
+
+ ir_rvalue *as_rvalue_to_saturate();
+
+ virtual bool is_lvalue()
+ {
+ return false;
+ }
+
+ /**
+ * Get the variable that is ultimately referenced by an r-value
+ */
+ virtual ir_variable *variable_referenced()
+ {
+ return NULL;
+ }
+
+
+ /**
+ * If an r-value is a reference to a whole variable, get that variable
+ *
+ * \return
+ * Pointer to a variable that is completely dereferenced by the r-value. If
+ * the r-value is not a dereference or the dereference does not access the
+ * entire variable (i.e., it's just one array element, struct field), \c NULL
+ * is returned.
+ */
+ virtual ir_variable *whole_variable_referenced()
+ {
+ return NULL;
+ }
+
+ /**
+ * Determine if an r-value has the value zero
+ *
+ * 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 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
+ */
+ virtual bool is_zero() const;
+
+ /**
+ * Determine if an r-value has the value one
+ *
+ * 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 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
+ */
+ virtual bool is_one() const;
+
+ /**
+ * Determine if an r-value has the value negative one
+ *
+ * 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 all elements set to the value
+ * negative one. For boolean times, the result is always \c false.
+ *
+ * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_one
+ */
+ virtual bool is_negative_one() const;
+
+protected:
+ ir_rvalue();
+};
+
+
+/**
+ * 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_in,
+ ir_var_out,
+ ir_var_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. */
+};
+
+enum ir_variable_interpolation {
+ ir_var_smooth = 0,
+ ir_var_flat,
+ ir_var_noperspective
+};
+
+/**
+ * \brief Layout qualifiers for gl_FragDepth.
+ *
+ * The AMD_conservative_depth extension allows gl_FragDepth to be redeclared
+ * with a layout qualifier.
+ */
+enum ir_depth_layout {
+ ir_depth_layout_none, /**< No depth layout is specified. */
+ ir_depth_layout_any,
+ ir_depth_layout_greater,
+ ir_depth_layout_less,
+ ir_depth_layout_unchanged
+};
+
+/**
+ * \brief Convert depth layout qualifier to string.
+ */
+const char*
+depth_layout_string(ir_depth_layout layout);
+
+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 should only be used on a shader input or output variable.
+ */
+ const char *interpolation_string() const;
+
+ /**
+ * Calculate the number of slots required to hold this variable
+ *
+ * This is used to determine how many uniform or varying locations a variable
+ * occupies. The count is in units of floating point components.
+ */
+ unsigned component_slots() const;
+
+ /**
+ * Delcared name of the variable
+ */
+ const char *name;
+
+ /**
+ * Highest element accessed with a constant expression array index
+ *
+ * Not used for non-array variables.
+ */
+ unsigned max_array_access;
+
+ /**
+ * 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;
+
+ /**
+ * 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.
+ */
+ unsigned used:1;
+
+ /**
+ * Storage class of the variable.
+ *
+ * \sa ir_variable_mode
+ */
+ unsigned mode:3;
+
+ /**
+ * Interpolation mode for shader inputs / outputs
+ *
+ * \sa ir_variable_interpolation
+ */
+ unsigned interpolation:2;
+
+ /**
+ * Flag that the whole array is assignable
+ *
+ * In GLSL 1.20 and later whole arrays are assignable (and comparable for
+ * equality). This flag enables this behavior.
+ */
+ unsigned array_lvalue:1;
+
+ /**
+ * \name ARB_fragment_coord_conventions
+ * @{
+ */
+ unsigned origin_upper_left:1;
+ unsigned pixel_center_integer: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;
+
+ /**
+ * 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;
+
+ /**
+ * 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_vert_result.
+ * - Fragment shader input: one of the values from \c gl_frag_attrib.
+ * - Fragment shader output: one of the values from \c gl_frag_result.
+ * - Uniforms: Per-stage 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;
+
+ /**
+ * 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_value;
+};
+
+
+/*@{*/
+/**
+ * The representation of a function instance; may be the full definition or
+ * simply a prototype.
+ */
+class ir_function_signature : public ir_instruction {
+ /* An ir_function_signature will be part of the list of signatures in
+ * an ir_function.
+ */
+public:
+ ir_function_signature(const glsl_type *return_type);
+
+ virtual ir_function_signature *clone(void *mem_ctx,
+ struct hash_table *ht) const;
+ ir_function_signature *clone_prototype(void *mem_ctx,
+ struct hash_table *ht) const;
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ /**
+ * Get the name of the function for which this is a signature
+ */
+ const char *function_name() const;
+
+ /**
+ * Get a handle to the function for which this is a signature
+ *
+ * There is no setter function, this function returns a \c const pointer,
+ * and \c ir_function_signature::_function is private for a reason. The
+ * only way to make a connection between a function and function signature
+ * is via \c ir_function::add_signature. This helps ensure that certain
+ * invariants (i.e., a function signature is in the list of signatures for
+ * its \c _function) are met.
+ *
+ * \sa ir_function::add_signature
+ */
+ inline const class ir_function *function() const
+ {
+ return this->_function;
+ }
+
+ /**
+ * Check whether the qualifiers match between this signature's parameters
+ * and the supplied parameter list. If not, returns the name of the first
+ * parameter with mismatched qualifiers (for use in error messages).
+ */
+ const char *qualifiers_match(exec_list *params);
+
+ /**
+ * Replace the current parameter list with the given one. This is useful
+ * if the current information came from a prototype, and either has invalid
+ * or missing parameter names.
+ */
+ void replace_parameters(exec_list *new_params);
+
+ /**
+ * Function return type.
+ *
+ * \note This discards the optional precision qualifier.
+ */
+ const struct glsl_type *return_type;
+
+ /**
+ * List of ir_variable of function parameters.
+ *
+ * This represents the storage. The paramaters passed in a particular
+ * call will be in ir_call::actual_paramaters.
+ */
+ struct exec_list parameters;
+
+ /** Whether or not this function has a body (which may be empty). */
+ unsigned is_defined:1;
+
+ /** Whether or not this function signature is a built-in. */
+ unsigned is_builtin:1;
+
+ /** Body of instructions in the function. */
+ struct exec_list body;
+
+private:
+ /** Function of which this signature is one overload. */
+ class ir_function *_function;
+
+ friend class ir_function;
+};
+
+
+/**
+ * Header for tracking multiple overloaded functions with the same name.
+ * Contains a list of ir_function_signatures representing each of the
+ * actual functions.
+ */
+class ir_function : public ir_instruction {
+public:
+ ir_function(const char *name);
+
+ virtual ir_function *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);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ void add_signature(ir_function_signature *sig)
+ {
+ sig->_function = 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.
+ */
+ ir_function_signature *matching_signature(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);
+
+ /**
+ * Name of the function.
+ */
+ const char *name;
+
+ /** Whether or not this function has a signature that isn't a built-in. */
+ bool has_user_signature();
+
+ /**
+ * List of ir_function_signature for each overloaded function with this name.
+ */
+ struct exec_list signatures;
+};
+
+inline const char *ir_function_signature::function_name() const
+{
+ return this->_function->name;
+}
+/*@}*/
+
+
+/**
+ * IR instruction representing high-level if-statements
+ */
+class ir_if : public ir_instruction {
+public:
+ ir_if(ir_rvalue *condition)
+ : 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 *);
+
+ ir_rvalue *condition;
+ /** List of ir_instruction for the body of the then branch */
+ exec_list then_instructions;
+ /** List of ir_instruction for the body of the else branch */
+ exec_list else_instructions;
+};
+
+
+/**
+ * IR instruction representing a high-level loop structure.
+ */
+class ir_loop : public ir_instruction {
+public:
+ ir_loop();
+
+ virtual ir_loop *clone(void *mem_ctx, struct hash_table *ht) const;
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ 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;
+ /*@}*/
+};
+
+
+class ir_assignment : public ir_instruction {
+public:
+ ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, ir_rvalue *condition);
+
+ /**
+ * Construct an assignment with an explicit write mask
+ *
+ * \note
+ * Since a write mask is supplied, the LHS must already be a bare
+ * \c ir_dereference. The cannot be any swizzles in the LHS.
+ */
+ ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, ir_rvalue *condition,
+ unsigned write_mask);
+
+ virtual ir_assignment *clone(void *mem_ctx, struct hash_table *ht) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ virtual ir_assignment * as_assignment()
+ {
+ return this;
+ }
+
+ /**
+ * Get a whole variable written by an assignment
+ *
+ * If the LHS of the assignment writes a whole variable, the variable is
+ * returned. Otherwise \c NULL is returned. Examples of whole-variable
+ * assignment are:
+ *
+ * - Assigning to a scalar
+ * - Assigning to all components of a vector
+ * - Whole array (or matrix) assignment
+ * - Whole structure assignment
+ */
+ ir_variable *whole_variable_written();
+
+ /**
+ * Set the LHS of an assignment
+ */
+ void set_lhs(ir_rvalue *lhs);
+
+ /**
+ * Left-hand side of the assignment.
+ *
+ * This should be treated as read only. If you need to set the LHS of an
+ * assignment, use \c ir_assignment::set_lhs.
+ */
+ ir_dereference *lhs;
+
+ /**
+ * Value being assigned
+ */
+ ir_rvalue *rhs;
+
+ /**
+ * Optional condition for the assignment.
+ */
+ ir_rvalue *condition;
+
+
+ /**
+ * Component mask written
+ *
+ * For non-vector types in the LHS, this field will be zero. For vector
+ * types, a bit will be set for each component that is written. Note that
+ * for \c vec2 and \c vec3 types only the lower bits will ever be set.
+ *
+ * A partially-set write mask means that each enabled channel gets
+ * the value from a consecutive channel of the rhs. For example,
+ * to write just .xyw of gl_FrontColor with color:
+ *
+ * (assign (constant bool (1)) (xyw)
+ * (var_ref gl_FragColor)
+ * (swiz xyw (var_ref color)))
+ */
+ unsigned write_mask:4;
+};
+
+/* Update ir_expression::num_operands() and operator_strs when
+ * updating this list.
+ */
+enum ir_expression_operation {
+ ir_unop_bit_not,
+ ir_unop_logic_not,
+ ir_unop_neg,
+ ir_unop_abs,
+ ir_unop_sign,
+ ir_unop_rcp,
+ ir_unop_rsq,
+ ir_unop_sqrt,
+ ir_unop_exp, /**< Log base e on gentype */
+ ir_unop_log, /**< Natural log on gentype */
+ ir_unop_exp2,
+ ir_unop_log2,
+ ir_unop_f2i, /**< Float-to-integer conversion. */
+ ir_unop_i2f, /**< Integer-to-float conversion. */
+ ir_unop_f2b, /**< Float-to-boolean conversion */
+ ir_unop_b2f, /**< Boolean-to-float conversion */
+ ir_unop_i2b, /**< int-to-boolean conversion */
+ ir_unop_b2i, /**< Boolean-to-int conversion */
+ ir_unop_u2f, /**< Unsigned-to-float conversion. */
+ ir_unop_any,
+
+ /**
+ * \name Unary floating-point rounding operations.
+ */
+ /*@{*/
+ ir_unop_trunc,
+ ir_unop_ceil,
+ ir_unop_floor,
+ ir_unop_fract,
+ ir_unop_round_even,
+ /*@}*/
+
+ /**
+ * \name Trigonometric operations.
+ */
+ /*@{*/
+ ir_unop_sin,
+ ir_unop_cos,
+ ir_unop_sin_reduced, /**< Reduced range sin. [-pi, pi] */
+ ir_unop_cos_reduced, /**< Reduced range cos. [-pi, pi] */
+ /*@}*/
+
+ /**
+ * \name Partial derivatives.
+ */
+ /*@{*/
+ ir_unop_dFdx,
+ ir_unop_dFdy,
+ /*@}*/
+
+ ir_unop_noise,
+
+ /**
+ * A sentinel marking the last of the unary operations.
+ */
+ ir_last_unop = ir_unop_noise,
+
+ ir_binop_add,
+ ir_binop_sub,
+ ir_binop_mul,
+ ir_binop_div,
+
+ /**
+ * Takes one of two combinations of arguments:
+ *
+ * - mod(vecN, vecN)
+ * - mod(vecN, float)
+ *
+ * Does not take integer types.
+ */
+ ir_binop_mod,
+
+ /**
+ * \name Binary comparison operators which return a boolean vector.
+ * The type of both operands must be equal.
+ */
+ /*@{*/
+ ir_binop_less,
+ ir_binop_greater,
+ ir_binop_lequal,
+ ir_binop_gequal,
+ ir_binop_equal,
+ ir_binop_nequal,
+ /**
+ * Returns single boolean for whether all components of operands[0]
+ * equal the components of operands[1].
+ */
+ ir_binop_all_equal,
+ /**
+ * Returns single boolean for whether any component of operands[0]
+ * is not equal to the corresponding component of operands[1].
+ */
+ ir_binop_any_nequal,
+ /*@}*/
+
+ /**
+ * \name Bit-wise binary operations.
+ */
+ /*@{*/
+ ir_binop_lshift,
+ ir_binop_rshift,
+ ir_binop_bit_and,
+ ir_binop_bit_xor,
+ ir_binop_bit_or,
+ /*@}*/
+
+ ir_binop_logic_and,
+ ir_binop_logic_xor,
+ ir_binop_logic_or,
+
+ ir_binop_dot,
+ ir_binop_min,
+ ir_binop_max,
+
+ ir_binop_pow,
+
+ /**
+ * A sentinel marking the last of the binary operations.
+ */
+ ir_last_binop = ir_binop_pow,
+
+ ir_quadop_vector,
+
+ /**
+ * A sentinel marking the last of all operations.
+ */
+ ir_last_opcode = ir_last_binop
+};
+
+class ir_expression : public ir_rvalue {
+public:
+ /**
+ * Constructor for unary operation expressions
+ */
+ ir_expression(int op, const struct glsl_type *type, ir_rvalue *);
+ ir_expression(int op, ir_rvalue *);
+
+ /**
+ * Constructor for binary operation expressions
+ */
+ ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *, ir_rvalue *);
+ ir_expression(int op, ir_rvalue *op0, ir_rvalue *op1);
+
+ /**
+ * Constructor for quad operator expressions
+ */
+ ir_expression(int op, const struct glsl_type *type,
+ ir_rvalue *, ir_rvalue *, ir_rvalue *, ir_rvalue *);
+
+ virtual ir_expression *as_expression()
+ {
+ return this;
+ }
+
+ virtual ir_expression *clone(void *mem_ctx, struct hash_table *ht) const;
+
+ /**
+ * Attempt to constant-fold the expression
+ *
+ * If the expression cannot be constant folded, this method will return
+ * \c NULL.
+ */
+ virtual ir_constant *constant_expression_value();
+
+ /**
+ * Determine the number of operands used by an expression
+ */
+ static unsigned int get_num_operands(ir_expression_operation);
+
+ /**
+ * Determine the number of operands used by an expression
+ */
+ unsigned int get_num_operands() const
+ {
+ return (this->operation == ir_quadop_vector)
+ ? this->type->vector_elements : get_num_operands(operation);
+ }
+
+ /**
+ * Return a string representing this expression's operator.
+ */
+ const char *operator_string();
+
+ /**
+ * Return a string representing this expression's operator.
+ */
+ static const char *operator_string(ir_expression_operation);
+
+
+ /**
+ * Do a reverse-lookup to translate the given string into an operator.
+ */
+ static ir_expression_operation get_operator(const char *);
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ ir_expression_operation operation;
+ ir_rvalue *operands[4];
+};
+
+
+/**
+ * IR instruction representing a function call
+ */
+class ir_call : public ir_rvalue {
+public:
+ ir_call(ir_function_signature *callee, exec_list *actual_parameters)
+ : callee(callee)
+ {
+ ir_type = ir_type_call;
+ assert(callee->return_type != NULL);
+ type = callee->return_type;
+ actual_parameters->move_nodes_to(& this->actual_parameters);
+ }
+
+ virtual ir_call *clone(void *mem_ctx, struct hash_table *ht) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ virtual ir_call *as_call()
+ {
+ return this;
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ /**
+ * Get a generic ir_call object when an error occurs
+ *
+ * Any allocation will be performed with 'ctx' as ralloc owner.
+ */
+ static ir_call *get_error_instruction(void *ctx);
+
+ /**
+ * 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.
+ */
+ const char *callee_name() const
+ {
+ return callee->function_name();
+ }
+
+ /**
+ * Get the function signature bound to this function call
+ */
+ ir_function_signature *get_callee()
+ {
+ return callee;
+ }
+
+ /**
+ * Set the function call target
+ */
+ void set_callee(ir_function_signature *sig);
+
+ /**
+ * Generates an inline version of the function before @ir,
+ * returning the return value of the function.
+ */
+ ir_rvalue *generate_inline(ir_instruction *ir);
+
+ /* List of ir_rvalue of paramaters passed in this call. */
+ exec_list actual_parameters;
+
+private:
+ ir_call()
+ : callee(NULL)
+ {
+ this->ir_type = ir_type_call;
+ }
+
+ ir_function_signature *callee;
+};
+
+
+/**
+ * \name Jump-like IR instructions.
+ *
+ * These include \c break, \c continue, \c return, and \c discard.
+ */
+/*@{*/
+class ir_jump : public ir_instruction {
+protected:
+ ir_jump()
+ {
+ ir_type = ir_type_unset;
+ }
+};
+
+class ir_return : public ir_jump {
+public:
+ ir_return()
+ : value(NULL)
+ {
+ this->ir_type = ir_type_return;
+ }
+
+ ir_return(ir_rvalue *value)
+ : 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;
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ ir_rvalue *value;
+};
+
+
+/**
+ * Jump instructions used inside loops
+ *
+ * These include \c break and \c continue. The \c break within a loop is
+ * different from the \c break within a switch-statement.
+ *
+ * \sa ir_switch_jump
+ */
+class ir_loop_jump : public ir_jump {
+public:
+ enum jump_mode {
+ jump_break,
+ jump_continue
+ };
+
+ ir_loop_jump(jump_mode mode)
+ {
+ this->ir_type = ir_type_loop_jump;
+ this->mode = mode;
+ this->loop = loop;
+ }
+
+ virtual ir_loop_jump *clone(void *mem_ctx, struct hash_table *) const;
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ bool is_break() const
+ {
+ return mode == jump_break;
+ }
+
+ bool is_continue() const
+ {
+ return mode == jump_continue;
+ }
+
+ /** Mode selector for the jump instruction. */
+ enum jump_mode mode;
+private:
+ /** Loop containing this break instruction. */
+ ir_loop *loop;
+};
+
+/**
+ * IR instruction representing discard statements.
+ */
+class ir_discard : public ir_jump {
+public:
+ ir_discard()
+ {
+ this->ir_type = ir_type_discard;
+ this->condition = NULL;
+ }
+
+ ir_discard(ir_rvalue *cond)
+ {
+ this->ir_type = ir_type_discard;
+ this->condition = cond;
+ }
+
+ virtual ir_discard *clone(void *mem_ctx, struct hash_table *ht) const;
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ virtual ir_discard *as_discard()
+ {
+ return this;
+ }
+
+ ir_rvalue *condition;
+};
+/*@}*/
+
+
+/**
+ * Texture sampling opcodes used in ir_texture
+ */
+enum ir_texture_opcode {
+ ir_tex, /**< Regular texture look-up */
+ ir_txb, /**< Texture look-up with LOD bias */
+ ir_txl, /**< Texture look-up with explicit LOD */
+ ir_txd, /**< Texture look-up with partial derivatvies */
+ ir_txf /**< Texel fetch with explicit LOD */
+};
+
+
+/**
+ * IR instruction to sample a texture
+ *
+ * The specific form of the IR instruction depends on the \c mode value
+ * selected from \c ir_texture_opcodes. In the printed IR, these will
+ * appear as:
+ *
+ * Texel offset (0 or an expression)
+ * | Projection divisor
+ * | | Shadow comparitor
+ * | | |
+ * v v v
+ * (tex <type> <sampler> <coordinate> 0 1 ( ))
+ * (txb <type> <sampler> <coordinate> 0 1 ( ) <bias>)
+ * (txl <type> <sampler> <coordinate> 0 1 ( ) <lod>)
+ * (txd <type> <sampler> <coordinate> 0 1 ( ) (dPdx dPdy))
+ * (txf <type> <sampler> <coordinate> 0 <lod>)
+ */
+class ir_texture : public ir_rvalue {
+public:
+ ir_texture(enum ir_texture_opcode op)
+ : op(op), projector(NULL), shadow_comparitor(NULL), offset(NULL)
+ {
+ this->ir_type = ir_type_texture;
+ }
+
+ virtual ir_texture *clone(void *mem_ctx, struct hash_table *) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ /**
+ * Return a string representing the ir_texture_opcode.
+ */
+ const char *opcode_string();
+
+ /** Set the sampler and type. */
+ void set_sampler(ir_dereference *sampler, const glsl_type *type);
+
+ /**
+ * Do a reverse-lookup to translate a string into an ir_texture_opcode.
+ */
+ static ir_texture_opcode get_opcode(const char *);
+
+ enum ir_texture_opcode op;
+
+ /** Sampler to use for the texture access. */
+ ir_dereference *sampler;
+
+ /** Texture coordinate to sample */
+ ir_rvalue *coordinate;
+
+ /**
+ * Value used for projective divide.
+ *
+ * If there is no projective divide (the common case), this will be
+ * \c NULL. Optimization passes should check for this to point to a constant
+ * of 1.0 and replace that with \c NULL.
+ */
+ ir_rvalue *projector;
+
+ /**
+ * Coordinate used for comparison on shadow look-ups.
+ *
+ * If there is no shadow comparison, this will be \c NULL. For the
+ * \c ir_txf opcode, this *must* be \c NULL.
+ */
+ ir_rvalue *shadow_comparitor;
+
+ /** Texel offset. */
+ ir_rvalue *offset;
+
+ union {
+ ir_rvalue *lod; /**< Floating point LOD */
+ ir_rvalue *bias; /**< Floating point LOD bias */
+ struct {
+ ir_rvalue *dPdx; /**< Partial derivative of coordinate wrt X */
+ ir_rvalue *dPdy; /**< Partial derivative of coordinate wrt Y */
+ } grad;
+ } lod_info;
+};
+
+
+struct ir_swizzle_mask {
+ unsigned x:2;
+ unsigned y:2;
+ unsigned z:2;
+ unsigned w:2;
+
+ /**
+ * Number of components in the swizzle.
+ */
+ unsigned num_components:3;
+
+ /**
+ * Does the swizzle contain duplicate components?
+ *
+ * L-value swizzles cannot contain duplicate components.
+ */
+ unsigned has_duplicates:1;
+};
+
+
+class ir_swizzle : public ir_rvalue {
+public:
+ ir_swizzle(ir_rvalue *, unsigned x, unsigned y, unsigned z, unsigned w,
+ unsigned count);
+
+ ir_swizzle(ir_rvalue *val, const unsigned *components, unsigned count);
+
+ ir_swizzle(ir_rvalue *val, ir_swizzle_mask mask);
+
+ virtual ir_swizzle *clone(void *mem_ctx, struct hash_table *) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ virtual ir_swizzle *as_swizzle()
+ {
+ return this;
+ }
+
+ /**
+ * Construct an ir_swizzle from the textual representation. Can fail.
+ */
+ static ir_swizzle *create(ir_rvalue *, const char *, unsigned vector_length);
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ bool is_lvalue()
+ {
+ return val->is_lvalue() && !mask.has_duplicates;
+ }
+
+ /**
+ * Get the variable that is ultimately referenced by an r-value
+ */
+ virtual ir_variable *variable_referenced();
+
+ ir_rvalue *val;
+ ir_swizzle_mask mask;
+
+private:
+ /**
+ * Initialize the mask component of a swizzle
+ *
+ * This is used by the \c ir_swizzle constructors.
+ */
+ void init_mask(const unsigned *components, unsigned count);
+};
+
+
+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();
+
+ /**
+ * Get the variable that is ultimately referenced by an r-value
+ */
+ virtual ir_variable *variable_referenced() = 0;
+};
+
+
+class ir_dereference_variable : public ir_dereference {
+public:
+ ir_dereference_variable(ir_variable *var);
+
+ virtual ir_dereference_variable *clone(void *mem_ctx,
+ struct hash_table *) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ virtual ir_dereference_variable *as_dereference_variable()
+ {
+ return this;
+ }
+
+ /**
+ * Get the variable that is ultimately referenced by an r-value
+ */
+ virtual ir_variable *variable_referenced()
+ {
+ return this->var;
+ }
+
+ virtual ir_variable *whole_variable_referenced()
+ {
+ /* ir_dereference_variable objects always dereference the entire
+ * variable. However, if this dereference is dereferenced by anything
+ * else, the complete deferefernce chain is not a whole-variable
+ * dereference. This method should only be called on the top most
+ * ir_rvalue in a dereference chain.
+ */
+ return this->var;
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ /**
+ * Object being dereferenced.
+ */
+ ir_variable *var;
+};
+
+
+class ir_dereference_array : public ir_dereference {
+public:
+ ir_dereference_array(ir_rvalue *value, ir_rvalue *array_index);
+
+ ir_dereference_array(ir_variable *var, ir_rvalue *array_index);
+
+ virtual ir_dereference_array *clone(void *mem_ctx,
+ struct hash_table *) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ virtual ir_dereference_array *as_dereference_array()
+ {
+ return this;
+ }
+
+ /**
+ * Get the variable that is ultimately referenced by an r-value
+ */
+ virtual ir_variable *variable_referenced()
+ {
+ return this->array->variable_referenced();
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ ir_rvalue *array;
+ ir_rvalue *array_index;
+
+private:
+ void set_array(ir_rvalue *value);
+};
+
+
+class ir_dereference_record : public ir_dereference {
+public:
+ ir_dereference_record(ir_rvalue *value, const char *field);
+
+ ir_dereference_record(ir_variable *var, const char *field);
+
+ virtual ir_dereference_record *clone(void *mem_ctx,
+ struct hash_table *) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ /**
+ * Get the variable that is ultimately referenced by an r-value
+ */
+ virtual ir_variable *variable_referenced()
+ {
+ return this->record->variable_referenced();
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ ir_rvalue *record;
+ const char *field;
+};
+
+
+/**
+ * Data stored in an ir_constant
+ */
+union ir_constant_data {
+ unsigned u[16];
+ int i[16];
+ float f[16];
+ bool b[16];
+};
+
+
+class ir_constant : public ir_rvalue {
+public:
+ ir_constant(const struct glsl_type *type, const ir_constant_data *data);
+ ir_constant(bool b);
+ ir_constant(unsigned int u);
+ ir_constant(int i);
+ ir_constant(float f);
+
+ /**
+ * Construct an ir_constant from a list of ir_constant values
+ */
+ ir_constant(const struct glsl_type *type, exec_list *values);
+
+ /**
+ * Construct an ir_constant from a scalar component of another ir_constant
+ *
+ * The new \c ir_constant inherits the type of the component from the
+ * source constant.
+ *
+ * \note
+ * In the case of a matrix constant, the new constant is a scalar, \b not
+ * a vector.
+ */
+ ir_constant(const ir_constant *c, unsigned i);
+
+ /**
+ * Return a new ir_constant of the specified type containing all zeros.
+ */
+ static ir_constant *zero(void *mem_ctx, const glsl_type *type);
+
+ virtual ir_constant *clone(void *mem_ctx, struct hash_table *) const;
+
+ virtual ir_constant *constant_expression_value();
+
+ virtual ir_constant *as_constant()
+ {
+ return this;
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+
+ /**
+ * Get a particular component of a constant as a specific type
+ *
+ * This is useful, for example, to get a value from an integer constant
+ * as a float or bool. This appears frequently when constructors are
+ * called with all constant parameters.
+ */
+ /*@{*/
+ bool get_bool_component(unsigned i) const;
+ float get_float_component(unsigned i) const;
+ int get_int_component(unsigned i) const;
+ unsigned get_uint_component(unsigned i) const;
+ /*@}*/
+
+ ir_constant *get_array_element(unsigned i) const;
+
+ ir_constant *get_record_field(const char *name);
+
+ /**
+ * 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
+ */
+ bool has_value(const ir_constant *) const;
+
+ virtual bool is_zero() const;
+ virtual bool is_one() const;
+ virtual bool is_negative_one() const;
+
+ /**
+ * Value of the constant.
+ *
+ * The field used to back the values supplied by the constant is determined
+ * by the type associated with the \c ir_instruction. Constants may be
+ * scalars, vectors, or matrices.
+ */
+ union ir_constant_data value;
+
+ /* Array elements */
+ ir_constant **array_elements;
+
+ /* Structure fields */
+ exec_list components;
+
+private:
+ /**
+ * Parameterless constructor only used by the clone method
+ */
+ ir_constant(void);
+};
+
+/*@}*/
+
+/**
+ * Apply a visitor to each IR node in a list
+ */
+void
+visit_exec_list(exec_list *list, ir_visitor *visitor);
+
+/**
+ * Validate invariants on each IR node in a list
+ */
+void validate_ir_tree(exec_list *instructions);
+
+/**
+ * Make a clone of each IR instruction in a list
+ *
+ * \param in List of IR instructions that are to be cloned
+ * \param out List to hold the cloned instructions
+ */
+void
+clone_ir_list(void *mem_ctx, exec_list *out, const exec_list *in);
+
+extern void
+_mesa_glsl_initialize_variables(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+extern void
+_mesa_glsl_initialize_functions(_mesa_glsl_parse_state *state);
+
+extern void
+_mesa_glsl_release_functions(void);
+
+extern void
+reparent_ir(exec_list *list, void *mem_ctx);
+
+struct glsl_symbol_table;
+
+extern void
+import_prototypes(const exec_list *source, exec_list *dest,
+ struct glsl_symbol_table *symbols, void *mem_ctx);
+
+extern bool
+ir_has_call(ir_instruction *ir);
+
+extern void
+do_set_program_inouts(exec_list *instructions, struct gl_program *prog);
+
+#endif /* IR_H */
diff --git a/mesalib/src/glsl/ir_print_visitor.cpp b/mesalib/src/glsl/ir_print_visitor.cpp index 82ccc722f..3c5c4fd20 100644 --- a/mesalib/src/glsl/ir_print_visitor.cpp +++ b/mesalib/src/glsl/ir_print_visitor.cpp @@ -1,471 +1,474 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "ir_print_visitor.h" -#include "glsl_types.h" -#include "glsl_parser_extras.h" - -static void print_type(const glsl_type *t); - -void -ir_instruction::print(void) const -{ - ir_instruction *deconsted = const_cast<ir_instruction *>(this); - - ir_print_visitor v; - deconsted->accept(&v); -} - -void -_mesa_print_ir(exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - if (state) { - for (unsigned i = 0; i < state->num_user_structures; i++) { - const glsl_type *const s = state->user_structures[i]; - - printf("(structure (%s) (%s@%p) (%u) (\n", - s->name, s->name, (void *) s, s->length); - - for (unsigned j = 0; j < s->length; j++) { - printf("\t(("); - print_type(s->fields.structure[j].type); - printf(")(%s))\n", s->fields.structure[j].name); - } - - printf(")\n"); - } - } - - printf("(\n"); - foreach_iter(exec_list_iterator, iter, *instructions) { - ir_instruction *ir = (ir_instruction *)iter.get(); - ir->print(); - if (ir->ir_type != ir_type_function) - printf("\n"); - } - printf("\n)"); -} - - -void ir_print_visitor::indent(void) -{ - for (int i = 0; i < indentation; i++) - printf(" "); -} - -static void -print_type(const glsl_type *t) -{ - if (t->base_type == GLSL_TYPE_ARRAY) { - printf("(array "); - print_type(t->fields.array); - printf(" %u)", t->length); - } else if ((t->base_type == GLSL_TYPE_STRUCT) - && (strncmp("gl_", t->name, 3) != 0)) { - printf("%s@%p", t->name, (void *) t); - } else { - printf("%s", t->name); - } -} - - -void ir_print_visitor::visit(ir_variable *ir) -{ - printf("(declare "); - - const char *const cent = (ir->centroid) ? "centroid " : ""; - const char *const inv = (ir->invariant) ? "invariant " : ""; - const char *const mode[] = { "", "uniform ", "in ", "out ", "inout ", - "const_in ", "sys ", "temporary " }; - const char *const interp[] = { "", "flat", "noperspective" }; - - printf("(%s%s%s%s) ", - cent, inv, mode[ir->mode], interp[ir->interpolation]); - - print_type(ir->type); - printf(" %s@%p)", ir->name, (void *) ir); -} - - -void ir_print_visitor::visit(ir_function_signature *ir) -{ - printf("(signature "); - indentation++; - - print_type(ir->return_type); - printf("\n"); - indent(); - - printf("(parameters\n"); - indentation++; - - foreach_iter(exec_list_iterator, iter, ir->parameters) { - ir_variable *const inst = (ir_variable *) iter.get(); - - indent(); - inst->accept(this); - printf("\n"); - } - indentation--; - - indent(); - printf(")\n"); - - indent(); - - printf("(\n"); - indentation++; - - foreach_iter(exec_list_iterator, iter, ir->body) { - ir_instruction *const inst = (ir_instruction *) iter.get(); - - indent(); - inst->accept(this); - printf("\n"); - } - indentation--; - indent(); - printf("))\n"); - indentation--; -} - - -void ir_print_visitor::visit(ir_function *ir) -{ - printf("(function %s\n", ir->name); - indentation++; - foreach_iter(exec_list_iterator, iter, *ir) { - ir_function_signature *const sig = (ir_function_signature *) iter.get(); - indent(); - sig->accept(this); - printf("\n"); - } - indentation--; - indent(); - printf(")\n\n"); -} - - -void ir_print_visitor::visit(ir_expression *ir) -{ - printf("(expression "); - - print_type(ir->type); - - printf(" %s ", ir->operator_string()); - - for (unsigned i = 0; i < ir->get_num_operands(); i++) { - ir->operands[i]->accept(this); - } - - printf(") "); -} - - -void ir_print_visitor::visit(ir_texture *ir) -{ - printf("(%s ", ir->opcode_string()); - - ir->sampler->accept(this); - printf(" "); - - ir->coordinate->accept(this); - - printf(" "); - - if (ir->offset != NULL) { - ir->offset->accept(this); - } else { - printf("0"); - } - - printf(" "); - - if (ir->op != ir_txf) { - if (ir->projector) - ir->projector->accept(this); - else - printf("1"); - - if (ir->shadow_comparitor) { - printf(" "); - ir->shadow_comparitor->accept(this); - } else { - printf(" ()"); - } - } - - printf(" "); - switch (ir->op) - { - case ir_tex: - break; - case ir_txb: - ir->lod_info.bias->accept(this); - break; - case ir_txl: - case ir_txf: - ir->lod_info.lod->accept(this); - break; - case ir_txd: - printf("("); - ir->lod_info.grad.dPdx->accept(this); - printf(" "); - ir->lod_info.grad.dPdy->accept(this); - printf(")"); - break; - }; - printf(")"); -} - - -void ir_print_visitor::visit(ir_swizzle *ir) -{ - const unsigned swiz[4] = { - ir->mask.x, - ir->mask.y, - ir->mask.z, - ir->mask.w, - }; - - printf("(swiz "); - for (unsigned i = 0; i < ir->mask.num_components; i++) { - printf("%c", "xyzw"[swiz[i]]); - } - printf(" "); - ir->val->accept(this); - printf(")"); -} - - -void ir_print_visitor::visit(ir_dereference_variable *ir) -{ - ir_variable *var = ir->variable_referenced(); - printf("(var_ref %s@%p) ", var->name, (void *) var); -} - - -void ir_print_visitor::visit(ir_dereference_array *ir) -{ - printf("(array_ref "); - ir->array->accept(this); - ir->array_index->accept(this); - printf(") "); -} - - -void ir_print_visitor::visit(ir_dereference_record *ir) -{ - printf("(record_ref "); - ir->record->accept(this); - printf(" %s) ", ir->field); -} - - -void ir_print_visitor::visit(ir_assignment *ir) -{ - printf("(assign "); - - if (ir->condition) - ir->condition->accept(this); - - char mask[5]; - unsigned j = 0; - - for (unsigned i = 0; i < 4; i++) { - if ((ir->write_mask & (1 << i)) != 0) { - mask[j] = "xyzw"[i]; - j++; - } - } - mask[j] = '\0'; - - printf(" (%s) ", mask); - - ir->lhs->accept(this); - - printf(" "); - - ir->rhs->accept(this); - printf(") "); -} - - -void ir_print_visitor::visit(ir_constant *ir) -{ - const glsl_type *const base_type = ir->type->get_base_type(); - - printf("(constant "); - print_type(ir->type); - printf(" ("); - - if (ir->type->is_array()) { - for (unsigned i = 0; i < ir->type->length; i++) - ir->get_array_element(i)->accept(this); - } else if (ir->type->is_record()) { - ir_constant *value = (ir_constant *) ir->components.get_head(); - for (unsigned i = 0; i < ir->type->length; i++) { - printf("(%s ", ir->type->fields.structure->name); - value->accept(this); - printf(")"); - - value = (ir_constant *) value->next; - } - } else { - for (unsigned i = 0; i < ir->type->components(); i++) { - if (i != 0) - printf(" "); - switch (base_type->base_type) { - case GLSL_TYPE_UINT: printf("%u", ir->value.u[i]); break; - case GLSL_TYPE_INT: printf("%d", ir->value.i[i]); break; - case GLSL_TYPE_FLOAT: printf("%f", ir->value.f[i]); break; - case GLSL_TYPE_BOOL: printf("%d", ir->value.b[i]); break; - default: assert(0); - } - } - } - printf(")) "); -} - - -void -ir_print_visitor::visit(ir_call *ir) -{ - printf("(call %s (", ir->callee_name()); - foreach_iter(exec_list_iterator, iter, *ir) { - ir_instruction *const inst = (ir_instruction *) iter.get(); - - inst->accept(this); - } - printf("))\n"); -} - - -void -ir_print_visitor::visit(ir_return *ir) -{ - printf("(return"); - - ir_rvalue *const value = ir->get_value(); - if (value) { - printf(" "); - value->accept(this); - } - - printf(")"); -} - - -void -ir_print_visitor::visit(ir_discard *ir) -{ - printf("(discard "); - - if (ir->condition != NULL) { - printf(" "); - ir->condition->accept(this); - } - - printf(")"); -} - - -void -ir_print_visitor::visit(ir_if *ir) -{ - printf("(if "); - ir->condition->accept(this); - - printf("(\n"); - indentation++; - - foreach_iter(exec_list_iterator, iter, ir->then_instructions) { - ir_instruction *const inst = (ir_instruction *) iter.get(); - - indent(); - inst->accept(this); - printf("\n"); - } - - indentation--; - indent(); - printf(")\n"); - - indent(); - if (!ir->else_instructions.is_empty()) { - printf("(\n"); - indentation++; - - foreach_iter(exec_list_iterator, iter, ir->else_instructions) { - ir_instruction *const inst = (ir_instruction *) iter.get(); - - indent(); - inst->accept(this); - printf("\n"); - } - indentation--; - indent(); - printf("))\n"); - } else { - printf("())\n"); - } -} - - -void -ir_print_visitor::visit(ir_loop *ir) -{ - printf("(loop ("); - if (ir->counter != NULL) - ir->counter->accept(this); - printf(") ("); - if (ir->from != NULL) - ir->from->accept(this); - printf(") ("); - if (ir->to != NULL) - ir->to->accept(this); - printf(") ("); - if (ir->increment != NULL) - ir->increment->accept(this); - printf(") (\n"); - indentation++; - - foreach_iter(exec_list_iterator, iter, ir->body_instructions) { - ir_instruction *const inst = (ir_instruction *) iter.get(); - - indent(); - inst->accept(this); - printf("\n"); - } - indentation--; - indent(); - printf("))\n"); -} - - -void -ir_print_visitor::visit(ir_loop_jump *ir) -{ - printf("%s", ir->is_break() ? "break" : "continue"); -} +/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ir_print_visitor.h"
+#include "glsl_types.h"
+#include "glsl_parser_extras.h"
+
+static void print_type(const glsl_type *t);
+
+void
+ir_instruction::print(void) const
+{
+ ir_instruction *deconsted = const_cast<ir_instruction *>(this);
+
+ ir_print_visitor v;
+ deconsted->accept(&v);
+}
+
+void
+_mesa_print_ir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (state) {
+ for (unsigned i = 0; i < state->num_user_structures; i++) {
+ const glsl_type *const s = state->user_structures[i];
+
+ printf("(structure (%s) (%s@%p) (%u) (\n",
+ s->name, s->name, (void *) s, s->length);
+
+ for (unsigned j = 0; j < s->length; j++) {
+ printf("\t((");
+ print_type(s->fields.structure[j].type);
+ printf(")(%s))\n", s->fields.structure[j].name);
+ }
+
+ printf(")\n");
+ }
+ }
+
+ printf("(\n");
+ foreach_iter(exec_list_iterator, iter, *instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir->print();
+ if (ir->ir_type != ir_type_function)
+ printf("\n");
+ }
+ printf("\n)");
+}
+
+
+void ir_print_visitor::indent(void)
+{
+ for (int i = 0; i < indentation; i++)
+ printf(" ");
+}
+
+static void
+print_type(const glsl_type *t)
+{
+ if (t->base_type == GLSL_TYPE_ARRAY) {
+ printf("(array ");
+ print_type(t->fields.array);
+ printf(" %u)", t->length);
+ } else if ((t->base_type == GLSL_TYPE_STRUCT)
+ && (strncmp("gl_", t->name, 3) != 0)) {
+ printf("%s@%p", t->name, (void *) t);
+ } else {
+ printf("%s", t->name);
+ }
+}
+
+
+void ir_print_visitor::visit(ir_variable *ir)
+{
+ printf("(declare ");
+
+ const char *const cent = (ir->centroid) ? "centroid " : "";
+ const char *const inv = (ir->invariant) ? "invariant " : "";
+ const char *const mode[] = { "", "uniform ", "in ", "out ", "inout ",
+ "const_in ", "sys ", "temporary " };
+ const char *const interp[] = { "", "flat", "noperspective" };
+
+ printf("(%s%s%s%s) ",
+ cent, inv, mode[ir->mode], interp[ir->interpolation]);
+
+ print_type(ir->type);
+ printf(" %s@%p)", ir->name, (void *) ir);
+}
+
+
+void ir_print_visitor::visit(ir_function_signature *ir)
+{
+ printf("(signature ");
+ indentation++;
+
+ print_type(ir->return_type);
+ printf("\n");
+ indent();
+
+ printf("(parameters\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->parameters) {
+ ir_variable *const inst = (ir_variable *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+
+ indent();
+ printf(")\n");
+
+ indent();
+
+ printf("(\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->body) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf("))\n");
+ indentation--;
+}
+
+
+void ir_print_visitor::visit(ir_function *ir)
+{
+ printf("(function %s\n", ir->name);
+ indentation++;
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_function_signature *const sig = (ir_function_signature *) iter.get();
+ indent();
+ sig->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf(")\n\n");
+}
+
+
+void ir_print_visitor::visit(ir_expression *ir)
+{
+ printf("(expression ");
+
+ print_type(ir->type);
+
+ printf(" %s ", ir->operator_string());
+
+ for (unsigned i = 0; i < ir->get_num_operands(); i++) {
+ ir->operands[i]->accept(this);
+ }
+
+ printf(") ");
+}
+
+
+void ir_print_visitor::visit(ir_texture *ir)
+{
+ printf("(%s ", ir->opcode_string());
+
+ print_type(ir->type);
+ printf(" ");
+
+ ir->sampler->accept(this);
+ printf(" ");
+
+ ir->coordinate->accept(this);
+
+ printf(" ");
+
+ if (ir->offset != NULL) {
+ ir->offset->accept(this);
+ } else {
+ printf("0");
+ }
+
+ printf(" ");
+
+ if (ir->op != ir_txf) {
+ if (ir->projector)
+ ir->projector->accept(this);
+ else
+ printf("1");
+
+ if (ir->shadow_comparitor) {
+ printf(" ");
+ ir->shadow_comparitor->accept(this);
+ } else {
+ printf(" ()");
+ }
+ }
+
+ printf(" ");
+ switch (ir->op)
+ {
+ case ir_tex:
+ break;
+ case ir_txb:
+ ir->lod_info.bias->accept(this);
+ break;
+ case ir_txl:
+ case ir_txf:
+ ir->lod_info.lod->accept(this);
+ break;
+ case ir_txd:
+ printf("(");
+ ir->lod_info.grad.dPdx->accept(this);
+ printf(" ");
+ ir->lod_info.grad.dPdy->accept(this);
+ printf(")");
+ break;
+ };
+ printf(")");
+}
+
+
+void ir_print_visitor::visit(ir_swizzle *ir)
+{
+ const unsigned swiz[4] = {
+ ir->mask.x,
+ ir->mask.y,
+ ir->mask.z,
+ ir->mask.w,
+ };
+
+ printf("(swiz ");
+ for (unsigned i = 0; i < ir->mask.num_components; i++) {
+ printf("%c", "xyzw"[swiz[i]]);
+ }
+ printf(" ");
+ ir->val->accept(this);
+ printf(")");
+}
+
+
+void ir_print_visitor::visit(ir_dereference_variable *ir)
+{
+ ir_variable *var = ir->variable_referenced();
+ printf("(var_ref %s@%p) ", var->name, (void *) var);
+}
+
+
+void ir_print_visitor::visit(ir_dereference_array *ir)
+{
+ printf("(array_ref ");
+ ir->array->accept(this);
+ ir->array_index->accept(this);
+ printf(") ");
+}
+
+
+void ir_print_visitor::visit(ir_dereference_record *ir)
+{
+ printf("(record_ref ");
+ ir->record->accept(this);
+ printf(" %s) ", ir->field);
+}
+
+
+void ir_print_visitor::visit(ir_assignment *ir)
+{
+ printf("(assign ");
+
+ if (ir->condition)
+ ir->condition->accept(this);
+
+ char mask[5];
+ unsigned j = 0;
+
+ for (unsigned i = 0; i < 4; i++) {
+ if ((ir->write_mask & (1 << i)) != 0) {
+ mask[j] = "xyzw"[i];
+ j++;
+ }
+ }
+ mask[j] = '\0';
+
+ printf(" (%s) ", mask);
+
+ ir->lhs->accept(this);
+
+ printf(" ");
+
+ ir->rhs->accept(this);
+ printf(") ");
+}
+
+
+void ir_print_visitor::visit(ir_constant *ir)
+{
+ const glsl_type *const base_type = ir->type->get_base_type();
+
+ printf("(constant ");
+ print_type(ir->type);
+ printf(" (");
+
+ if (ir->type->is_array()) {
+ for (unsigned i = 0; i < ir->type->length; i++)
+ ir->get_array_element(i)->accept(this);
+ } else if (ir->type->is_record()) {
+ ir_constant *value = (ir_constant *) ir->components.get_head();
+ for (unsigned i = 0; i < ir->type->length; i++) {
+ printf("(%s ", ir->type->fields.structure->name);
+ value->accept(this);
+ printf(")");
+
+ value = (ir_constant *) value->next;
+ }
+ } else {
+ for (unsigned i = 0; i < ir->type->components(); i++) {
+ if (i != 0)
+ printf(" ");
+ switch (base_type->base_type) {
+ case GLSL_TYPE_UINT: printf("%u", ir->value.u[i]); break;
+ case GLSL_TYPE_INT: printf("%d", ir->value.i[i]); break;
+ case GLSL_TYPE_FLOAT: printf("%f", ir->value.f[i]); break;
+ case GLSL_TYPE_BOOL: printf("%d", ir->value.b[i]); break;
+ default: assert(0);
+ }
+ }
+ }
+ printf(")) ");
+}
+
+
+void
+ir_print_visitor::visit(ir_call *ir)
+{
+ printf("(call %s (", ir->callee_name());
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ inst->accept(this);
+ }
+ printf("))\n");
+}
+
+
+void
+ir_print_visitor::visit(ir_return *ir)
+{
+ printf("(return");
+
+ ir_rvalue *const value = ir->get_value();
+ if (value) {
+ printf(" ");
+ value->accept(this);
+ }
+
+ printf(")");
+}
+
+
+void
+ir_print_visitor::visit(ir_discard *ir)
+{
+ printf("(discard ");
+
+ if (ir->condition != NULL) {
+ printf(" ");
+ ir->condition->accept(this);
+ }
+
+ printf(")");
+}
+
+
+void
+ir_print_visitor::visit(ir_if *ir)
+{
+ printf("(if ");
+ ir->condition->accept(this);
+
+ printf("(\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->then_instructions) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+
+ indentation--;
+ indent();
+ printf(")\n");
+
+ indent();
+ if (!ir->else_instructions.is_empty()) {
+ printf("(\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->else_instructions) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf("))\n");
+ } else {
+ printf("())\n");
+ }
+}
+
+
+void
+ir_print_visitor::visit(ir_loop *ir)
+{
+ printf("(loop (");
+ if (ir->counter != NULL)
+ ir->counter->accept(this);
+ printf(") (");
+ if (ir->from != NULL)
+ ir->from->accept(this);
+ printf(") (");
+ if (ir->to != NULL)
+ ir->to->accept(this);
+ printf(") (");
+ if (ir->increment != NULL)
+ ir->increment->accept(this);
+ printf(") (\n");
+ indentation++;
+
+ foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
+ ir_instruction *const inst = (ir_instruction *) iter.get();
+
+ indent();
+ inst->accept(this);
+ printf("\n");
+ }
+ indentation--;
+ indent();
+ printf("))\n");
+}
+
+
+void
+ir_print_visitor::visit(ir_loop_jump *ir)
+{
+ printf("%s", ir->is_break() ? "break" : "continue");
+}
diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp index af85e06ae..201e436be 100644 --- a/mesalib/src/glsl/ir_reader.cpp +++ b/mesalib/src/glsl/ir_reader.cpp @@ -1,996 +1,1005 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "ir_reader.h" -#include "glsl_parser_extras.h" -#include "glsl_types.h" -#include "s_expression.h" - -const static bool debug = false; - -class ir_reader { -public: - ir_reader(_mesa_glsl_parse_state *); - - void read(exec_list *instructions, const char *src, bool scan_for_protos); - -private: - void *mem_ctx; - _mesa_glsl_parse_state *state; - - void ir_read_error(s_expression *, const char *fmt, ...); - - const glsl_type *read_type(s_expression *); - - void scan_for_prototypes(exec_list *, s_expression *); - ir_function *read_function(s_expression *, bool skip_body); - void read_function_sig(ir_function *, s_expression *, bool skip_body); - - void read_instructions(exec_list *, s_expression *, ir_loop *); - ir_instruction *read_instruction(s_expression *, ir_loop *); - ir_variable *read_declaration(s_expression *); - ir_if *read_if(s_expression *, ir_loop *); - ir_loop *read_loop(s_expression *); - ir_return *read_return(s_expression *); - ir_rvalue *read_rvalue(s_expression *); - ir_assignment *read_assignment(s_expression *); - ir_expression *read_expression(s_expression *); - ir_call *read_call(s_expression *); - ir_swizzle *read_swizzle(s_expression *); - ir_constant *read_constant(s_expression *); - ir_texture *read_texture(s_expression *); - - ir_dereference *read_dereference(s_expression *); -}; - -ir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state) -{ - this->mem_ctx = state; -} - -void -_mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions, - const char *src, bool scan_for_protos) -{ - ir_reader r(state); - r.read(instructions, src, scan_for_protos); -} - -void -ir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos) -{ - s_expression *expr = s_expression::read_expression(mem_ctx, src); - if (expr == NULL) { - ir_read_error(NULL, "couldn't parse S-Expression."); - return; - } - - if (scan_for_protos) { - scan_for_prototypes(instructions, expr); - if (state->error) - return; - } - - read_instructions(instructions, expr, NULL); - ralloc_free(expr); - - if (debug) - validate_ir_tree(instructions); -} - -void -ir_reader::ir_read_error(s_expression *expr, const char *fmt, ...) -{ - va_list ap; - - state->error = true; - - if (state->current_function != NULL) - ralloc_asprintf_append(&state->info_log, "In function %s:\n", - state->current_function->function_name()); - ralloc_strcat(&state->info_log, "error: "); - - va_start(ap, fmt); - ralloc_vasprintf_append(&state->info_log, fmt, ap); - va_end(ap); - ralloc_strcat(&state->info_log, "\n"); - - if (expr != NULL) { - ralloc_strcat(&state->info_log, "...in this context:\n "); - expr->print(); - ralloc_strcat(&state->info_log, "\n\n"); - } -} - -const glsl_type * -ir_reader::read_type(s_expression *expr) -{ - s_expression *s_base_type; - s_int *s_size; - - s_pattern pat[] = { "array", s_base_type, s_size }; - if (MATCH(expr, pat)) { - const glsl_type *base_type = read_type(s_base_type); - if (base_type == NULL) { - ir_read_error(NULL, "when reading base type of array type"); - return NULL; - } - - return glsl_type::get_array_instance(base_type, s_size->value()); - } - - s_symbol *type_sym = SX_AS_SYMBOL(expr); - if (type_sym == NULL) { - ir_read_error(expr, "expected <type>"); - return NULL; - } - - const glsl_type *type = state->symbols->get_type(type_sym->value()); - if (type == NULL) - ir_read_error(expr, "invalid type: %s", type_sym->value()); - - return type; -} - - -void -ir_reader::scan_for_prototypes(exec_list *instructions, s_expression *expr) -{ - s_list *list = SX_AS_LIST(expr); - if (list == NULL) { - ir_read_error(expr, "Expected (<instruction> ...); found an atom."); - return; - } - - foreach_iter(exec_list_iterator, it, list->subexpressions) { - s_list *sub = SX_AS_LIST(it.get()); - if (sub == NULL) - continue; // not a (function ...); ignore it. - - s_symbol *tag = SX_AS_SYMBOL(sub->subexpressions.get_head()); - if (tag == NULL || strcmp(tag->value(), "function") != 0) - continue; // not a (function ...); ignore it. - - ir_function *f = read_function(sub, true); - if (f == NULL) - return; - instructions->push_tail(f); - } -} - -ir_function * -ir_reader::read_function(s_expression *expr, bool skip_body) -{ - bool added = false; - s_symbol *name; - - s_pattern pat[] = { "function", name }; - if (!PARTIAL_MATCH(expr, pat)) { - ir_read_error(expr, "Expected (function <name> (signature ...) ...)"); - return NULL; - } - - ir_function *f = state->symbols->get_function(name->value()); - if (f == NULL) { - f = new(mem_ctx) ir_function(name->value()); - added = state->symbols->add_function(f); - assert(added); - } - - exec_list_iterator it = ((s_list *) expr)->subexpressions.iterator(); - it.next(); // skip "function" tag - it.next(); // skip function name - for (/* nothing */; it.has_next(); it.next()) { - s_expression *s_sig = (s_expression *) it.get(); - read_function_sig(f, s_sig, skip_body); - } - return added ? f : NULL; -} - -void -ir_reader::read_function_sig(ir_function *f, s_expression *expr, bool skip_body) -{ - s_expression *type_expr; - s_list *paramlist; - s_list *body_list; - - s_pattern pat[] = { "signature", type_expr, paramlist, body_list }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "Expected (signature <type> (parameters ...) " - "(<instruction> ...))"); - return; - } - - const glsl_type *return_type = read_type(type_expr); - if (return_type == NULL) - return; - - s_symbol *paramtag = SX_AS_SYMBOL(paramlist->subexpressions.get_head()); - if (paramtag == NULL || strcmp(paramtag->value(), "parameters") != 0) { - ir_read_error(paramlist, "Expected (parameters ...)"); - return; - } - - // Read the parameters list into a temporary place. - exec_list hir_parameters; - state->symbols->push_scope(); - - exec_list_iterator it = paramlist->subexpressions.iterator(); - for (it.next() /* skip "parameters" */; it.has_next(); it.next()) { - ir_variable *var = read_declaration((s_expression *) it.get()); - if (var == NULL) - return; - - hir_parameters.push_tail(var); - } - - ir_function_signature *sig = f->exact_matching_signature(&hir_parameters); - if (sig == NULL && skip_body) { - /* If scanning for prototypes, generate a new signature. */ - sig = new(mem_ctx) ir_function_signature(return_type); - sig->is_builtin = true; - f->add_signature(sig); - } else if (sig != NULL) { - const char *badvar = sig->qualifiers_match(&hir_parameters); - if (badvar != NULL) { - ir_read_error(expr, "function `%s' parameter `%s' qualifiers " - "don't match prototype", f->name, badvar); - return; - } - - if (sig->return_type != return_type) { - ir_read_error(expr, "function `%s' return type doesn't " - "match prototype", f->name); - return; - } - } else { - /* No prototype for this body exists - skip it. */ - state->symbols->pop_scope(); - return; - } - assert(sig != NULL); - - sig->replace_parameters(&hir_parameters); - - if (!skip_body && !body_list->subexpressions.is_empty()) { - if (sig->is_defined) { - ir_read_error(expr, "function %s redefined", f->name); - return; - } - state->current_function = sig; - read_instructions(&sig->body, body_list, NULL); - state->current_function = NULL; - sig->is_defined = true; - } - - state->symbols->pop_scope(); -} - -void -ir_reader::read_instructions(exec_list *instructions, s_expression *expr, - ir_loop *loop_ctx) -{ - // Read in a list of instructions - s_list *list = SX_AS_LIST(expr); - if (list == NULL) { - ir_read_error(expr, "Expected (<instruction> ...); found an atom."); - return; - } - - foreach_iter(exec_list_iterator, it, list->subexpressions) { - s_expression *sub = (s_expression*) it.get(); - ir_instruction *ir = read_instruction(sub, loop_ctx); - if (ir != NULL) { - /* Global variable declarations should be moved to the top, before - * any functions that might use them. Functions are added to the - * instruction stream when scanning for prototypes, so without this - * hack, they always appear before variable declarations. - */ - if (state->current_function == NULL && ir->as_variable() != NULL) - instructions->push_head(ir); - else - instructions->push_tail(ir); - } - } -} - - -ir_instruction * -ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx) -{ - s_symbol *symbol = SX_AS_SYMBOL(expr); - if (symbol != NULL) { - if (strcmp(symbol->value(), "break") == 0 && loop_ctx != NULL) - return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break); - if (strcmp(symbol->value(), "continue") == 0 && loop_ctx != NULL) - return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue); - } - - s_list *list = SX_AS_LIST(expr); - if (list == NULL || list->subexpressions.is_empty()) { - ir_read_error(expr, "Invalid instruction.\n"); - return NULL; - } - - s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head()); - if (tag == NULL) { - ir_read_error(expr, "expected instruction tag"); - return NULL; - } - - ir_instruction *inst = NULL; - if (strcmp(tag->value(), "declare") == 0) { - inst = read_declaration(list); - } else if (strcmp(tag->value(), "assign") == 0) { - inst = read_assignment(list); - } else if (strcmp(tag->value(), "if") == 0) { - inst = read_if(list, loop_ctx); - } else if (strcmp(tag->value(), "loop") == 0) { - inst = read_loop(list); - } else if (strcmp(tag->value(), "return") == 0) { - inst = read_return(list); - } else if (strcmp(tag->value(), "function") == 0) { - inst = read_function(list, false); - } else { - inst = read_rvalue(list); - if (inst == NULL) - ir_read_error(NULL, "when reading instruction"); - } - return inst; -} - -ir_variable * -ir_reader::read_declaration(s_expression *expr) -{ - s_list *s_quals; - s_expression *s_type; - s_symbol *s_name; - - s_pattern pat[] = { "declare", s_quals, s_type, s_name }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (declare (<qualifiers>) <type> <name>)"); - return NULL; - } - - const glsl_type *type = read_type(s_type); - if (type == NULL) - return NULL; - - ir_variable *var = new(mem_ctx) ir_variable(type, s_name->value(), - ir_var_auto); - - foreach_iter(exec_list_iterator, it, s_quals->subexpressions) { - s_symbol *qualifier = SX_AS_SYMBOL(it.get()); - if (qualifier == NULL) { - ir_read_error(expr, "qualifier list must contain only symbols"); - return NULL; - } - - // FINISHME: Check for duplicate/conflicting qualifiers. - if (strcmp(qualifier->value(), "centroid") == 0) { - var->centroid = 1; - } else if (strcmp(qualifier->value(), "invariant") == 0) { - var->invariant = 1; - } else if (strcmp(qualifier->value(), "uniform") == 0) { - var->mode = ir_var_uniform; - } else if (strcmp(qualifier->value(), "auto") == 0) { - var->mode = ir_var_auto; - } else if (strcmp(qualifier->value(), "in") == 0) { - var->mode = ir_var_in; - } else if (strcmp(qualifier->value(), "const_in") == 0) { - var->mode = ir_var_const_in; - } else if (strcmp(qualifier->value(), "out") == 0) { - var->mode = ir_var_out; - } else if (strcmp(qualifier->value(), "inout") == 0) { - var->mode = ir_var_inout; - } else if (strcmp(qualifier->value(), "smooth") == 0) { - var->interpolation = ir_var_smooth; - } else if (strcmp(qualifier->value(), "flat") == 0) { - var->interpolation = ir_var_flat; - } else if (strcmp(qualifier->value(), "noperspective") == 0) { - var->interpolation = ir_var_noperspective; - } else { - ir_read_error(expr, "unknown qualifier: %s", qualifier->value()); - return NULL; - } - } - - // Add the variable to the symbol table - state->symbols->add_variable(var); - - return var; -} - - -ir_if * -ir_reader::read_if(s_expression *expr, ir_loop *loop_ctx) -{ - s_expression *s_cond; - s_expression *s_then; - s_expression *s_else; - - s_pattern pat[] = { "if", s_cond, s_then, s_else }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (if <condition> (<then>...) (<else>...))"); - return NULL; - } - - ir_rvalue *condition = read_rvalue(s_cond); - if (condition == NULL) { - ir_read_error(NULL, "when reading condition of (if ...)"); - return NULL; - } - - ir_if *iff = new(mem_ctx) ir_if(condition); - - read_instructions(&iff->then_instructions, s_then, loop_ctx); - read_instructions(&iff->else_instructions, s_else, loop_ctx); - if (state->error) { - delete iff; - iff = NULL; - } - return iff; -} - - -ir_loop * -ir_reader::read_loop(s_expression *expr) -{ - s_expression *s_counter, *s_from, *s_to, *s_inc, *s_body; - - s_pattern pat[] = { "loop", s_counter, s_from, s_to, s_inc, s_body }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (loop <counter> <from> <to> " - "<increment> <body>)"); - return NULL; - } - - // FINISHME: actually read the count/from/to fields. - - ir_loop *loop = new(mem_ctx) ir_loop; - read_instructions(&loop->body_instructions, s_body, loop); - if (state->error) { - delete loop; - loop = NULL; - } - return loop; -} - - -ir_return * -ir_reader::read_return(s_expression *expr) -{ - s_expression *s_retval; - - s_pattern pat[] = { "return", s_retval}; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (return <rvalue>)"); - return NULL; - } - - ir_rvalue *retval = read_rvalue(s_retval); - if (retval == NULL) { - ir_read_error(NULL, "when reading return value"); - return NULL; - } - - return new(mem_ctx) ir_return(retval); -} - - -ir_rvalue * -ir_reader::read_rvalue(s_expression *expr) -{ - s_list *list = SX_AS_LIST(expr); - if (list == NULL || list->subexpressions.is_empty()) - return NULL; - - s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head()); - if (tag == NULL) { - ir_read_error(expr, "expected rvalue tag"); - return NULL; - } - - ir_rvalue *rvalue = read_dereference(list); - if (rvalue != NULL || state->error) - return rvalue; - else if (strcmp(tag->value(), "swiz") == 0) { - rvalue = read_swizzle(list); - } else if (strcmp(tag->value(), "expression") == 0) { - rvalue = read_expression(list); - } else if (strcmp(tag->value(), "call") == 0) { - rvalue = read_call(list); - } else if (strcmp(tag->value(), "constant") == 0) { - rvalue = read_constant(list); - } else { - rvalue = read_texture(list); - if (rvalue == NULL && !state->error) - ir_read_error(expr, "unrecognized rvalue tag: %s", tag->value()); - } - - return rvalue; -} - -ir_assignment * -ir_reader::read_assignment(s_expression *expr) -{ - s_expression *cond_expr = NULL; - s_expression *lhs_expr, *rhs_expr; - s_list *mask_list; - - s_pattern pat4[] = { "assign", mask_list, lhs_expr, rhs_expr }; - s_pattern pat5[] = { "assign", cond_expr, mask_list, lhs_expr, rhs_expr }; - if (!MATCH(expr, pat4) && !MATCH(expr, pat5)) { - ir_read_error(expr, "expected (assign [<condition>] (<write mask>) " - "<lhs> <rhs>)"); - return NULL; - } - - ir_rvalue *condition = NULL; - if (cond_expr != NULL) { - condition = read_rvalue(cond_expr); - if (condition == NULL) { - ir_read_error(NULL, "when reading condition of assignment"); - return NULL; - } - } - - unsigned mask = 0; - - s_symbol *mask_symbol; - s_pattern mask_pat[] = { mask_symbol }; - if (MATCH(mask_list, mask_pat)) { - const char *mask_str = mask_symbol->value(); - unsigned mask_length = strlen(mask_str); - if (mask_length > 4) { - ir_read_error(expr, "invalid write mask: %s", mask_str); - return NULL; - } - - const unsigned idx_map[] = { 3, 0, 1, 2 }; /* w=bit 3, x=0, y=1, z=2 */ - - for (unsigned i = 0; i < mask_length; i++) { - if (mask_str[i] < 'w' || mask_str[i] > 'z') { - ir_read_error(expr, "write mask contains invalid character: %c", - mask_str[i]); - return NULL; - } - mask |= 1 << idx_map[mask_str[i] - 'w']; - } - } else if (!mask_list->subexpressions.is_empty()) { - ir_read_error(mask_list, "expected () or (<write mask>)"); - return NULL; - } - - ir_dereference *lhs = read_dereference(lhs_expr); - if (lhs == NULL) { - ir_read_error(NULL, "when reading left-hand side of assignment"); - return NULL; - } - - ir_rvalue *rhs = read_rvalue(rhs_expr); - if (rhs == NULL) { - ir_read_error(NULL, "when reading right-hand side of assignment"); - return NULL; - } - - if (mask == 0 && (lhs->type->is_vector() || lhs->type->is_scalar())) { - ir_read_error(expr, "non-zero write mask required."); - return NULL; - } - - return new(mem_ctx) ir_assignment(lhs, rhs, condition, mask); -} - -ir_call * -ir_reader::read_call(s_expression *expr) -{ - s_symbol *name; - s_list *params; - - s_pattern pat[] = { "call", name, params }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (call <name> (<param> ...))"); - return NULL; - } - - exec_list parameters; - - foreach_iter(exec_list_iterator, it, params->subexpressions) { - s_expression *expr = (s_expression*) it.get(); - ir_rvalue *param = read_rvalue(expr); - if (param == NULL) { - ir_read_error(expr, "when reading parameter to function call"); - return NULL; - } - parameters.push_tail(param); - } - - ir_function *f = state->symbols->get_function(name->value()); - if (f == NULL) { - ir_read_error(expr, "found call to undefined function %s", - name->value()); - return NULL; - } - - ir_function_signature *callee = f->matching_signature(¶meters); - if (callee == NULL) { - ir_read_error(expr, "couldn't find matching signature for function " - "%s", name->value()); - return NULL; - } - - return new(mem_ctx) ir_call(callee, ¶meters); -} - -ir_expression * -ir_reader::read_expression(s_expression *expr) -{ - s_expression *s_type; - s_symbol *s_op; - s_expression *s_arg1; - - s_pattern pat[] = { "expression", s_type, s_op, s_arg1 }; - if (!PARTIAL_MATCH(expr, pat)) { - ir_read_error(expr, "expected (expression <type> <operator> " - "<operand> [<operand>])"); - return NULL; - } - s_expression *s_arg2 = (s_expression *) s_arg1->next; // may be tail sentinel - - const glsl_type *type = read_type(s_type); - if (type == NULL) - return NULL; - - /* Read the operator */ - ir_expression_operation op = ir_expression::get_operator(s_op->value()); - if (op == (ir_expression_operation) -1) { - ir_read_error(expr, "invalid operator: %s", s_op->value()); - return NULL; - } - - unsigned num_operands = ir_expression::get_num_operands(op); - if (num_operands == 1 && !s_arg1->next->is_tail_sentinel()) { - ir_read_error(expr, "expected (expression <type> %s <operand>)", - s_op->value()); - return NULL; - } - - ir_rvalue *arg1 = read_rvalue(s_arg1); - ir_rvalue *arg2 = NULL; - if (arg1 == NULL) { - ir_read_error(NULL, "when reading first operand of %s", s_op->value()); - return NULL; - } - - if (num_operands == 2) { - if (s_arg2->is_tail_sentinel() || !s_arg2->next->is_tail_sentinel()) { - ir_read_error(expr, "expected (expression <type> %s <operand> " - "<operand>)", s_op->value()); - return NULL; - } - arg2 = read_rvalue(s_arg2); - if (arg2 == NULL) { - ir_read_error(NULL, "when reading second operand of %s", - s_op->value()); - return NULL; - } - } - - return new(mem_ctx) ir_expression(op, type, arg1, arg2); -} - -ir_swizzle * -ir_reader::read_swizzle(s_expression *expr) -{ - s_symbol *swiz; - s_expression *sub; - - s_pattern pat[] = { "swiz", swiz, sub }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (swiz <swizzle> <rvalue>)"); - return NULL; - } - - if (strlen(swiz->value()) > 4) { - ir_read_error(expr, "expected a valid swizzle; found %s", swiz->value()); - return NULL; - } - - ir_rvalue *rvalue = read_rvalue(sub); - if (rvalue == NULL) - return NULL; - - ir_swizzle *ir = ir_swizzle::create(rvalue, swiz->value(), - rvalue->type->vector_elements); - if (ir == NULL) - ir_read_error(expr, "invalid swizzle"); - - return ir; -} - -ir_constant * -ir_reader::read_constant(s_expression *expr) -{ - s_expression *type_expr; - s_list *values; - - s_pattern pat[] = { "constant", type_expr, values }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (constant <type> (...))"); - return NULL; - } - - const glsl_type *type = read_type(type_expr); - if (type == NULL) - return NULL; - - if (values == NULL) { - ir_read_error(expr, "expected (constant <type> (...))"); - return NULL; - } - - if (type->is_array()) { - unsigned elements_supplied = 0; - exec_list elements; - foreach_iter(exec_list_iterator, it, values->subexpressions) { - s_expression *elt = (s_expression *) it.get(); - ir_constant *ir_elt = read_constant(elt); - if (ir_elt == NULL) - return NULL; - elements.push_tail(ir_elt); - elements_supplied++; - } - - if (elements_supplied != type->length) { - ir_read_error(values, "expected exactly %u array elements, " - "given %u", type->length, elements_supplied); - return NULL; - } - return new(mem_ctx) ir_constant(type, &elements); - } - - const glsl_type *const base_type = type->get_base_type(); - - ir_constant_data data = { { 0 } }; - - // Read in list of values (at most 16). - int k = 0; - foreach_iter(exec_list_iterator, it, values->subexpressions) { - if (k >= 16) { - ir_read_error(values, "expected at most 16 numbers"); - return NULL; - } - - s_expression *expr = (s_expression*) it.get(); - - if (base_type->base_type == GLSL_TYPE_FLOAT) { - s_number *value = SX_AS_NUMBER(expr); - if (value == NULL) { - ir_read_error(values, "expected numbers"); - return NULL; - } - data.f[k] = value->fvalue(); - } else { - s_int *value = SX_AS_INT(expr); - if (value == NULL) { - ir_read_error(values, "expected integers"); - return NULL; - } - - switch (base_type->base_type) { - case GLSL_TYPE_UINT: { - data.u[k] = value->value(); - break; - } - case GLSL_TYPE_INT: { - data.i[k] = value->value(); - break; - } - case GLSL_TYPE_BOOL: { - data.b[k] = value->value(); - break; - } - default: - ir_read_error(values, "unsupported constant type"); - return NULL; - } - } - ++k; - } - - return new(mem_ctx) ir_constant(type, &data); -} - -ir_dereference * -ir_reader::read_dereference(s_expression *expr) -{ - s_symbol *s_var; - s_expression *s_subject; - s_expression *s_index; - s_symbol *s_field; - - s_pattern var_pat[] = { "var_ref", s_var }; - s_pattern array_pat[] = { "array_ref", s_subject, s_index }; - s_pattern record_pat[] = { "record_ref", s_subject, s_field }; - - if (MATCH(expr, var_pat)) { - ir_variable *var = state->symbols->get_variable(s_var->value()); - if (var == NULL) { - ir_read_error(expr, "undeclared variable: %s", s_var->value()); - return NULL; - } - return new(mem_ctx) ir_dereference_variable(var); - } else if (MATCH(expr, array_pat)) { - ir_rvalue *subject = read_rvalue(s_subject); - if (subject == NULL) { - ir_read_error(NULL, "when reading the subject of an array_ref"); - return NULL; - } - - ir_rvalue *idx = read_rvalue(s_index); - if (subject == NULL) { - ir_read_error(NULL, "when reading the index of an array_ref"); - return NULL; - } - return new(mem_ctx) ir_dereference_array(subject, idx); - } else if (MATCH(expr, record_pat)) { - ir_rvalue *subject = read_rvalue(s_subject); - if (subject == NULL) { - ir_read_error(NULL, "when reading the subject of a record_ref"); - return NULL; - } - return new(mem_ctx) ir_dereference_record(subject, s_field->value()); - } - return NULL; -} - -ir_texture * -ir_reader::read_texture(s_expression *expr) -{ - s_symbol *tag = NULL; - s_expression *s_sampler = NULL; - s_expression *s_coord = NULL; - s_expression *s_offset = NULL; - s_expression *s_proj = NULL; - s_list *s_shadow = NULL; - s_expression *s_lod = NULL; - - ir_texture_opcode op = ir_tex; /* silence warning */ - - s_pattern tex_pattern[] = - { "tex", s_sampler, s_coord, s_offset, s_proj, s_shadow }; - s_pattern txf_pattern[] = - { "txf", s_sampler, s_coord, s_offset, s_lod }; - s_pattern other_pattern[] = - { tag, s_sampler, s_coord, s_offset, s_proj, s_shadow, s_lod }; - - if (MATCH(expr, tex_pattern)) { - op = ir_tex; - } else if (MATCH(expr, txf_pattern)) { - op = ir_txf; - } else if (MATCH(expr, other_pattern)) { - op = ir_texture::get_opcode(tag->value()); - if (op == -1) - return NULL; - } else { - ir_read_error(NULL, "unexpected texture pattern"); - return NULL; - } - - ir_texture *tex = new(mem_ctx) ir_texture(op); - - // Read sampler (must be a deref) - ir_dereference *sampler = read_dereference(s_sampler); - if (sampler == NULL) { - ir_read_error(NULL, "when reading sampler in (%s ...)", - tex->opcode_string()); - return NULL; - } - tex->set_sampler(sampler); - - // Read coordinate (any rvalue) - tex->coordinate = read_rvalue(s_coord); - if (tex->coordinate == NULL) { - ir_read_error(NULL, "when reading coordinate in (%s ...)", - tex->opcode_string()); - return NULL; - } - - // Read texel offset - either 0 or an rvalue. - s_int *si_offset = SX_AS_INT(s_offset); - if (si_offset == NULL || si_offset->value() != 0) { - tex->offset = read_rvalue(s_offset); - if (tex->offset == NULL) { - ir_read_error(s_offset, "expected 0 or an expression"); - return NULL; - } - } - - if (op != ir_txf) { - s_int *proj_as_int = SX_AS_INT(s_proj); - if (proj_as_int && proj_as_int->value() == 1) { - tex->projector = NULL; - } else { - tex->projector = read_rvalue(s_proj); - if (tex->projector == NULL) { - ir_read_error(NULL, "when reading projective divide in (%s ..)", - tex->opcode_string()); - return NULL; - } - } - - if (s_shadow->subexpressions.is_empty()) { - tex->shadow_comparitor = NULL; - } else { - tex->shadow_comparitor = read_rvalue(s_shadow); - if (tex->shadow_comparitor == NULL) { - ir_read_error(NULL, "when reading shadow comparitor in (%s ..)", - tex->opcode_string()); - return NULL; - } - } - } - - switch (op) { - case ir_txb: - tex->lod_info.bias = read_rvalue(s_lod); - if (tex->lod_info.bias == NULL) { - ir_read_error(NULL, "when reading LOD bias in (txb ...)"); - return NULL; - } - break; - case ir_txl: - case ir_txf: - tex->lod_info.lod = read_rvalue(s_lod); - if (tex->lod_info.lod == NULL) { - ir_read_error(NULL, "when reading LOD in (%s ...)", - tex->opcode_string()); - return NULL; - } - break; - case ir_txd: { - s_expression *s_dx, *s_dy; - s_pattern dxdy_pat[] = { s_dx, s_dy }; - if (!MATCH(s_lod, dxdy_pat)) { - ir_read_error(s_lod, "expected (dPdx dPdy) in (txd ...)"); - return NULL; - } - tex->lod_info.grad.dPdx = read_rvalue(s_dx); - if (tex->lod_info.grad.dPdx == NULL) { - ir_read_error(NULL, "when reading dPdx in (txd ...)"); - return NULL; - } - tex->lod_info.grad.dPdy = read_rvalue(s_dy); - if (tex->lod_info.grad.dPdy == NULL) { - ir_read_error(NULL, "when reading dPdy in (txd ...)"); - return NULL; - } - break; - } - default: - // tex doesn't have any extra parameters. - break; - }; - return tex; -} +/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ir_reader.h"
+#include "glsl_parser_extras.h"
+#include "glsl_types.h"
+#include "s_expression.h"
+
+const static bool debug = false;
+
+class ir_reader {
+public:
+ ir_reader(_mesa_glsl_parse_state *);
+
+ void read(exec_list *instructions, const char *src, bool scan_for_protos);
+
+private:
+ void *mem_ctx;
+ _mesa_glsl_parse_state *state;
+
+ void ir_read_error(s_expression *, const char *fmt, ...);
+
+ const glsl_type *read_type(s_expression *);
+
+ void scan_for_prototypes(exec_list *, s_expression *);
+ ir_function *read_function(s_expression *, bool skip_body);
+ void read_function_sig(ir_function *, s_expression *, bool skip_body);
+
+ void read_instructions(exec_list *, s_expression *, ir_loop *);
+ ir_instruction *read_instruction(s_expression *, ir_loop *);
+ ir_variable *read_declaration(s_expression *);
+ ir_if *read_if(s_expression *, ir_loop *);
+ ir_loop *read_loop(s_expression *);
+ ir_return *read_return(s_expression *);
+ ir_rvalue *read_rvalue(s_expression *);
+ ir_assignment *read_assignment(s_expression *);
+ ir_expression *read_expression(s_expression *);
+ ir_call *read_call(s_expression *);
+ ir_swizzle *read_swizzle(s_expression *);
+ ir_constant *read_constant(s_expression *);
+ ir_texture *read_texture(s_expression *);
+
+ ir_dereference *read_dereference(s_expression *);
+};
+
+ir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state)
+{
+ this->mem_ctx = state;
+}
+
+void
+_mesa_glsl_read_ir(_mesa_glsl_parse_state *state, exec_list *instructions,
+ const char *src, bool scan_for_protos)
+{
+ ir_reader r(state);
+ r.read(instructions, src, scan_for_protos);
+}
+
+void
+ir_reader::read(exec_list *instructions, const char *src, bool scan_for_protos)
+{
+ s_expression *expr = s_expression::read_expression(mem_ctx, src);
+ if (expr == NULL) {
+ ir_read_error(NULL, "couldn't parse S-Expression.");
+ return;
+ }
+
+ if (scan_for_protos) {
+ scan_for_prototypes(instructions, expr);
+ if (state->error)
+ return;
+ }
+
+ read_instructions(instructions, expr, NULL);
+ ralloc_free(expr);
+
+ if (debug)
+ validate_ir_tree(instructions);
+}
+
+void
+ir_reader::ir_read_error(s_expression *expr, const char *fmt, ...)
+{
+ va_list ap;
+
+ state->error = true;
+
+ if (state->current_function != NULL)
+ ralloc_asprintf_append(&state->info_log, "In function %s:\n",
+ state->current_function->function_name());
+ ralloc_strcat(&state->info_log, "error: ");
+
+ va_start(ap, fmt);
+ ralloc_vasprintf_append(&state->info_log, fmt, ap);
+ va_end(ap);
+ ralloc_strcat(&state->info_log, "\n");
+
+ if (expr != NULL) {
+ ralloc_strcat(&state->info_log, "...in this context:\n ");
+ expr->print();
+ ralloc_strcat(&state->info_log, "\n\n");
+ }
+}
+
+const glsl_type *
+ir_reader::read_type(s_expression *expr)
+{
+ s_expression *s_base_type;
+ s_int *s_size;
+
+ s_pattern pat[] = { "array", s_base_type, s_size };
+ if (MATCH(expr, pat)) {
+ const glsl_type *base_type = read_type(s_base_type);
+ if (base_type == NULL) {
+ ir_read_error(NULL, "when reading base type of array type");
+ return NULL;
+ }
+
+ return glsl_type::get_array_instance(base_type, s_size->value());
+ }
+
+ s_symbol *type_sym = SX_AS_SYMBOL(expr);
+ if (type_sym == NULL) {
+ ir_read_error(expr, "expected <type>");
+ return NULL;
+ }
+
+ const glsl_type *type = state->symbols->get_type(type_sym->value());
+ if (type == NULL)
+ ir_read_error(expr, "invalid type: %s", type_sym->value());
+
+ return type;
+}
+
+
+void
+ir_reader::scan_for_prototypes(exec_list *instructions, s_expression *expr)
+{
+ s_list *list = SX_AS_LIST(expr);
+ if (list == NULL) {
+ ir_read_error(expr, "Expected (<instruction> ...); found an atom.");
+ return;
+ }
+
+ foreach_iter(exec_list_iterator, it, list->subexpressions) {
+ s_list *sub = SX_AS_LIST(it.get());
+ if (sub == NULL)
+ continue; // not a (function ...); ignore it.
+
+ s_symbol *tag = SX_AS_SYMBOL(sub->subexpressions.get_head());
+ if (tag == NULL || strcmp(tag->value(), "function") != 0)
+ continue; // not a (function ...); ignore it.
+
+ ir_function *f = read_function(sub, true);
+ if (f == NULL)
+ return;
+ instructions->push_tail(f);
+ }
+}
+
+ir_function *
+ir_reader::read_function(s_expression *expr, bool skip_body)
+{
+ bool added = false;
+ s_symbol *name;
+
+ s_pattern pat[] = { "function", name };
+ if (!PARTIAL_MATCH(expr, pat)) {
+ ir_read_error(expr, "Expected (function <name> (signature ...) ...)");
+ return NULL;
+ }
+
+ ir_function *f = state->symbols->get_function(name->value());
+ if (f == NULL) {
+ f = new(mem_ctx) ir_function(name->value());
+ added = state->symbols->add_function(f);
+ assert(added);
+ }
+
+ exec_list_iterator it = ((s_list *) expr)->subexpressions.iterator();
+ it.next(); // skip "function" tag
+ it.next(); // skip function name
+ for (/* nothing */; it.has_next(); it.next()) {
+ s_expression *s_sig = (s_expression *) it.get();
+ read_function_sig(f, s_sig, skip_body);
+ }
+ return added ? f : NULL;
+}
+
+void
+ir_reader::read_function_sig(ir_function *f, s_expression *expr, bool skip_body)
+{
+ s_expression *type_expr;
+ s_list *paramlist;
+ s_list *body_list;
+
+ s_pattern pat[] = { "signature", type_expr, paramlist, body_list };
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "Expected (signature <type> (parameters ...) "
+ "(<instruction> ...))");
+ return;
+ }
+
+ const glsl_type *return_type = read_type(type_expr);
+ if (return_type == NULL)
+ return;
+
+ s_symbol *paramtag = SX_AS_SYMBOL(paramlist->subexpressions.get_head());
+ if (paramtag == NULL || strcmp(paramtag->value(), "parameters") != 0) {
+ ir_read_error(paramlist, "Expected (parameters ...)");
+ return;
+ }
+
+ // Read the parameters list into a temporary place.
+ exec_list hir_parameters;
+ state->symbols->push_scope();
+
+ exec_list_iterator it = paramlist->subexpressions.iterator();
+ for (it.next() /* skip "parameters" */; it.has_next(); it.next()) {
+ ir_variable *var = read_declaration((s_expression *) it.get());
+ if (var == NULL)
+ return;
+
+ hir_parameters.push_tail(var);
+ }
+
+ ir_function_signature *sig = f->exact_matching_signature(&hir_parameters);
+ if (sig == NULL && skip_body) {
+ /* If scanning for prototypes, generate a new signature. */
+ sig = new(mem_ctx) ir_function_signature(return_type);
+ sig->is_builtin = true;
+ f->add_signature(sig);
+ } else if (sig != NULL) {
+ const char *badvar = sig->qualifiers_match(&hir_parameters);
+ if (badvar != NULL) {
+ ir_read_error(expr, "function `%s' parameter `%s' qualifiers "
+ "don't match prototype", f->name, badvar);
+ return;
+ }
+
+ if (sig->return_type != return_type) {
+ ir_read_error(expr, "function `%s' return type doesn't "
+ "match prototype", f->name);
+ return;
+ }
+ } else {
+ /* No prototype for this body exists - skip it. */
+ state->symbols->pop_scope();
+ return;
+ }
+ assert(sig != NULL);
+
+ sig->replace_parameters(&hir_parameters);
+
+ if (!skip_body && !body_list->subexpressions.is_empty()) {
+ if (sig->is_defined) {
+ ir_read_error(expr, "function %s redefined", f->name);
+ return;
+ }
+ state->current_function = sig;
+ read_instructions(&sig->body, body_list, NULL);
+ state->current_function = NULL;
+ sig->is_defined = true;
+ }
+
+ state->symbols->pop_scope();
+}
+
+void
+ir_reader::read_instructions(exec_list *instructions, s_expression *expr,
+ ir_loop *loop_ctx)
+{
+ // Read in a list of instructions
+ s_list *list = SX_AS_LIST(expr);
+ if (list == NULL) {
+ ir_read_error(expr, "Expected (<instruction> ...); found an atom.");
+ return;
+ }
+
+ foreach_iter(exec_list_iterator, it, list->subexpressions) {
+ s_expression *sub = (s_expression*) it.get();
+ ir_instruction *ir = read_instruction(sub, loop_ctx);
+ if (ir != NULL) {
+ /* Global variable declarations should be moved to the top, before
+ * any functions that might use them. Functions are added to the
+ * instruction stream when scanning for prototypes, so without this
+ * hack, they always appear before variable declarations.
+ */
+ if (state->current_function == NULL && ir->as_variable() != NULL)
+ instructions->push_head(ir);
+ else
+ instructions->push_tail(ir);
+ }
+ }
+}
+
+
+ir_instruction *
+ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx)
+{
+ s_symbol *symbol = SX_AS_SYMBOL(expr);
+ if (symbol != NULL) {
+ if (strcmp(symbol->value(), "break") == 0 && loop_ctx != NULL)
+ return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break);
+ if (strcmp(symbol->value(), "continue") == 0 && loop_ctx != NULL)
+ return new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
+ }
+
+ s_list *list = SX_AS_LIST(expr);
+ if (list == NULL || list->subexpressions.is_empty()) {
+ ir_read_error(expr, "Invalid instruction.\n");
+ return NULL;
+ }
+
+ s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head());
+ if (tag == NULL) {
+ ir_read_error(expr, "expected instruction tag");
+ return NULL;
+ }
+
+ ir_instruction *inst = NULL;
+ if (strcmp(tag->value(), "declare") == 0) {
+ inst = read_declaration(list);
+ } else if (strcmp(tag->value(), "assign") == 0) {
+ inst = read_assignment(list);
+ } else if (strcmp(tag->value(), "if") == 0) {
+ inst = read_if(list, loop_ctx);
+ } else if (strcmp(tag->value(), "loop") == 0) {
+ inst = read_loop(list);
+ } else if (strcmp(tag->value(), "return") == 0) {
+ inst = read_return(list);
+ } else if (strcmp(tag->value(), "function") == 0) {
+ inst = read_function(list, false);
+ } else {
+ inst = read_rvalue(list);
+ if (inst == NULL)
+ ir_read_error(NULL, "when reading instruction");
+ }
+ return inst;
+}
+
+ir_variable *
+ir_reader::read_declaration(s_expression *expr)
+{
+ s_list *s_quals;
+ s_expression *s_type;
+ s_symbol *s_name;
+
+ s_pattern pat[] = { "declare", s_quals, s_type, s_name };
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (declare (<qualifiers>) <type> <name>)");
+ return NULL;
+ }
+
+ const glsl_type *type = read_type(s_type);
+ if (type == NULL)
+ return NULL;
+
+ ir_variable *var = new(mem_ctx) ir_variable(type, s_name->value(),
+ ir_var_auto);
+
+ foreach_iter(exec_list_iterator, it, s_quals->subexpressions) {
+ s_symbol *qualifier = SX_AS_SYMBOL(it.get());
+ if (qualifier == NULL) {
+ ir_read_error(expr, "qualifier list must contain only symbols");
+ return NULL;
+ }
+
+ // FINISHME: Check for duplicate/conflicting qualifiers.
+ if (strcmp(qualifier->value(), "centroid") == 0) {
+ var->centroid = 1;
+ } else if (strcmp(qualifier->value(), "invariant") == 0) {
+ var->invariant = 1;
+ } else if (strcmp(qualifier->value(), "uniform") == 0) {
+ var->mode = ir_var_uniform;
+ } else if (strcmp(qualifier->value(), "auto") == 0) {
+ var->mode = ir_var_auto;
+ } else if (strcmp(qualifier->value(), "in") == 0) {
+ var->mode = ir_var_in;
+ } else if (strcmp(qualifier->value(), "const_in") == 0) {
+ var->mode = ir_var_const_in;
+ } else if (strcmp(qualifier->value(), "out") == 0) {
+ var->mode = ir_var_out;
+ } else if (strcmp(qualifier->value(), "inout") == 0) {
+ var->mode = ir_var_inout;
+ } else if (strcmp(qualifier->value(), "smooth") == 0) {
+ var->interpolation = ir_var_smooth;
+ } else if (strcmp(qualifier->value(), "flat") == 0) {
+ var->interpolation = ir_var_flat;
+ } else if (strcmp(qualifier->value(), "noperspective") == 0) {
+ var->interpolation = ir_var_noperspective;
+ } else {
+ ir_read_error(expr, "unknown qualifier: %s", qualifier->value());
+ return NULL;
+ }
+ }
+
+ // Add the variable to the symbol table
+ state->symbols->add_variable(var);
+
+ return var;
+}
+
+
+ir_if *
+ir_reader::read_if(s_expression *expr, ir_loop *loop_ctx)
+{
+ s_expression *s_cond;
+ s_expression *s_then;
+ s_expression *s_else;
+
+ s_pattern pat[] = { "if", s_cond, s_then, s_else };
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (if <condition> (<then>...) (<else>...))");
+ return NULL;
+ }
+
+ ir_rvalue *condition = read_rvalue(s_cond);
+ if (condition == NULL) {
+ ir_read_error(NULL, "when reading condition of (if ...)");
+ return NULL;
+ }
+
+ ir_if *iff = new(mem_ctx) ir_if(condition);
+
+ read_instructions(&iff->then_instructions, s_then, loop_ctx);
+ read_instructions(&iff->else_instructions, s_else, loop_ctx);
+ if (state->error) {
+ delete iff;
+ iff = NULL;
+ }
+ return iff;
+}
+
+
+ir_loop *
+ir_reader::read_loop(s_expression *expr)
+{
+ s_expression *s_counter, *s_from, *s_to, *s_inc, *s_body;
+
+ s_pattern pat[] = { "loop", s_counter, s_from, s_to, s_inc, s_body };
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (loop <counter> <from> <to> "
+ "<increment> <body>)");
+ return NULL;
+ }
+
+ // FINISHME: actually read the count/from/to fields.
+
+ ir_loop *loop = new(mem_ctx) ir_loop;
+ read_instructions(&loop->body_instructions, s_body, loop);
+ if (state->error) {
+ delete loop;
+ loop = NULL;
+ }
+ return loop;
+}
+
+
+ir_return *
+ir_reader::read_return(s_expression *expr)
+{
+ s_expression *s_retval;
+
+ s_pattern pat[] = { "return", s_retval};
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (return <rvalue>)");
+ return NULL;
+ }
+
+ ir_rvalue *retval = read_rvalue(s_retval);
+ if (retval == NULL) {
+ ir_read_error(NULL, "when reading return value");
+ return NULL;
+ }
+
+ return new(mem_ctx) ir_return(retval);
+}
+
+
+ir_rvalue *
+ir_reader::read_rvalue(s_expression *expr)
+{
+ s_list *list = SX_AS_LIST(expr);
+ if (list == NULL || list->subexpressions.is_empty())
+ return NULL;
+
+ s_symbol *tag = SX_AS_SYMBOL(list->subexpressions.get_head());
+ if (tag == NULL) {
+ ir_read_error(expr, "expected rvalue tag");
+ return NULL;
+ }
+
+ ir_rvalue *rvalue = read_dereference(list);
+ if (rvalue != NULL || state->error)
+ return rvalue;
+ else if (strcmp(tag->value(), "swiz") == 0) {
+ rvalue = read_swizzle(list);
+ } else if (strcmp(tag->value(), "expression") == 0) {
+ rvalue = read_expression(list);
+ } else if (strcmp(tag->value(), "call") == 0) {
+ rvalue = read_call(list);
+ } else if (strcmp(tag->value(), "constant") == 0) {
+ rvalue = read_constant(list);
+ } else {
+ rvalue = read_texture(list);
+ if (rvalue == NULL && !state->error)
+ ir_read_error(expr, "unrecognized rvalue tag: %s", tag->value());
+ }
+
+ return rvalue;
+}
+
+ir_assignment *
+ir_reader::read_assignment(s_expression *expr)
+{
+ s_expression *cond_expr = NULL;
+ s_expression *lhs_expr, *rhs_expr;
+ s_list *mask_list;
+
+ s_pattern pat4[] = { "assign", mask_list, lhs_expr, rhs_expr };
+ s_pattern pat5[] = { "assign", cond_expr, mask_list, lhs_expr, rhs_expr };
+ if (!MATCH(expr, pat4) && !MATCH(expr, pat5)) {
+ ir_read_error(expr, "expected (assign [<condition>] (<write mask>) "
+ "<lhs> <rhs>)");
+ return NULL;
+ }
+
+ ir_rvalue *condition = NULL;
+ if (cond_expr != NULL) {
+ condition = read_rvalue(cond_expr);
+ if (condition == NULL) {
+ ir_read_error(NULL, "when reading condition of assignment");
+ return NULL;
+ }
+ }
+
+ unsigned mask = 0;
+
+ s_symbol *mask_symbol;
+ s_pattern mask_pat[] = { mask_symbol };
+ if (MATCH(mask_list, mask_pat)) {
+ const char *mask_str = mask_symbol->value();
+ unsigned mask_length = strlen(mask_str);
+ if (mask_length > 4) {
+ ir_read_error(expr, "invalid write mask: %s", mask_str);
+ return NULL;
+ }
+
+ const unsigned idx_map[] = { 3, 0, 1, 2 }; /* w=bit 3, x=0, y=1, z=2 */
+
+ for (unsigned i = 0; i < mask_length; i++) {
+ if (mask_str[i] < 'w' || mask_str[i] > 'z') {
+ ir_read_error(expr, "write mask contains invalid character: %c",
+ mask_str[i]);
+ return NULL;
+ }
+ mask |= 1 << idx_map[mask_str[i] - 'w'];
+ }
+ } else if (!mask_list->subexpressions.is_empty()) {
+ ir_read_error(mask_list, "expected () or (<write mask>)");
+ return NULL;
+ }
+
+ ir_dereference *lhs = read_dereference(lhs_expr);
+ if (lhs == NULL) {
+ ir_read_error(NULL, "when reading left-hand side of assignment");
+ return NULL;
+ }
+
+ ir_rvalue *rhs = read_rvalue(rhs_expr);
+ if (rhs == NULL) {
+ ir_read_error(NULL, "when reading right-hand side of assignment");
+ return NULL;
+ }
+
+ if (mask == 0 && (lhs->type->is_vector() || lhs->type->is_scalar())) {
+ ir_read_error(expr, "non-zero write mask required.");
+ return NULL;
+ }
+
+ return new(mem_ctx) ir_assignment(lhs, rhs, condition, mask);
+}
+
+ir_call *
+ir_reader::read_call(s_expression *expr)
+{
+ s_symbol *name;
+ s_list *params;
+
+ s_pattern pat[] = { "call", name, params };
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (call <name> (<param> ...))");
+ return NULL;
+ }
+
+ exec_list parameters;
+
+ foreach_iter(exec_list_iterator, it, params->subexpressions) {
+ s_expression *expr = (s_expression*) it.get();
+ ir_rvalue *param = read_rvalue(expr);
+ if (param == NULL) {
+ ir_read_error(expr, "when reading parameter to function call");
+ return NULL;
+ }
+ parameters.push_tail(param);
+ }
+
+ ir_function *f = state->symbols->get_function(name->value());
+ if (f == NULL) {
+ ir_read_error(expr, "found call to undefined function %s",
+ name->value());
+ return NULL;
+ }
+
+ ir_function_signature *callee = f->matching_signature(¶meters);
+ if (callee == NULL) {
+ ir_read_error(expr, "couldn't find matching signature for function "
+ "%s", name->value());
+ return NULL;
+ }
+
+ return new(mem_ctx) ir_call(callee, ¶meters);
+}
+
+ir_expression *
+ir_reader::read_expression(s_expression *expr)
+{
+ s_expression *s_type;
+ s_symbol *s_op;
+ s_expression *s_arg1;
+
+ s_pattern pat[] = { "expression", s_type, s_op, s_arg1 };
+ if (!PARTIAL_MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (expression <type> <operator> "
+ "<operand> [<operand>])");
+ return NULL;
+ }
+ s_expression *s_arg2 = (s_expression *) s_arg1->next; // may be tail sentinel
+
+ const glsl_type *type = read_type(s_type);
+ if (type == NULL)
+ return NULL;
+
+ /* Read the operator */
+ ir_expression_operation op = ir_expression::get_operator(s_op->value());
+ if (op == (ir_expression_operation) -1) {
+ ir_read_error(expr, "invalid operator: %s", s_op->value());
+ return NULL;
+ }
+
+ unsigned num_operands = ir_expression::get_num_operands(op);
+ if (num_operands == 1 && !s_arg1->next->is_tail_sentinel()) {
+ ir_read_error(expr, "expected (expression <type> %s <operand>)",
+ s_op->value());
+ return NULL;
+ }
+
+ ir_rvalue *arg1 = read_rvalue(s_arg1);
+ ir_rvalue *arg2 = NULL;
+ if (arg1 == NULL) {
+ ir_read_error(NULL, "when reading first operand of %s", s_op->value());
+ return NULL;
+ }
+
+ if (num_operands == 2) {
+ if (s_arg2->is_tail_sentinel() || !s_arg2->next->is_tail_sentinel()) {
+ ir_read_error(expr, "expected (expression <type> %s <operand> "
+ "<operand>)", s_op->value());
+ return NULL;
+ }
+ arg2 = read_rvalue(s_arg2);
+ if (arg2 == NULL) {
+ ir_read_error(NULL, "when reading second operand of %s",
+ s_op->value());
+ return NULL;
+ }
+ }
+
+ return new(mem_ctx) ir_expression(op, type, arg1, arg2);
+}
+
+ir_swizzle *
+ir_reader::read_swizzle(s_expression *expr)
+{
+ s_symbol *swiz;
+ s_expression *sub;
+
+ s_pattern pat[] = { "swiz", swiz, sub };
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (swiz <swizzle> <rvalue>)");
+ return NULL;
+ }
+
+ if (strlen(swiz->value()) > 4) {
+ ir_read_error(expr, "expected a valid swizzle; found %s", swiz->value());
+ return NULL;
+ }
+
+ ir_rvalue *rvalue = read_rvalue(sub);
+ if (rvalue == NULL)
+ return NULL;
+
+ ir_swizzle *ir = ir_swizzle::create(rvalue, swiz->value(),
+ rvalue->type->vector_elements);
+ if (ir == NULL)
+ ir_read_error(expr, "invalid swizzle");
+
+ return ir;
+}
+
+ir_constant *
+ir_reader::read_constant(s_expression *expr)
+{
+ s_expression *type_expr;
+ s_list *values;
+
+ s_pattern pat[] = { "constant", type_expr, values };
+ if (!MATCH(expr, pat)) {
+ ir_read_error(expr, "expected (constant <type> (...))");
+ return NULL;
+ }
+
+ const glsl_type *type = read_type(type_expr);
+ if (type == NULL)
+ return NULL;
+
+ if (values == NULL) {
+ ir_read_error(expr, "expected (constant <type> (...))");
+ return NULL;
+ }
+
+ if (type->is_array()) {
+ unsigned elements_supplied = 0;
+ exec_list elements;
+ foreach_iter(exec_list_iterator, it, values->subexpressions) {
+ s_expression *elt = (s_expression *) it.get();
+ ir_constant *ir_elt = read_constant(elt);
+ if (ir_elt == NULL)
+ return NULL;
+ elements.push_tail(ir_elt);
+ elements_supplied++;
+ }
+
+ if (elements_supplied != type->length) {
+ ir_read_error(values, "expected exactly %u array elements, "
+ "given %u", type->length, elements_supplied);
+ return NULL;
+ }
+ return new(mem_ctx) ir_constant(type, &elements);
+ }
+
+ const glsl_type *const base_type = type->get_base_type();
+
+ ir_constant_data data = { { 0 } };
+
+ // Read in list of values (at most 16).
+ int k = 0;
+ foreach_iter(exec_list_iterator, it, values->subexpressions) {
+ if (k >= 16) {
+ ir_read_error(values, "expected at most 16 numbers");
+ return NULL;
+ }
+
+ s_expression *expr = (s_expression*) it.get();
+
+ if (base_type->base_type == GLSL_TYPE_FLOAT) {
+ s_number *value = SX_AS_NUMBER(expr);
+ if (value == NULL) {
+ ir_read_error(values, "expected numbers");
+ return NULL;
+ }
+ data.f[k] = value->fvalue();
+ } else {
+ s_int *value = SX_AS_INT(expr);
+ if (value == NULL) {
+ ir_read_error(values, "expected integers");
+ return NULL;
+ }
+
+ switch (base_type->base_type) {
+ case GLSL_TYPE_UINT: {
+ data.u[k] = value->value();
+ break;
+ }
+ case GLSL_TYPE_INT: {
+ data.i[k] = value->value();
+ break;
+ }
+ case GLSL_TYPE_BOOL: {
+ data.b[k] = value->value();
+ break;
+ }
+ default:
+ ir_read_error(values, "unsupported constant type");
+ return NULL;
+ }
+ }
+ ++k;
+ }
+
+ return new(mem_ctx) ir_constant(type, &data);
+}
+
+ir_dereference *
+ir_reader::read_dereference(s_expression *expr)
+{
+ s_symbol *s_var;
+ s_expression *s_subject;
+ s_expression *s_index;
+ s_symbol *s_field;
+
+ s_pattern var_pat[] = { "var_ref", s_var };
+ s_pattern array_pat[] = { "array_ref", s_subject, s_index };
+ s_pattern record_pat[] = { "record_ref", s_subject, s_field };
+
+ if (MATCH(expr, var_pat)) {
+ ir_variable *var = state->symbols->get_variable(s_var->value());
+ if (var == NULL) {
+ ir_read_error(expr, "undeclared variable: %s", s_var->value());
+ return NULL;
+ }
+ return new(mem_ctx) ir_dereference_variable(var);
+ } else if (MATCH(expr, array_pat)) {
+ ir_rvalue *subject = read_rvalue(s_subject);
+ if (subject == NULL) {
+ ir_read_error(NULL, "when reading the subject of an array_ref");
+ return NULL;
+ }
+
+ ir_rvalue *idx = read_rvalue(s_index);
+ if (subject == NULL) {
+ ir_read_error(NULL, "when reading the index of an array_ref");
+ return NULL;
+ }
+ return new(mem_ctx) ir_dereference_array(subject, idx);
+ } else if (MATCH(expr, record_pat)) {
+ ir_rvalue *subject = read_rvalue(s_subject);
+ if (subject == NULL) {
+ ir_read_error(NULL, "when reading the subject of a record_ref");
+ return NULL;
+ }
+ return new(mem_ctx) ir_dereference_record(subject, s_field->value());
+ }
+ return NULL;
+}
+
+ir_texture *
+ir_reader::read_texture(s_expression *expr)
+{
+ s_symbol *tag = NULL;
+ s_expression *s_type = NULL;
+ s_expression *s_sampler = NULL;
+ s_expression *s_coord = NULL;
+ s_expression *s_offset = NULL;
+ s_expression *s_proj = NULL;
+ s_list *s_shadow = NULL;
+ s_expression *s_lod = NULL;
+
+ ir_texture_opcode op = ir_tex; /* silence warning */
+
+ s_pattern tex_pattern[] =
+ { "tex", s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow };
+ s_pattern txf_pattern[] =
+ { "txf", s_type, s_sampler, s_coord, s_offset, s_lod };
+ s_pattern other_pattern[] =
+ { tag, s_type, s_sampler, s_coord, s_offset, s_proj, s_shadow, s_lod };
+
+ if (MATCH(expr, tex_pattern)) {
+ op = ir_tex;
+ } else if (MATCH(expr, txf_pattern)) {
+ op = ir_txf;
+ } else if (MATCH(expr, other_pattern)) {
+ op = ir_texture::get_opcode(tag->value());
+ if (op == -1)
+ return NULL;
+ } else {
+ ir_read_error(NULL, "unexpected texture pattern");
+ return NULL;
+ }
+
+ ir_texture *tex = new(mem_ctx) ir_texture(op);
+
+ // Read return type
+ const glsl_type *type = read_type(s_type);
+ if (type == NULL) {
+ ir_read_error(NULL, "when reading type in (%s ...)",
+ tex->opcode_string());
+ return NULL;
+ }
+
+ // Read sampler (must be a deref)
+ ir_dereference *sampler = read_dereference(s_sampler);
+ if (sampler == NULL) {
+ ir_read_error(NULL, "when reading sampler in (%s ...)",
+ tex->opcode_string());
+ return NULL;
+ }
+ tex->set_sampler(sampler, type);
+
+ // Read coordinate (any rvalue)
+ tex->coordinate = read_rvalue(s_coord);
+ if (tex->coordinate == NULL) {
+ ir_read_error(NULL, "when reading coordinate in (%s ...)",
+ tex->opcode_string());
+ return NULL;
+ }
+
+ // Read texel offset - either 0 or an rvalue.
+ s_int *si_offset = SX_AS_INT(s_offset);
+ if (si_offset == NULL || si_offset->value() != 0) {
+ tex->offset = read_rvalue(s_offset);
+ if (tex->offset == NULL) {
+ ir_read_error(s_offset, "expected 0 or an expression");
+ return NULL;
+ }
+ }
+
+ if (op != ir_txf) {
+ s_int *proj_as_int = SX_AS_INT(s_proj);
+ if (proj_as_int && proj_as_int->value() == 1) {
+ tex->projector = NULL;
+ } else {
+ tex->projector = read_rvalue(s_proj);
+ if (tex->projector == NULL) {
+ ir_read_error(NULL, "when reading projective divide in (%s ..)",
+ tex->opcode_string());
+ return NULL;
+ }
+ }
+
+ if (s_shadow->subexpressions.is_empty()) {
+ tex->shadow_comparitor = NULL;
+ } else {
+ tex->shadow_comparitor = read_rvalue(s_shadow);
+ if (tex->shadow_comparitor == NULL) {
+ ir_read_error(NULL, "when reading shadow comparitor in (%s ..)",
+ tex->opcode_string());
+ return NULL;
+ }
+ }
+ }
+
+ switch (op) {
+ case ir_txb:
+ tex->lod_info.bias = read_rvalue(s_lod);
+ if (tex->lod_info.bias == NULL) {
+ ir_read_error(NULL, "when reading LOD bias in (txb ...)");
+ return NULL;
+ }
+ break;
+ case ir_txl:
+ case ir_txf:
+ tex->lod_info.lod = read_rvalue(s_lod);
+ if (tex->lod_info.lod == NULL) {
+ ir_read_error(NULL, "when reading LOD in (%s ...)",
+ tex->opcode_string());
+ return NULL;
+ }
+ break;
+ case ir_txd: {
+ s_expression *s_dx, *s_dy;
+ s_pattern dxdy_pat[] = { s_dx, s_dy };
+ if (!MATCH(s_lod, dxdy_pat)) {
+ ir_read_error(s_lod, "expected (dPdx dPdy) in (txd ...)");
+ return NULL;
+ }
+ tex->lod_info.grad.dPdx = read_rvalue(s_dx);
+ if (tex->lod_info.grad.dPdx == NULL) {
+ ir_read_error(NULL, "when reading dPdx in (txd ...)");
+ return NULL;
+ }
+ tex->lod_info.grad.dPdy = read_rvalue(s_dy);
+ if (tex->lod_info.grad.dPdy == NULL) {
+ ir_read_error(NULL, "when reading dPdy in (txd ...)");
+ return NULL;
+ }
+ break;
+ }
+ default:
+ // tex doesn't have any extra parameters.
+ break;
+ };
+ return tex;
+}
diff --git a/mesalib/src/glsl/opt_dead_functions.cpp b/mesalib/src/glsl/opt_dead_functions.cpp index ceb79080a..3c3eb8904 100644 --- a/mesalib/src/glsl/opt_dead_functions.cpp +++ b/mesalib/src/glsl/opt_dead_functions.cpp @@ -1,153 +1,164 @@ - /* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - - /** - * \file opt_dead_functions.cpp - * - * Eliminates unused functions from the linked program. - */ - - #include "ir.h" - #include "ir_visitor.h" - #include "ir_expression_flattening.h" - #include "glsl_types.h" - - class signature_entry : public exec_node - { - public: - signature_entry(ir_function_signature *sig) - { - this->signature = sig; - this->used = false; - } - - ir_function_signature *signature; - bool used; - }; - - class ir_dead_functions_visitor : public ir_hierarchical_visitor { - public: - ir_dead_functions_visitor() - { - this->mem_ctx = ralloc_context(NULL); - } - - ~ir_dead_functions_visitor() - { - ralloc_free(this->mem_ctx); - } - - virtual ir_visitor_status visit_enter(ir_function_signature *); - virtual ir_visitor_status visit_enter(ir_call *); - - signature_entry *get_signature_entry(ir_function_signature *var); - - bool (*predicate)(ir_instruction *ir); - - /* List of signature_entry */ - exec_list signature_list; - void *mem_ctx; - }; - - - signature_entry * - ir_dead_functions_visitor::get_signature_entry(ir_function_signature *sig) - { - foreach_iter(exec_list_iterator, iter, this->signature_list) { - signature_entry *entry = (signature_entry *)iter.get(); - if (entry->signature == sig) - return entry; - } - - signature_entry *entry = new(mem_ctx) signature_entry(sig); - this->signature_list.push_tail(entry); - return entry; - } - - - ir_visitor_status - ir_dead_functions_visitor::visit_enter(ir_function_signature *ir) - { - signature_entry *entry = this->get_signature_entry(ir); - - if (strcmp(ir->function_name(), "main") == 0) { - entry->used = true; - } - - return visit_continue; - } - - - ir_visitor_status - ir_dead_functions_visitor::visit_enter(ir_call *ir) - { - signature_entry *entry = this->get_signature_entry(ir->get_callee()); - - entry->used = true; - - return visit_continue; -} - -bool -do_dead_functions(exec_list *instructions) -{ - ir_dead_functions_visitor v; - bool progress = false; - - visit_list_elements(&v, instructions); - - /* Now that we've figured out which function signatures are used, remove - * the unused ones, and remove function definitions that have no more - * signatures. - */ - foreach_iter(exec_list_iterator, iter, v.signature_list) { - signature_entry *entry = (signature_entry *)iter.get(); - - if (!entry->used) { - entry->signature->remove(); - delete entry->signature; - progress = true; - } - delete(entry); - } - - /* We don't just do this above when we nuked a signature because of - * const pointers. - */ - foreach_iter(exec_list_iterator, iter, *instructions) { - ir_instruction *ir = (ir_instruction *)iter.get(); - ir_function *func = ir->as_function(); - - if (func && func->signatures.is_empty()) { - /* At this point (post-linking), the symbol table is no - * longer in use, so not removing the function from the - * symbol table should be OK. - */ - func->remove(); - delete func; - progress = true; - } - } - - return progress; -} +/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file opt_dead_functions.cpp
+ *
+ * Eliminates unused functions from the linked program.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+
+class signature_entry : public exec_node
+{
+public:
+ signature_entry(ir_function_signature *sig)
+ {
+ this->signature = sig;
+ this->used = false;
+ }
+
+ ir_function_signature *signature;
+ bool used;
+};
+
+class ir_dead_functions_visitor : public ir_hierarchical_visitor {
+public:
+ ir_dead_functions_visitor()
+ {
+ this->mem_ctx = ralloc_context(NULL);
+ this->seen_another_function_signature = false;
+ }
+
+ ~ir_dead_functions_visitor()
+ {
+ ralloc_free(this->mem_ctx);
+ }
+
+ virtual ir_visitor_status visit_enter(ir_function_signature *);
+ virtual ir_visitor_status visit_enter(ir_call *);
+
+ signature_entry *get_signature_entry(ir_function_signature *var);
+
+ bool (*predicate)(ir_instruction *ir);
+
+ bool seen_another_function_signature;
+
+ /* List of signature_entry */
+ exec_list signature_list;
+ void *mem_ctx;
+};
+
+
+signature_entry *
+ir_dead_functions_visitor::get_signature_entry(ir_function_signature *sig)
+{
+ foreach_iter(exec_list_iterator, iter, this->signature_list) {
+ signature_entry *entry = (signature_entry *)iter.get();
+ if (entry->signature == sig)
+ return entry;
+ }
+
+ signature_entry *entry = new(mem_ctx) signature_entry(sig);
+ this->signature_list.push_tail(entry);
+ return entry;
+}
+
+
+ir_visitor_status
+ir_dead_functions_visitor::visit_enter(ir_function_signature *ir)
+{
+ signature_entry *entry = this->get_signature_entry(ir);
+
+ if (strcmp(ir->function_name(), "main") == 0) {
+ entry->used = true;
+ }
+
+ /* If this is the first signature to look at, no need to descend to see
+ * if it has calls to another function signature.
+ */
+ if (!this->seen_another_function_signature) {
+ this->seen_another_function_signature = true;
+ return visit_continue_with_parent;
+ }
+
+ return visit_continue;
+}
+
+
+ir_visitor_status
+ir_dead_functions_visitor::visit_enter(ir_call *ir)
+{
+ signature_entry *entry = this->get_signature_entry(ir->get_callee());
+
+ entry->used = true;
+
+ return visit_continue;
+}
+
+bool
+do_dead_functions(exec_list *instructions)
+{
+ ir_dead_functions_visitor v;
+ bool progress = false;
+
+ visit_list_elements(&v, instructions);
+
+ /* Now that we've figured out which function signatures are used, remove
+ * the unused ones, and remove function definitions that have no more
+ * signatures.
+ */
+ foreach_iter(exec_list_iterator, iter, v.signature_list) {
+ signature_entry *entry = (signature_entry *)iter.get();
+
+ if (!entry->used) {
+ entry->signature->remove();
+ delete entry->signature;
+ progress = true;
+ }
+ delete(entry);
+ }
+
+ /* We don't just do this above when we nuked a signature because of
+ * const pointers.
+ */
+ foreach_iter(exec_list_iterator, iter, *instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir_function *func = ir->as_function();
+
+ if (func && func->signatures.is_empty()) {
+ /* At this point (post-linking), the symbol table is no
+ * longer in use, so not removing the function from the
+ * symbol table should be OK.
+ */
+ func->remove();
+ delete func;
+ progress = true;
+ }
+ }
+
+ return progress;
+}
diff --git a/mesalib/src/glsl/opt_discard_simplification.cpp b/mesalib/src/glsl/opt_discard_simplification.cpp index df8caba4d..37622eb02 100644 --- a/mesalib/src/glsl/opt_discard_simplification.cpp +++ b/mesalib/src/glsl/opt_discard_simplification.cpp @@ -95,6 +95,7 @@ public: ir_visitor_status visit_enter(ir_if *);
ir_visitor_status visit_enter(ir_loop *);
+ ir_visitor_status visit_enter(ir_assignment *);
bool progress;
};
@@ -117,6 +118,15 @@ is_only_instruction(ir_discard *discard) discard->next->is_tail_sentinel());
}
+/* We only care about the top level instructions, so don't descend
+ * into expressions.
+ */
+ir_visitor_status
+discard_simplifier::visit_enter(ir_assignment *ir)
+{
+ return visit_continue_with_parent;
+}
+
ir_visitor_status
discard_simplifier::visit_enter(ir_if *ir)
{
diff --git a/mesalib/src/glsl/opt_if_simplification.cpp b/mesalib/src/glsl/opt_if_simplification.cpp index ce94f42fe..2d8858e49 100644 --- a/mesalib/src/glsl/opt_if_simplification.cpp +++ b/mesalib/src/glsl/opt_if_simplification.cpp @@ -38,10 +38,20 @@ public: }
ir_visitor_status visit_leave(ir_if *);
+ ir_visitor_status visit_enter(ir_assignment *);
bool made_progress;
};
+/* We only care about the top level "if" instructions, so don't
+ * descend into expressions.
+ */
+ir_visitor_status
+ir_if_simplification_visitor::visit_enter(ir_assignment *ir)
+{
+ return visit_continue_with_parent;
+}
+
bool
do_if_simplification(exec_list *instructions)
{
diff --git a/mesalib/src/glsl/opt_redundant_jumps.cpp b/mesalib/src/glsl/opt_redundant_jumps.cpp index edf4bb6c2..eb60519e2 100644 --- a/mesalib/src/glsl/opt_redundant_jumps.cpp +++ b/mesalib/src/glsl/opt_redundant_jumps.cpp @@ -1,111 +1,120 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file opt_redundant_jumps.cpp - * Remove certain types of redundant jumps - */ - -#include "ir.h" - -class redundant_jumps_visitor : public ir_hierarchical_visitor { -public: - redundant_jumps_visitor() - { - this->progress = false; - } - - virtual ir_visitor_status visit_leave(ir_if *); - virtual ir_visitor_status visit_leave(ir_loop *); - - bool progress; -}; - - -ir_visitor_status -redundant_jumps_visitor::visit_leave(ir_if *ir) -{ - /* If the last instruction in both branches is a 'break' or a 'continue', - * pull it out of the branches and insert it after the if-statment. Note - * that both must be the same type (either 'break' or 'continue'). - */ - ir_instruction *const last_then = - (ir_instruction *) ir->then_instructions.get_tail(); - ir_instruction *const last_else = - (ir_instruction *) ir->else_instructions.get_tail(); - - if ((last_then == NULL) || (last_else == NULL)) - return visit_continue; - - if ((last_then->ir_type != ir_type_loop_jump) - || (last_else->ir_type != ir_type_loop_jump)) - return visit_continue; - - ir_loop_jump *const then_jump = (ir_loop_jump *) last_then; - ir_loop_jump *const else_jump = (ir_loop_jump *) last_else; - - if (then_jump->mode != else_jump->mode) - return visit_continue; - - then_jump->remove(); - else_jump->remove(); - this->progress = true; - - ir->insert_after(then_jump); - - /* If both branchs of the if-statement are now empty, remove the - * if-statement. - */ - if (ir->then_instructions.is_empty() && ir->else_instructions.is_empty()) - ir->remove(); - - return visit_continue; -} - - -ir_visitor_status -redundant_jumps_visitor::visit_leave(ir_loop *ir) -{ - /* If the last instruction of a loop body is a 'continue', remove it. - */ - ir_instruction *const last = - (ir_instruction *) ir->body_instructions.get_tail(); - - if (last && (last->ir_type == ir_type_loop_jump) - && (((ir_loop_jump *) last)->mode == ir_loop_jump::jump_continue)) { - last->remove(); - this->progress = true; - } - - return visit_continue; -} - - -bool -optimize_redundant_jumps(exec_list *instructions) -{ - redundant_jumps_visitor v; - - v.run(instructions); - return v.progress; -} +/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file opt_redundant_jumps.cpp
+ * Remove certain types of redundant jumps
+ */
+
+#include "ir.h"
+
+class redundant_jumps_visitor : public ir_hierarchical_visitor {
+public:
+ redundant_jumps_visitor()
+ {
+ this->progress = false;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_if *);
+ virtual ir_visitor_status visit_leave(ir_loop *);
+ virtual ir_visitor_status visit_enter(ir_assignment *);
+
+ bool progress;
+};
+
+/* We only care about the top level instructions, so don't descend
+ * into expressions.
+ */
+ir_visitor_status
+redundant_jumps_visitor::visit_enter(ir_assignment *ir)
+{
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+redundant_jumps_visitor::visit_leave(ir_if *ir)
+{
+ /* If the last instruction in both branches is a 'break' or a 'continue',
+ * pull it out of the branches and insert it after the if-statment. Note
+ * that both must be the same type (either 'break' or 'continue').
+ */
+ ir_instruction *const last_then =
+ (ir_instruction *) ir->then_instructions.get_tail();
+ ir_instruction *const last_else =
+ (ir_instruction *) ir->else_instructions.get_tail();
+
+ if ((last_then == NULL) || (last_else == NULL))
+ return visit_continue;
+
+ if ((last_then->ir_type != ir_type_loop_jump)
+ || (last_else->ir_type != ir_type_loop_jump))
+ return visit_continue;
+
+ ir_loop_jump *const then_jump = (ir_loop_jump *) last_then;
+ ir_loop_jump *const else_jump = (ir_loop_jump *) last_else;
+
+ if (then_jump->mode != else_jump->mode)
+ return visit_continue;
+
+ then_jump->remove();
+ else_jump->remove();
+ this->progress = true;
+
+ ir->insert_after(then_jump);
+
+ /* If both branchs of the if-statement are now empty, remove the
+ * if-statement.
+ */
+ if (ir->then_instructions.is_empty() && ir->else_instructions.is_empty())
+ ir->remove();
+
+ return visit_continue;
+}
+
+
+ir_visitor_status
+redundant_jumps_visitor::visit_leave(ir_loop *ir)
+{
+ /* If the last instruction of a loop body is a 'continue', remove it.
+ */
+ ir_instruction *const last =
+ (ir_instruction *) ir->body_instructions.get_tail();
+
+ if (last && (last->ir_type == ir_type_loop_jump)
+ && (((ir_loop_jump *) last)->mode == ir_loop_jump::jump_continue)) {
+ last->remove();
+ this->progress = true;
+ }
+
+ return visit_continue;
+}
+
+
+bool
+optimize_redundant_jumps(exec_list *instructions)
+{
+ redundant_jumps_visitor v;
+
+ v.run(instructions);
+ return v.progress;
+}
diff --git a/mesalib/src/glsl/opt_structure_splitting.cpp b/mesalib/src/glsl/opt_structure_splitting.cpp index 014407c0b..d08a5cee1 100644 --- a/mesalib/src/glsl/opt_structure_splitting.cpp +++ b/mesalib/src/glsl/opt_structure_splitting.cpp @@ -1,361 +1,367 @@ -/* - * Copyright © 2010 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file opt_structure_splitting.cpp - * - * If a structure is only ever referenced by its components, then - * split those components out to individual variables so they can be - * handled normally by other optimization passes. - * - * This skips structures like uniforms, which need to be accessible as - * structures for their access by the GL. - */ - -#include "ir.h" -#include "ir_visitor.h" -#include "ir_print_visitor.h" -#include "ir_rvalue_visitor.h" -#include "glsl_types.h" - -static bool debug = false; - -// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined -// function) with the variable_entry class seen in ir_variable_refcount.h -// Perhaps we can use the one in ir_variable_refcount.h and make this class -// here go away? -class variable_entry2 : public exec_node -{ -public: - variable_entry2(ir_variable *var) - { - this->var = var; - this->whole_structure_access = 0; - this->declaration = false; - this->components = NULL; - this->mem_ctx = NULL; - } - - ir_variable *var; /* The key: the variable's pointer. */ - - /** Number of times the variable is referenced, including assignments. */ - unsigned whole_structure_access; - - bool declaration; /* If the variable had a decl in the instruction stream */ - - ir_variable **components; - - /** ralloc_parent(this->var) -- the shader's ralloc context. */ - void *mem_ctx; -}; - - -class ir_structure_reference_visitor : public ir_hierarchical_visitor { -public: - ir_structure_reference_visitor(void) - { - this->mem_ctx = ralloc_context(NULL); - this->variable_list.make_empty(); - } - - ~ir_structure_reference_visitor(void) - { - ralloc_free(mem_ctx); - } - - virtual ir_visitor_status visit(ir_variable *); - virtual ir_visitor_status visit(ir_dereference_variable *); - virtual ir_visitor_status visit_enter(ir_dereference_record *); - virtual ir_visitor_status visit_enter(ir_assignment *); - virtual ir_visitor_status visit_enter(ir_function_signature *); - - variable_entry2 *get_variable_entry2(ir_variable *var); - - /* List of variable_entry */ - exec_list variable_list; - - void *mem_ctx; -}; - -variable_entry2 * -ir_structure_reference_visitor::get_variable_entry2(ir_variable *var) -{ - assert(var); - - if (!var->type->is_record() || var->mode == ir_var_uniform) - return NULL; - - foreach_iter(exec_list_iterator, iter, this->variable_list) { - variable_entry2 *entry = (variable_entry2 *)iter.get(); - if (entry->var == var) - return entry; - } - - variable_entry2 *entry = new(mem_ctx) variable_entry2(var); - this->variable_list.push_tail(entry); - return entry; -} - - -ir_visitor_status -ir_structure_reference_visitor::visit(ir_variable *ir) -{ - variable_entry2 *entry = this->get_variable_entry2(ir); - - if (entry) - entry->declaration = true; - - return visit_continue; -} - -ir_visitor_status -ir_structure_reference_visitor::visit(ir_dereference_variable *ir) -{ - ir_variable *const var = ir->variable_referenced(); - variable_entry2 *entry = this->get_variable_entry2(var); - - if (entry) - entry->whole_structure_access++; - - return visit_continue; -} - -ir_visitor_status -ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir) -{ - (void) ir; - /* Don't descend into the ir_dereference_variable below. */ - return visit_continue_with_parent; -} - -ir_visitor_status -ir_structure_reference_visitor::visit_enter(ir_assignment *ir) -{ - if (ir->lhs->as_dereference_variable() && - ir->rhs->as_dereference_variable() && - !ir->condition) { - /* We'll split copies of a structure to copies of components, so don't - * descend to the ir_dereference_variables. - */ - return visit_continue_with_parent; - } - return visit_continue; -} - -ir_visitor_status -ir_structure_reference_visitor::visit_enter(ir_function_signature *ir) -{ - /* We don't want to descend into the function parameters and - * dead-code eliminate them, so just accept the body here. - */ - visit_list_elements(this, &ir->body); - return visit_continue_with_parent; -} - -class ir_structure_splitting_visitor : public ir_rvalue_visitor { -public: - ir_structure_splitting_visitor(exec_list *vars) - { - this->variable_list = vars; - } - - virtual ~ir_structure_splitting_visitor() - { - } - - virtual ir_visitor_status visit_leave(ir_assignment *); - - void split_deref(ir_dereference **deref); - void handle_rvalue(ir_rvalue **rvalue); - variable_entry2 *get_splitting_entry(ir_variable *var); - - exec_list *variable_list; - void *mem_ctx; -}; - -variable_entry2 * -ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var) -{ - assert(var); - - if (!var->type->is_record()) - return NULL; - - foreach_iter(exec_list_iterator, iter, *this->variable_list) { - variable_entry2 *entry = (variable_entry2 *)iter.get(); - if (entry->var == var) { - return entry; - } - } - - return NULL; -} - -void -ir_structure_splitting_visitor::split_deref(ir_dereference **deref) -{ - if ((*deref)->ir_type != ir_type_dereference_record) - return; - - ir_dereference_record *deref_record = (ir_dereference_record *)*deref; - ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable(); - if (!deref_var) - return; - - variable_entry2 *entry = get_splitting_entry(deref_var->var); - if (!entry) - return; - - unsigned int i; - for (i = 0; i < entry->var->type->length; i++) { - if (strcmp(deref_record->field, - entry->var->type->fields.structure[i].name) == 0) - break; - } - assert(i != entry->var->type->length); - - *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]); -} - -void -ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) -{ - if (!*rvalue) - return; - - ir_dereference *deref = (*rvalue)->as_dereference(); - - if (!deref) - return; - - split_deref(&deref); - *rvalue = deref; -} - -ir_visitor_status -ir_structure_splitting_visitor::visit_leave(ir_assignment *ir) -{ - ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable(); - ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable(); - variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL; - variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL; - const glsl_type *type = ir->rhs->type; - - if ((lhs_entry || rhs_entry) && !ir->condition) { - for (unsigned int i = 0; i < type->length; i++) { - ir_dereference *new_lhs, *new_rhs; - void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx; - - if (lhs_entry) { - new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]); - } else { - new_lhs = new(mem_ctx) - ir_dereference_record(ir->lhs->clone(mem_ctx, NULL), - type->fields.structure[i].name); - } - - if (rhs_entry) { - new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]); - } else { - new_rhs = new(mem_ctx) - ir_dereference_record(ir->rhs->clone(mem_ctx, NULL), - type->fields.structure[i].name); - } - - ir->insert_before(new(mem_ctx) ir_assignment(new_lhs, - new_rhs, - NULL)); - } - ir->remove(); - } else { - handle_rvalue(&ir->rhs); - split_deref(&ir->lhs); - } - - handle_rvalue(&ir->condition); - - return visit_continue; -} - -bool -do_structure_splitting(exec_list *instructions) -{ - ir_structure_reference_visitor refs; - - visit_list_elements(&refs, instructions); - - /* Trim out variables we can't split. */ - foreach_iter(exec_list_iterator, iter, refs.variable_list) { - variable_entry2 *entry = (variable_entry2 *)iter.get(); - - if (debug) { - printf("structure %s@%p: decl %d, whole_access %d\n", - entry->var->name, (void *) entry->var, entry->declaration, - entry->whole_structure_access); - } - - if (!entry->declaration || entry->whole_structure_access) { - entry->remove(); - } - } - - if (refs.variable_list.is_empty()) - return false; - - void *mem_ctx = ralloc_context(NULL); - - /* Replace the decls of the structures to be split with their split - * components. - */ - foreach_iter(exec_list_iterator, iter, refs.variable_list) { - variable_entry2 *entry = (variable_entry2 *)iter.get(); - const struct glsl_type *type = entry->var->type; - - entry->mem_ctx = ralloc_parent(entry->var); - - entry->components = ralloc_array(mem_ctx, - ir_variable *, - type->length); - - for (unsigned int i = 0; i < entry->var->type->length; i++) { - const char *name = ralloc_asprintf(mem_ctx, "%s_%s", - entry->var->name, - type->fields.structure[i].name); - - entry->components[i] = - new(entry->mem_ctx) ir_variable(type->fields.structure[i].type, - name, - ir_var_temporary); - entry->var->insert_before(entry->components[i]); - } - - entry->var->remove(); - } - - ir_structure_splitting_visitor split(&refs.variable_list); - visit_list_elements(&split, instructions); - - ralloc_free(mem_ctx); - - return true; -} +/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file opt_structure_splitting.cpp
+ *
+ * If a structure is only ever referenced by its components, then
+ * split those components out to individual variables so they can be
+ * handled normally by other optimization passes.
+ *
+ * This skips structures like uniforms, which need to be accessible as
+ * structures for their access by the GL.
+ */
+
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_print_visitor.h"
+#include "ir_rvalue_visitor.h"
+#include "glsl_types.h"
+
+static bool debug = false;
+
+// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined
+// function) with the variable_entry class seen in ir_variable_refcount.h
+// Perhaps we can use the one in ir_variable_refcount.h and make this class
+// here go away?
+class variable_entry2 : public exec_node
+{
+public:
+ variable_entry2(ir_variable *var)
+ {
+ this->var = var;
+ this->whole_structure_access = 0;
+ this->declaration = false;
+ this->components = NULL;
+ this->mem_ctx = NULL;
+ }
+
+ ir_variable *var; /* The key: the variable's pointer. */
+
+ /** Number of times the variable is referenced, including assignments. */
+ unsigned whole_structure_access;
+
+ bool declaration; /* If the variable had a decl in the instruction stream */
+
+ ir_variable **components;
+
+ /** ralloc_parent(this->var) -- the shader's ralloc context. */
+ void *mem_ctx;
+};
+
+
+class ir_structure_reference_visitor : public ir_hierarchical_visitor {
+public:
+ ir_structure_reference_visitor(void)
+ {
+ this->mem_ctx = ralloc_context(NULL);
+ this->variable_list.make_empty();
+ }
+
+ ~ir_structure_reference_visitor(void)
+ {
+ ralloc_free(mem_ctx);
+ }
+
+ virtual ir_visitor_status visit(ir_variable *);
+ virtual ir_visitor_status visit(ir_dereference_variable *);
+ virtual ir_visitor_status visit_enter(ir_dereference_record *);
+ virtual ir_visitor_status visit_enter(ir_assignment *);
+ virtual ir_visitor_status visit_enter(ir_function_signature *);
+
+ variable_entry2 *get_variable_entry2(ir_variable *var);
+
+ /* List of variable_entry */
+ exec_list variable_list;
+
+ void *mem_ctx;
+};
+
+variable_entry2 *
+ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
+{
+ assert(var);
+
+ if (!var->type->is_record() || var->mode == ir_var_uniform)
+ return NULL;
+
+ foreach_iter(exec_list_iterator, iter, this->variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+ if (entry->var == var)
+ return entry;
+ }
+
+ variable_entry2 *entry = new(mem_ctx) variable_entry2(var);
+ this->variable_list.push_tail(entry);
+ return entry;
+}
+
+
+ir_visitor_status
+ir_structure_reference_visitor::visit(ir_variable *ir)
+{
+ variable_entry2 *entry = this->get_variable_entry2(ir);
+
+ if (entry)
+ entry->declaration = true;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
+{
+ ir_variable *const var = ir->variable_referenced();
+ variable_entry2 *entry = this->get_variable_entry2(var);
+
+ if (entry)
+ entry->whole_structure_access++;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
+{
+ (void) ir;
+ /* Don't descend into the ir_dereference_variable below. */
+ return visit_continue_with_parent;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
+{
+ /* If there are no structure references yet, no need to bother with
+ * processing the expression tree.
+ */
+ if (this->variable_list.is_empty())
+ return visit_continue_with_parent;
+
+ if (ir->lhs->as_dereference_variable() &&
+ ir->rhs->as_dereference_variable() &&
+ !ir->condition) {
+ /* We'll split copies of a structure to copies of components, so don't
+ * descend to the ir_dereference_variables.
+ */
+ return visit_continue_with_parent;
+ }
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
+{
+ /* We don't want to descend into the function parameters and
+ * dead-code eliminate them, so just accept the body here.
+ */
+ visit_list_elements(this, &ir->body);
+ return visit_continue_with_parent;
+}
+
+class ir_structure_splitting_visitor : public ir_rvalue_visitor {
+public:
+ ir_structure_splitting_visitor(exec_list *vars)
+ {
+ this->variable_list = vars;
+ }
+
+ virtual ~ir_structure_splitting_visitor()
+ {
+ }
+
+ virtual ir_visitor_status visit_leave(ir_assignment *);
+
+ void split_deref(ir_dereference **deref);
+ void handle_rvalue(ir_rvalue **rvalue);
+ variable_entry2 *get_splitting_entry(ir_variable *var);
+
+ exec_list *variable_list;
+ void *mem_ctx;
+};
+
+variable_entry2 *
+ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
+{
+ assert(var);
+
+ if (!var->type->is_record())
+ return NULL;
+
+ foreach_iter(exec_list_iterator, iter, *this->variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+ if (entry->var == var) {
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+void
+ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
+{
+ if ((*deref)->ir_type != ir_type_dereference_record)
+ return;
+
+ ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
+ ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
+ if (!deref_var)
+ return;
+
+ variable_entry2 *entry = get_splitting_entry(deref_var->var);
+ if (!entry)
+ return;
+
+ unsigned int i;
+ for (i = 0; i < entry->var->type->length; i++) {
+ if (strcmp(deref_record->field,
+ entry->var->type->fields.structure[i].name) == 0)
+ break;
+ }
+ assert(i != entry->var->type->length);
+
+ *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
+}
+
+void
+ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (!*rvalue)
+ return;
+
+ ir_dereference *deref = (*rvalue)->as_dereference();
+
+ if (!deref)
+ return;
+
+ split_deref(&deref);
+ *rvalue = deref;
+}
+
+ir_visitor_status
+ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
+{
+ ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
+ ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
+ variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
+ variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
+ const glsl_type *type = ir->rhs->type;
+
+ if ((lhs_entry || rhs_entry) && !ir->condition) {
+ for (unsigned int i = 0; i < type->length; i++) {
+ ir_dereference *new_lhs, *new_rhs;
+ void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
+
+ if (lhs_entry) {
+ new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
+ } else {
+ new_lhs = new(mem_ctx)
+ ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
+ type->fields.structure[i].name);
+ }
+
+ if (rhs_entry) {
+ new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
+ } else {
+ new_rhs = new(mem_ctx)
+ ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
+ type->fields.structure[i].name);
+ }
+
+ ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
+ new_rhs,
+ NULL));
+ }
+ ir->remove();
+ } else {
+ handle_rvalue(&ir->rhs);
+ split_deref(&ir->lhs);
+ }
+
+ handle_rvalue(&ir->condition);
+
+ return visit_continue;
+}
+
+bool
+do_structure_splitting(exec_list *instructions)
+{
+ ir_structure_reference_visitor refs;
+
+ visit_list_elements(&refs, instructions);
+
+ /* Trim out variables we can't split. */
+ foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+
+ if (debug) {
+ printf("structure %s@%p: decl %d, whole_access %d\n",
+ entry->var->name, (void *) entry->var, entry->declaration,
+ entry->whole_structure_access);
+ }
+
+ if (!entry->declaration || entry->whole_structure_access) {
+ entry->remove();
+ }
+ }
+
+ if (refs.variable_list.is_empty())
+ return false;
+
+ void *mem_ctx = ralloc_context(NULL);
+
+ /* Replace the decls of the structures to be split with their split
+ * components.
+ */
+ foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+ variable_entry2 *entry = (variable_entry2 *)iter.get();
+ const struct glsl_type *type = entry->var->type;
+
+ entry->mem_ctx = ralloc_parent(entry->var);
+
+ entry->components = ralloc_array(mem_ctx,
+ ir_variable *,
+ type->length);
+
+ for (unsigned int i = 0; i < entry->var->type->length; i++) {
+ const char *name = ralloc_asprintf(mem_ctx, "%s_%s",
+ entry->var->name,
+ type->fields.structure[i].name);
+
+ entry->components[i] =
+ new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
+ name,
+ ir_var_temporary);
+ entry->var->insert_before(entry->components[i]);
+ }
+
+ entry->var->remove();
+ }
+
+ ir_structure_splitting_visitor split(&refs.variable_list);
+ visit_list_elements(&split, instructions);
+
+ ralloc_free(mem_ctx);
+
+ return true;
+}
|