From 5a7758efbe14dee026245a4f4f4fb3ccf7b2c23b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 2 Aug 2010 18:48:25 -0700 Subject: glsl2: Add ir_assignment::write_mask and associated methods Replace swizzles on the LHS with additional swizzles on the RHS and a write mask in the assignment instruction. As part of this add ir_assignment::set_lhs. Ideally we'd make ir_assignment::lhs private to prevent erroneous writes, but that would require a lot of code butchery at this point. Add ir_assignment constructor that takes an explicit write mask. This is required for ir_assignment::clone, but it can also be used in other places. Without this, ir_assignment clones lose their write masks, and incorrect IR is generated in optimization passes. Add ir_assignment::whole_variable_written method. This method gets the variable on the LHS if the whole variable is written or NULL otherwise. This is different from ir->lhs->whole_variable_referenced() because the latter has no knowledge of the write mask stored in the ir_assignment. Gut all code from ir_to_mesa that handled swizzles on the LHS of assignments. There is probably some other refactoring that could be done here, but that can be left for another day. --- src/glsl/ir.cpp | 113 ++++++++++++++++++++++++++++++++++- src/glsl/ir.h | 44 +++++++++++++- src/glsl/ir_clone.cpp | 3 +- src/glsl/ir_constant_variable.cpp | 2 +- src/glsl/ir_copy_propagation.cpp | 2 +- src/glsl/ir_dead_code_local.cpp | 2 +- src/glsl/ir_print_visitor.cpp | 14 ++++- src/glsl/ir_tree_grafting.cpp | 2 +- src/glsl/ir_vec_index_to_swizzle.cpp | 2 +- 9 files changed, 174 insertions(+), 10 deletions(-) (limited to 'src/glsl') diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 79cbaa9ea0..c3bade8d54 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -22,6 +22,7 @@ */ #include #include "main/imports.h" +#include "main/macros.h" #include "ir.h" #include "ir_visitor.h" #include "glsl_types.h" @@ -31,13 +32,121 @@ ir_rvalue::ir_rvalue() this->type = glsl_type::error_type; } +/** + * 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) +{ + 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(this) 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; +} + ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, ir_rvalue *condition) { this->ir_type = ir_type_assignment; - this->lhs = lhs; - this->rhs = rhs; 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); } diff --git a/src/glsl/ir.h b/src/glsl/ir.h index f964b36083..98789503e0 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -514,6 +514,16 @@ 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(); @@ -530,10 +540,32 @@ public: 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_rvalue *lhs; + ir_dereference *lhs; /** * Value being assigned @@ -544,6 +576,16 @@ public: * 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. + */ + unsigned write_mask:4; }; /* Update ir_expression::num_operands() and operator_strs when diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index 59831834bd..0e202164b3 100644 --- a/src/glsl/ir_clone.cpp +++ b/src/glsl/ir_clone.cpp @@ -242,7 +242,8 @@ ir_assignment::clone(void *mem_ctx, struct hash_table *ht) const return new(mem_ctx) ir_assignment(this->lhs->clone(mem_ctx, ht), this->rhs->clone(mem_ctx, ht), - new_condition); + new_condition, + this->write_mask); } ir_function * diff --git a/src/glsl/ir_constant_variable.cpp b/src/glsl/ir_constant_variable.cpp index 749e2cf809..1fb73e765e 100644 --- a/src/glsl/ir_constant_variable.cpp +++ b/src/glsl/ir_constant_variable.cpp @@ -110,7 +110,7 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir) return visit_continue; } - ir_variable *var = ir->lhs->whole_variable_referenced(); + ir_variable *var = ir->whole_variable_written(); if (!var) return visit_continue; diff --git a/src/glsl/ir_copy_propagation.cpp b/src/glsl/ir_copy_propagation.cpp index 5712398732..26588a352c 100644 --- a/src/glsl/ir_copy_propagation.cpp +++ b/src/glsl/ir_copy_propagation.cpp @@ -224,7 +224,7 @@ add_copy(void *ctx, ir_assignment *ir, exec_list *acp) return; } - ir_variable *lhs_var = ir->lhs->whole_variable_referenced(); + ir_variable *lhs_var = ir->whole_variable_written(); ir_variable *rhs_var = ir->rhs->whole_variable_referenced(); if ((lhs_var != NULL) && (rhs_var != NULL)) { diff --git a/src/glsl/ir_dead_code_local.cpp b/src/glsl/ir_dead_code_local.cpp index 7a44ec8a4a..b22cc558df 100644 --- a/src/glsl/ir_dead_code_local.cpp +++ b/src/glsl/ir_dead_code_local.cpp @@ -137,7 +137,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments) } /* Now, check if we did a whole-variable assignment. */ - if (always_assign && (ir->lhs->whole_variable_referenced() != NULL)) { + if (always_assign && (ir->whole_variable_written() != NULL)) { /* We did a whole-variable assignment. So, any instruction in * the assignment list with the same LHS is dead. */ diff --git a/src/glsl/ir_print_visitor.cpp b/src/glsl/ir_print_visitor.cpp index 73476e7e9b..39b11bb32c 100644 --- a/src/glsl/ir_print_visitor.cpp +++ b/src/glsl/ir_print_visitor.cpp @@ -296,7 +296,19 @@ void ir_print_visitor::visit(ir_assignment *ir) else printf("(constant bool (1))"); - printf(" "); + + 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); diff --git a/src/glsl/ir_tree_grafting.cpp b/src/glsl/ir_tree_grafting.cpp index 6f62de758b..38034a6197 100644 --- a/src/glsl/ir_tree_grafting.cpp +++ b/src/glsl/ir_tree_grafting.cpp @@ -315,7 +315,7 @@ tree_grafting_basic_block(ir_instruction *bb_first, if (!assign) continue; - ir_variable *lhs_var = assign->lhs->whole_variable_referenced(); + ir_variable *lhs_var = assign->whole_variable_written(); if (!lhs_var) continue; diff --git a/src/glsl/ir_vec_index_to_swizzle.cpp b/src/glsl/ir_vec_index_to_swizzle.cpp index 1e170cbae6..b3de91f8ab 100644 --- a/src/glsl/ir_vec_index_to_swizzle.cpp +++ b/src/glsl/ir_vec_index_to_swizzle.cpp @@ -107,7 +107,7 @@ ir_vec_index_to_swizzle_visitor::visit_enter(ir_swizzle *ir) ir_visitor_status ir_vec_index_to_swizzle_visitor::visit_enter(ir_assignment *ir) { - ir->lhs = convert_vec_index_to_swizzle(ir->lhs); + ir->set_lhs(convert_vec_index_to_swizzle(ir->lhs)); ir->rhs = convert_vec_index_to_swizzle(ir->rhs); return visit_continue; -- cgit v1.2.3