[Mesa-dev] [PATCH 2/3] glsl_to_tgsi: Use a separate visitor to handle dereferences.
Vincent Lejeune
vljn at ovi.com
Sat Jan 7 14:06:01 PST 2012
---
src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 375 +++++++++++++++++++---------
1 files changed, 262 insertions(+), 113 deletions(-)
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 2825180..ab93a65 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -526,6 +526,205 @@ variable_store::optimise_access(void)
reindex_rvalue();
}
+/**
+ * This visitor will retrieve offset and expression of indirect addressing
+ * from any ir_dereference*
+ */
+class glsl_to_tgsi_dereference_to_address : public ir_visitor {
+public:
+ ir_constant *possible_constant;
+ unsigned offset;
+ struct {
+ unsigned stride;
+ unsigned max_index;
+ ir_rvalue *expr;
+ } indirect_address_expression[8];
+ unsigned indirect_address_expression_count;
+ variable_store &store;
+ glsl_to_tgsi_dereference_to_address(variable_store&);
+ void* mem_ctx;
+ variable_storage *entry;
+
+ void visit(class ir_dereference_variable *);
+ void visit(class ir_dereference_array *);
+ void visit(class ir_dereference_record *);
+ void visit(class ir_constant *);
+
+ void visit(ir_variable *);
+ void visit(ir_function_signature *);
+ void visit(ir_function *);
+ void visit(ir_expression *);
+ void visit(ir_texture *);
+ void visit(ir_swizzle *);
+ void visit(ir_assignment *);
+ void visit(ir_call *);
+ void visit(ir_discard *);
+ void visit(ir_if *);
+ void visit(ir_loop *);
+ void visit(ir_loop_jump *);
+ void visit(ir_return *);
+};
+
+glsl_to_tgsi_dereference_to_address::glsl_to_tgsi_dereference_to_address(variable_store &s):possible_constant(NULL), indirect_address_expression_count(0), store(s), entry(NULL)
+{
+
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_variable *ir)
+{
+ entry = store.find_variable_storage(ir->var);
+ ir_variable *var = ir->var;
+
+ if (!entry) {
+ switch (var->mode) {
+ case ir_var_uniform:
+ entry = store.push(var, PROGRAM_UNIFORM, var->location);
+ break;
+ case ir_var_in:
+ case ir_var_inout:
+ /* The linker assigns locations for varyings and attributes,
+ * including deprecated builtins (like gl_Color), user-assign
+ * generic attributes (glBindVertexLocation), and
+ * user-defined varyings.
+ *
+ * FINISHME: We would hit this path for function arguments. Fix!
+ */
+ assert(var->location != -1);
+ entry = store.push(var, PROGRAM_INPUT, var->location);
+ break;
+ case ir_var_out:
+ entry = store.push(var, PROGRAM_OUTPUT, var->location);
+ break;
+ case ir_var_system_value:
+ entry = store.push(var, PROGRAM_SYSTEM_VALUE, var->location);
+ break;
+ case ir_var_auto:
+ case ir_var_temporary:
+ entry = store.push(var);
+ break;
+ }
+ }
+
+ if (!entry) {
+ printf("Failed to make storage for %s\n", var->name);
+ exit(1);
+ }
+
+ offset = 0;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_constant *ir)
+{
+ possible_constant = ir;
+ offset = 0;
+ return;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_record *ir)
+{
+ unsigned int i;
+ const glsl_type *struct_type = ir->record->type;
+ ir->record->accept(this);
+
+ for (i = 0; i < struct_type->length; i++) {
+ if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
+ break;
+ offset += type_size(struct_type->fields.structure[i].type);
+ }
+ return;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_array *ir)
+{
+ ir_constant *index;
+ int element_size = type_size(ir->type);
+ ir->array->accept(this);
+
+ index = ir->array_index->constant_expression_value();
+
+ if (index) {
+ offset += index->value.i[0] * element_size;
+ } else {
+ indirect_address_expression[indirect_address_expression_count].expr = ir->array_index;
+ indirect_address_expression[indirect_address_expression_count].stride = element_size;
+ if (ir->array->type->is_array()) {
+ indirect_address_expression[indirect_address_expression_count].max_index = ir->array->type->length;
+ }
+ else if (ir->array->type->is_matrix()) {
+ indirect_address_expression[indirect_address_expression_count].max_index = ir->array->type->components();
+ }
+
+ indirect_address_expression_count++;
+ }
+ return;
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_function *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_if *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_variable *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_discard *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_function_signature *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_expression *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_call *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_texture *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_loop *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_return *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_loop_jump *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_assignment *)
+{
+ assert(0);
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_swizzle *)
+{
+ assert(0);
+}
+
+
class glsl_to_tgsi_visitor : public ir_visitor {
public:
glsl_to_tgsi_visitor();
@@ -584,6 +783,8 @@ public:
virtual void visit(ir_if *);
/*@}*/
+ void handle_dereference(ir_dereference *);
+
st_src_reg result;
/** List of variable_storage */
@@ -2084,145 +2285,93 @@ glsl_to_tgsi_visitor::visit(ir_swizzle *ir)
}
void
-glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir)
+glsl_to_tgsi_visitor::handle_dereference(ir_dereference *ir)
{
- variable_storage *entry = find_variable_storage(ir->var);
- ir_variable *var = ir->var;
+ glsl_to_tgsi_dereference_to_address secondary_visitor(store);
+ secondary_visitor.mem_ctx = mem_ctx;
+ ir->accept(&secondary_visitor);
- if (!entry) {
- switch (var->mode) {
- case ir_var_uniform:
- entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
- var->location);
- this->variables.push_tail(entry);
- break;
- case ir_var_in:
- case ir_var_inout:
- /* The linker assigns locations for varyings and attributes,
- * including deprecated builtins (like gl_Color), user-assign
- * generic attributes (glBindVertexLocation), and
- * user-defined varyings.
- *
- * FINISHME: We would hit this path for function arguments. Fix!
- */
- assert(var->location != -1);
- entry = new(mem_ctx) variable_storage(var,
- PROGRAM_INPUT,
- var->location);
- break;
- case ir_var_out:
- assert(var->location != -1);
- entry = new(mem_ctx) variable_storage(var,
- PROGRAM_OUTPUT,
- var->location);
- break;
- case ir_var_system_value:
- entry = new(mem_ctx) variable_storage(var,
- PROGRAM_SYSTEM_VALUE,
- var->location);
- break;
- case ir_var_auto:
- case ir_var_temporary:
- entry = new(mem_ctx) variable_storage(var, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variables.push_tail(entry);
-
- next_temp += type_size(var->type);
- break;
- }
+ st_src_reg result;
+ if (secondary_visitor.possible_constant) {
+ secondary_visitor.possible_constant->accept(this);
+ result = this->result;
- if (!entry) {
- printf("Failed to make storage for %s\n", var->name);
- exit(1);
- }
+ }
+ else {
+ variable_storage *entry = secondary_visitor.entry;
+ result = st_src_reg(entry->file, entry->index, ir->type);
}
- this->result = st_src_reg(entry->file, entry->index, var->type);
- if (!native_integers)
- this->result.type = GLSL_TYPE_FLOAT;
-}
-
-void
-glsl_to_tgsi_visitor::visit(ir_dereference_array *ir)
-{
- ir_constant *index;
- st_src_reg src;
- int element_size = type_size(ir->type);
-
- index = ir->array_index->constant_expression_value();
-
- ir->array->accept(this);
- src = this->result;
-
- if (index) {
- src.index += index->value.i[0] * element_size;
- } else {
- /* Variable index array dereference. It eats the "vec4" of the
- * base of the array and an index that offsets the TGSI register
- * index.
- */
- ir->array_index->accept(this);
+ result.index += secondary_visitor.offset;
+ if (secondary_visitor.indirect_address_expression_count > 0) {
st_src_reg index_reg;
- if (element_size == 1) {
- index_reg = this->result;
- } else {
- index_reg = get_temp(native_integers ?
- glsl_type::int_type : glsl_type::float_type);
-
- emit(ir, TGSI_OPCODE_MUL, st_dst_reg(index_reg),
- this->result, st_src_reg_for_type(index_reg.type, element_size));
+ if(secondary_visitor.entry)
+ secondary_visitor.entry->is_reladdressed = true;
+ else {
+ /* This is an ugly hack that should be properly handled when variable_store will also store immediates*/
+ store.retrieve_anonymous_temp(result.index)->is_reladdressed = true;
}
- /* If there was already a relative address register involved, add the
- * new and the old together to get the new offset.
- */
- if (src.reladdr != NULL) {
- st_src_reg accum_reg = get_temp(native_integers ?
- glsl_type::int_type : glsl_type::float_type);
+ for (unsigned i = 0; i < secondary_visitor.indirect_address_expression_count; i++) {
+ secondary_visitor.indirect_address_expression[i].expr->accept(this);
+ unsigned element_size = secondary_visitor.indirect_address_expression[i].stride;
- emit(ir, TGSI_OPCODE_ADD, st_dst_reg(accum_reg),
- index_reg, *src.reladdr);
+ if (i == 0) {
+ if (element_size == 1) {
+ index_reg = this->result;
+ } else {
+ index_reg = store.get_temp(native_integers ?
+ glsl_type::int_type : glsl_type::float_type);
- index_reg = accum_reg;
+ emit(ir, TGSI_OPCODE_MUL, st_dst_reg(index_reg),
+ this->result, st_src_reg_for_type(index_reg.type, element_size));
+ }
+ }
+ else {
+ if (element_size == 1) {
+ emit(ir, TGSI_OPCODE_ADD, st_dst_reg(index_reg),
+ index_reg, this->result);
+ }
+ else {
+ emit(ir, TGSI_OPCODE_UMAD, st_dst_reg(index_reg),
+ this->result, st_src_reg_for_type(index_reg.type, element_size), index_reg);
+ }
+ }
}
- src.reladdr = ralloc(mem_ctx, st_src_reg);
- memcpy(src.reladdr, &index_reg, sizeof(index_reg));
+ result.reladdr = ralloc(mem_ctx, st_src_reg);
+ *(result.reladdr) = st_src_reg(index_reg);
}
+ this->result = result;
/* If the type is smaller than a vec4, replicate the last channel out. */
if (ir->type->is_scalar() || ir->type->is_vector())
- src.swizzle = swizzle_for_size(ir->type->vector_elements);
+ this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
else
- src.swizzle = SWIZZLE_NOOP;
+ this->result.swizzle = SWIZZLE_NOOP;
- this->result = src;
+ if (!native_integers)
+ this->result.type = GLSL_TYPE_FLOAT;
}
void
-glsl_to_tgsi_visitor::visit(ir_dereference_record *ir)
+glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir)
{
- unsigned int i;
- const glsl_type *struct_type = ir->record->type;
- int offset = 0;
-
- ir->record->accept(this);
-
- for (i = 0; i < struct_type->length; i++) {
- if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
- break;
- offset += type_size(struct_type->fields.structure[i].type);
- }
+ handle_dereference(ir);
+}
- /* If the type is smaller than a vec4, replicate the last channel out. */
- if (ir->type->is_scalar() || ir->type->is_vector())
- this->result.swizzle = swizzle_for_size(ir->type->vector_elements);
- else
- this->result.swizzle = SWIZZLE_NOOP;
+void
+glsl_to_tgsi_visitor::visit(ir_dereference_array *ir)
+{
+ handle_dereference(ir);
+}
- this->result.index += offset;
+void
+glsl_to_tgsi_visitor::visit(ir_dereference_record *ir)
+{
+ handle_dereference(ir);
}
/**
--
1.7.7
More information about the mesa-dev
mailing list