summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <ian.d.romanick@intel.com>2010-12-07 14:50:34 -0800
committerIan Romanick <ian.d.romanick@intel.com>2010-12-07 15:03:14 -0800
commit6848e27e1462e98dd91826a06f96c203c9eeebd0 (patch)
treea0c4ac86461100065a480de9b25810cff7a686ff
parentb7617346dcff50a66a10c61b95c33682cf629c9e (diff)
i965: Correctly emit constants for aggregate types (array, matrix, struct)
Previously the code only handled scalars and vectors. This new code is modeled somewhat after similar code in ir_to_mesa. Reviewed-by: Eric Anholt <eric@anholt.net>
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs.cpp80
1 files changed, 61 insertions, 19 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
index c775a0488a..a956453dbf 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -1427,28 +1427,70 @@ fs_visitor::visit(ir_discard *ir)
void
fs_visitor::visit(ir_constant *ir)
{
- fs_reg reg(this, ir->type);
- this->result = reg;
+ /* Set this->result to reg at the bottom of the function because some code
+ * paths will cause this visitor to be applied to other fields. This will
+ * cause the value stored in this->result to be modified.
+ *
+ * Make reg constant so that it doesn't get accidentally modified along the
+ * way. Yes, I actually had this problem. :(
+ */
+ const fs_reg reg(this, ir->type);
+ fs_reg dst_reg = reg;
- for (unsigned int i = 0; i < ir->type->vector_elements; i++) {
- switch (ir->type->base_type) {
- case GLSL_TYPE_FLOAT:
- emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.f[i])));
- break;
- case GLSL_TYPE_UINT:
- emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.u[i])));
- break;
- case GLSL_TYPE_INT:
- emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.i[i])));
- break;
- case GLSL_TYPE_BOOL:
- emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg((int)ir->value.b[i])));
- break;
- default:
- assert(!"Non-float/uint/int/bool constant");
+ if (ir->type->is_array()) {
+ const unsigned size = type_size(ir->type->fields.array);
+
+ for (unsigned i = 0; i < ir->type->length; i++) {
+ ir->array_elements[i]->accept(this);
+ fs_reg src_reg = this->result;
+
+ dst_reg.type = src_reg.type;
+ for (unsigned j = 0; j < size; j++) {
+ emit(fs_inst(BRW_OPCODE_MOV, dst_reg, src_reg));
+ src_reg.reg_offset++;
+ dst_reg.reg_offset++;
+ }
+ }
+ } else if (ir->type->is_record()) {
+ foreach_list(node, &ir->components) {
+ ir_instruction *const field = (ir_instruction *) node;
+ const unsigned size = type_size(field->type);
+
+ field->accept(this);
+ fs_reg src_reg = this->result;
+
+ dst_reg.type = src_reg.type;
+ for (unsigned j = 0; j < size; j++) {
+ emit(fs_inst(BRW_OPCODE_MOV, dst_reg, src_reg));
+ src_reg.reg_offset++;
+ dst_reg.reg_offset++;
+ }
+ }
+ } else {
+ const unsigned size = type_size(ir->type);
+
+ for (unsigned i = 0; i < size; i++) {
+ switch (ir->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ emit(fs_inst(BRW_OPCODE_MOV, dst_reg, fs_reg(ir->value.f[i])));
+ break;
+ case GLSL_TYPE_UINT:
+ emit(fs_inst(BRW_OPCODE_MOV, dst_reg, fs_reg(ir->value.u[i])));
+ break;
+ case GLSL_TYPE_INT:
+ emit(fs_inst(BRW_OPCODE_MOV, dst_reg, fs_reg(ir->value.i[i])));
+ break;
+ case GLSL_TYPE_BOOL:
+ emit(fs_inst(BRW_OPCODE_MOV, dst_reg, fs_reg((int)ir->value.b[i])));
+ break;
+ default:
+ assert(!"Non-float/uint/int/bool constant");
+ }
+ dst_reg.reg_offset++;
}
- reg.reg_offset++;
}
+
+ this->result = reg;
}
void