aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/SConscript9
-rw-r--r--mesalib/src/glsl/ir.cpp3148
-rw-r--r--mesalib/src/glsl/ir.h3280
-rw-r--r--mesalib/src/glsl/ir_print_visitor.cpp945
-rw-r--r--mesalib/src/glsl/ir_reader.cpp2001
-rw-r--r--mesalib/src/glsl/opt_dead_functions.cpp317
-rw-r--r--mesalib/src/glsl/opt_discard_simplification.cpp10
-rw-r--r--mesalib/src/glsl/opt_if_simplification.cpp10
-rw-r--r--mesalib/src/glsl/opt_redundant_jumps.cpp231
-rw-r--r--mesalib/src/glsl/opt_structure_splitting.cpp728
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(&parameters);
-}
-
-
-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(&parameters);
+}
+
+
+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(&parameters);
- 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, &parameters);
-}
-
-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(&parameters);
+ 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, &parameters);
+}
+
+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;
+}