freedreno/ir3: handle half registers for arrays during register allocation.
authorHyunjun Ko <zzoon@igalia.com>
Mon, 18 Nov 2019 09:54:09 +0000 (09:54 +0000)
committerMarge Bot <eric+marge@anholt.net>
Mon, 24 Feb 2020 17:24:13 +0000 (17:24 +0000)
So far we only handle full regs of arrays during pre-allocation.
This patch is to handle half regs of arrays and also consider the size
of half regs when finding out conflicts.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/merge_requests/3822>

src/freedreno/ir3/ir3.h
src/freedreno/ir3/ir3_context.c
src/freedreno/ir3/ir3_ra.c

index fc82932ba22e5da86737a1d83ea5830dfb657754..f927d1ff2045a991e8457c512bc4bb658b2b2870 100644 (file)
@@ -500,6 +500,9 @@ struct ir3_array {
        unsigned base;      /* base vreg name */
        unsigned reg;       /* base physical reg */
        uint16_t start_ip, end_ip;
+
+       /* Indicates if half-precision */
+       bool half;
 };
 
 struct ir3_array * ir3_lookup_array(struct ir3 *ir, unsigned id);
index b44dc4a67f338034041e2a536d02391961ed9c5b..b8ec4a7da447539f955304711c25192f40355369 100644 (file)
@@ -525,6 +525,7 @@ ir3_create_array_load(struct ir3_context *ctx, struct ir3_array *arr, int n,
                mov->cat1.src_type = TYPE_U16;
                mov->cat1.dst_type = TYPE_U16;
                flags |= IR3_REG_HALF;
+               arr->half = true;
        } else {
                mov->cat1.src_type = TYPE_U32;
                mov->cat1.dst_type = TYPE_U32;
index f04db4f29ac1af304fec564414c8f57da04daf08..6d32c0d08e08867c297c713c45891cb6fdd40722 100644 (file)
@@ -366,6 +366,15 @@ is_high(struct ir3_instruction *instr)
        return !!(instr->regs[0]->flags & IR3_REG_HIGH);
 }
 
+static unsigned
+reg_size_for_array(struct ir3_array *arr)
+{
+       if (arr->half)
+               return DIV_ROUND_UP(arr->length, 2);
+
+       return arr->length;
+}
+
 static int
 size_to_class(unsigned sz, bool half, bool high)
 {
@@ -665,8 +674,8 @@ ra_init(struct ir3_ra_ctx *ctx)
        base = ctx->class_base[total_class_count];
        foreach_array (arr, &ctx->ir->array_list) {
                arr->base = base;
-               ctx->class_alloc_count[total_class_count] += arr->length;
-               base += arr->length;
+               ctx->class_alloc_count[total_class_count] += reg_size_for_array(arr);
+               base += reg_size_for_array(arr);
        }
        ctx->alloc_count += ctx->class_alloc_count[total_class_count];
 
@@ -791,7 +800,10 @@ ra_block_compute_live_ranges(struct ir3_ra_ctx *ctx, struct ir3_block *block)
                                 */
                                for (i = 0; i < arr->length; i++) {
                                        unsigned name = arr->base + i;
-                                       ra_set_node_class(ctx->g, name, ctx->set->classes[0]);
+                                       if(arr->half)
+                                               ra_set_node_class(ctx->g, name, ctx->set->half_classes[0]);
+                                       else
+                                               ra_set_node_class(ctx->g, name, ctx->set->classes[0]);
                                }
 
                                /* indirect write is treated like a write to all array
@@ -1333,9 +1345,9 @@ retry:
                        /* if it intersects with liverange AND register range.. */
                        if (intersects(arr->start_ip, arr->end_ip,
                                        arr2->start_ip, arr2->end_ip) &&
-                               intersects(base, base + arr->length,
-                                       arr2->reg, arr2->reg + arr2->length)) {
-                               base = MAX2(base, arr2->reg + arr2->length);
+                               intersects(base, base + reg_size_for_array(arr),
+                                       arr2->reg, arr2->reg + reg_size_for_array(arr2))) {
+                               base = MAX2(base, arr2->reg + reg_size_for_array(arr2));
                                goto retry;
                        }
                }
@@ -1361,7 +1373,7 @@ retry:
                         */
                        if (intersects(arr->start_ip, arr->end_ip,
                                                        ctx->def[name], ctx->use[name]) &&
-                                       intersects(base, base + arr->length,
+                                       intersects(base, base + reg_size_for_array(arr),
                                                        regid, regid + class_sizes[id->cls])) {
                                base = MAX2(base, regid + class_sizes[id->cls]);
                                goto retry;
@@ -1373,9 +1385,22 @@ retry:
                for (unsigned i = 0; i < arr->length; i++) {
                        unsigned name, reg;
 
-                       name = arr->base + i;
-                       reg = ctx->set->gpr_to_ra_reg[0][base++];
+                       if (arr->half) {
+                               /* Doesn't need to do this on older generations than a6xx,
+                                * since there's no conflict between full regs and half regs
+                                * on them.
+                                *
+                                * TODO Presumably "base" could start from 0 respectively
+                                * for half regs of arrays on older generations.
+                                */
+                               unsigned base_half = base * 2 + i;
+                               reg = ctx->set->gpr_to_ra_reg[0+HALF_OFFSET][base_half];
+                               base = base_half / 2 + 1;
+                       } else {
+                               reg = ctx->set->gpr_to_ra_reg[0][base++];
+                       }
 
+                       name = arr->base + i;
                        ra_set_node_reg(ctx->g, name, reg);
                }
        }