r300/compiler: Prevent regalloc from creating non-native swizzles
authorTom Stellard <tstellar@gmail.com>
Sat, 14 May 2011 07:48:57 +0000 (00:48 -0700)
committerTom Stellard <tstellar@gmail.com>
Sat, 15 Oct 2011 01:30:14 +0000 (18:30 -0700)
src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c

index 49983d6ce75d58bb252a025f9c5349f3f5206b34..30716a3484307aeadb473cf10887207abbda968d 100644 (file)
@@ -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 {