summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c79
1 files changed, 63 insertions, 16 deletions
diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c
index 49983d6ce75..30716a34843 100644
--- a/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c
+++ b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c
@@ -253,6 +253,25 @@ static int find_class(
return -1;
}
+struct variable_get_class_cb_data {
+ unsigned int * can_change_writemask;
+ unsigned int conversion_swizzle;
+};
+
+static void variable_get_class_read_cb(
+ void * userdata,
+ struct rc_instruction * inst,
+ struct rc_pair_instruction_arg * arg,
+ struct rc_pair_instruction_source * src)
+{
+ struct variable_get_class_cb_data * d = userdata;
+ unsigned int new_swizzle = rc_adjust_channels(arg->Swizzle,
+ d->conversion_swizzle);
+ if (!r300_swizzle_is_native_basic(new_swizzle)) {
+ *d->can_change_writemask = 0;
+ }
+}
+
static enum rc_reg_class variable_get_class(
struct rc_variable * variable,
struct rc_class * classes)
@@ -265,11 +284,14 @@ static enum rc_reg_class variable_get_class(
if (!variable->C->is_r500) {
struct rc_class c;
+ struct rc_variable * var_ptr;
/* The assumption here is that if an instruction has type
* RC_INSTRUCTION_NORMAL then it is a TEX instruction.
* r300 and r400 can't swizzle the result of a TEX lookup. */
- if (variable->Inst->Type == RC_INSTRUCTION_NORMAL) {
- writemask = RC_MASK_XYZW;
+ for (var_ptr = variable; var_ptr; var_ptr = var_ptr->Friend) {
+ if (var_ptr->Inst->Type == RC_INSTRUCTION_NORMAL) {
+ writemask = RC_MASK_XYZW;
+ }
}
/* Check if it is possible to do swizzle packing for r300/r400
@@ -279,24 +301,48 @@ static enum rc_reg_class variable_get_class(
goto error;
}
c = classes[class_index];
+ if (c.WritemaskCount == 1) {
+ goto done;
+ }
for (i = 0; i < c.WritemaskCount; i++) {
- int j;
- unsigned int conversion_swizzle =
+ struct rc_variable * var_ptr;
+ for (var_ptr = variable; var_ptr;
+ var_ptr = var_ptr->Friend) {
+ int j;
+ unsigned int conversion_swizzle =
rc_make_conversion_swizzle(
writemask, c.Writemasks[i]);
- for (j = 0; j < variable->ReaderCount; j++) {
- unsigned int old_swizzle;
- unsigned int new_swizzle;
- struct rc_reader r = variable->Readers[j];
- if (r.Inst->Type == RC_INSTRUCTION_PAIR ) {
- old_swizzle = r.U.P.Arg->Swizzle;
- } else {
- old_swizzle = r.U.I.Src->Swizzle;
+ struct variable_get_class_cb_data d;
+ d.can_change_writemask = &can_change_writemask;
+ d.conversion_swizzle = conversion_swizzle;
+ /* If we get this far var_ptr->Inst has to
+ * be a pair instruction. If variable or any
+ * of its friends are normal instructions,
+ * then the writemask will be set to RC_MASK_XYZW
+ * and the function will return before it gets
+ * here. */
+ rc_pair_for_all_reads_arg(var_ptr->Inst,
+ variable_get_class_read_cb, &d);
+
+ for (j = 0; j < var_ptr->ReaderCount; j++) {
+ unsigned int old_swizzle;
+ unsigned int new_swizzle;
+ struct rc_reader r = var_ptr->Readers[j];
+ if (r.Inst->Type ==
+ RC_INSTRUCTION_PAIR ) {
+ old_swizzle = r.U.P.Arg->Swizzle;
+ } else {
+ old_swizzle = r.U.I.Src->Swizzle;
+ }
+ new_swizzle = rc_adjust_channels(
+ old_swizzle, conversion_swizzle);
+ if (!r300_swizzle_is_native_basic(
+ new_swizzle)) {
+ can_change_writemask = 0;
+ break;
+ }
}
- new_swizzle = rc_adjust_channels(
- old_swizzle, conversion_swizzle);
- if (!r300_swizzle_is_native_basic(new_swizzle)) {
- can_change_writemask = 0;
+ if (!can_change_writemask) {
break;
}
}
@@ -332,6 +378,7 @@ static enum rc_reg_class variable_get_class(
class_index = find_class(classes, writemask,
can_change_writemask ? 3 : 1);
+done:
if (class_index > -1) {
return classes[class_index].Class;
} else {