[Mesa-dev] [PATCH 1/2] gallium: dereference are now handled by a separate visitor in glsl_to_tgsi
Vincent Lejeune
vljn at ovi.com
Fri Dec 30 08:34:48 PST 2011
v2: fix glsl-fs-uniform-array-4 piglit test
v3: fix glsl-array-bound-02 piglit crash
---
src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 466 ++++++++++++++++++----------
1 files changed, 307 insertions(+), 159 deletions(-)
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 59ecb52..2bfa622 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -293,6 +293,46 @@ public:
void push(class variable_storage *);
};
+/**
+ * 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;
+ ir_rvalue *expr;
+ } indirect_address_expression[8];
+ unsigned indirect_address_expression_count;
+ variable_store &store;
+ int &next_temp;
+ glsl_to_tgsi_dereference_to_address(variable_store&,int&);
+ void* mem_ctx;
+ gl_register_file file;
+
+ 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 *);
+};
+
+
class glsl_to_tgsi_visitor : public ir_visitor {
public:
glsl_to_tgsi_visitor();
@@ -354,6 +394,8 @@ public:
virtual void visit(ir_if *);
/*@}*/
+ void handle_dereference(ir_dereference *);
+
st_src_reg result;
/** List of variable_storage */
@@ -491,6 +533,215 @@ num_inst_src_regs(unsigned opcode)
return info->is_tex ? info->num_src - 1 : info->num_src;
}
+static int
+type_size(const struct glsl_type *type)
+{
+ unsigned int i;
+ int size;
+
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ if (type->is_matrix()) {
+ return type->matrix_columns;
+ } else {
+ /* Regardless of size of vector, it gets a vec4. This is bad
+ * packing for things like floats, but otherwise arrays become a
+ * mess. Hopefully a later pass over the code can pack scalars
+ * down if appropriate.
+ */
+ return 1;
+ }
+ case GLSL_TYPE_ARRAY:
+ assert(type->length > 0);
+ return type_size(type->fields.array) * type->length;
+ case GLSL_TYPE_STRUCT:
+ size = 0;
+ for (i = 0; i < type->length; i++) {
+ size += type_size(type->fields.structure[i].type);
+ }
+ return size;
+ case GLSL_TYPE_SAMPLER:
+ /* Samplers take up one slot in UNIFORMS[], but they're baked in
+ * at link time.
+ */
+ return 1;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+glsl_to_tgsi_dereference_to_address::glsl_to_tgsi_dereference_to_address(variable_store &s, int &t):possible_constant(0),indirect_address_expression_count(0),store(s),next_temp(t)
+{
+
+}
+
+void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_variable *ir)
+{
+ variable_storage *entry = store.find_variable_storage(ir->var);
+ ir_variable *var = ir->var;
+
+ if (!entry) {
+ switch (var->mode) {
+ case ir_var_uniform:
+ entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
+ var->location);
+ store.push(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);
+ store.push(entry);
+
+ next_temp += type_size(var->type);
+ break;
+ }
+
+ if (!entry) {
+ printf("Failed to make storage for %s\n", var->name);
+ exit(1);
+ }
+ }
+ offset = entry->index;
+ file = entry->file;
+ return;
+}
+
+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;
+ 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);
+}
+
glsl_to_tgsi_instruction *
glsl_to_tgsi_visitor::emit(ir_instruction *ir, unsigned op,
st_dst_reg dst,
@@ -931,46 +1182,7 @@ glsl_to_tgsi_visitor::st_src_reg_for_type(int type, int val)
return st_src_reg_for_float(val);
}
-static int
-type_size(const struct glsl_type *type)
-{
- unsigned int i;
- int size;
- switch (type->base_type) {
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_BOOL:
- if (type->is_matrix()) {
- return type->matrix_columns;
- } else {
- /* Regardless of size of vector, it gets a vec4. This is bad
- * packing for things like floats, but otherwise arrays become a
- * mess. Hopefully a later pass over the code can pack scalars
- * down if appropriate.
- */
- return 1;
- }
- case GLSL_TYPE_ARRAY:
- assert(type->length > 0);
- return type_size(type->fields.array) * type->length;
- case GLSL_TYPE_STRUCT:
- size = 0;
- for (i = 0; i < type->length; i++) {
- size += type_size(type->fields.structure[i].type);
- }
- return size;
- case GLSL_TYPE_SAMPLER:
- /* Samplers take up one slot in UNIFORMS[], but they're baked in
- * at link time.
- */
- return 1;
- default:
- assert(0);
- return 0;
- }
-}
/**
* In the initial pass of codegen, we assign temporary numbers to
@@ -1902,145 +2114,81 @@ 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 = store.find_variable_storage(ir->var);
- ir_variable *var = ir->var;
-
- if (!entry) {
- switch (var->mode) {
- case ir_var_uniform:
- entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
- var->location);
- store.push(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);
- store.push(entry);
-
- next_temp += type_size(var->type);
- break;
- }
+ glsl_to_tgsi_dereference_to_address secondary_visitor(store,next_temp);
+ secondary_visitor.mem_ctx = mem_ctx;
+ ir->accept(&secondary_visitor);
- if (!entry) {
- printf("Failed to make storage for %s\n", var->name);
- exit(1);
- }
+ st_src_reg result;
+ if (secondary_visitor.possible_constant) {
+ secondary_visitor.possible_constant->accept(this);
+ result = this->result;
+ result.index += secondary_visitor.offset;
+ }
+ else {
+ result = st_src_reg(secondary_visitor.file,secondary_visitor.offset,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);
-
- 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 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);
+ if (secondary_visitor.indirect_address_expression_count > 0) {
+ 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;
+ st_src_reg index_reg;
- 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 = 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);
+ }
+ }
+ result.reladdr = ralloc(mem_ctx, st_src_reg);
+ memcpy(result.reladdr, &index_reg, sizeof(index_reg));
}
-
- src.reladdr = ralloc(mem_ctx, st_src_reg);
- memcpy(src.reladdr, &index_reg, sizeof(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