lima/ppir: improve regalloc spill cost calculation
authorErico Nunes <nunes.erico@gmail.com>
Tue, 27 Aug 2019 23:09:12 +0000 (01:09 +0200)
committerErico Nunes <nunes.erico@gmail.com>
Thu, 5 Sep 2019 23:29:24 +0000 (23:29 +0000)
Now that spilling ops can be inserted into existing instructions, it
makes sense to increase cost to spill registers that would cause the
creation of a new instruction.
Experimental results showed that penalizing too much due to this caused
worse results, however it is beneficial as a tie resolver between
registers with the same number of components.

Signed-off-by: Erico Nunes <nunes.erico@gmail.com>
Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
src/gallium/drivers/lima/ir/pp/regalloc.c

index 70a178deff85a870e42010cfae84062c397c61ce..c7012294178e901e17289f58149031812cb4e8d4 100644 (file)
@@ -479,27 +479,71 @@ static bool ppir_regalloc_spill_reg(ppir_compiler *comp, ppir_reg *chosen)
 static ppir_reg *ppir_regalloc_choose_spill_node(ppir_compiler *comp,
                                                  struct ra_graph *g)
 {
-   int i = 0;
-   ppir_reg *chosen = NULL;
+   float spill_costs[list_length(&comp->reg_list)];
+   /* experimentally determined, it seems to be worth scaling cost of
+    * regs in instructions that have used uniform/store_temp slots,
+    * but not too much as to offset the num_components base cost. */
+   const float slot_scale = 1.1f;
 
    list_for_each_entry(ppir_reg, reg, &comp->reg_list, list) {
       if (reg->spilled || reg->live_out == INT_MAX) {
          /* not considered for spilling */
-         ra_set_node_spill_cost(g, i++, 0.0f);
+         spill_costs[reg->regalloc_index] = 0.0f;
          continue;
       }
 
       /* It is beneficial to spill registers with higher component number,
        * so increase the cost of spilling registers with few components */
       float spill_cost = 4.0f / (float)reg->num_components;
-      ra_set_node_spill_cost(g, i++, spill_cost);
+      spill_costs[reg->regalloc_index] = spill_cost;
    }
 
+   list_for_each_entry(ppir_block, block, &comp->block_list, list) {
+      list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
+         if (instr->slots[PPIR_INSTR_SLOT_UNIFORM]) {
+            for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) {
+               ppir_node *node = instr->slots[i];
+               if (!node)
+                  continue;
+               for (int j = 0; j < ppir_node_get_src_num(node); j++) {
+                  ppir_src *src = ppir_node_get_src(node, j);
+                  if (!src)
+                     continue;
+                  ppir_reg *reg = ppir_src_get_reg(src);
+                  if (!reg)
+                     continue;
+
+                  spill_costs[reg->regalloc_index] *= slot_scale;
+               }
+            }
+         }
+         if (instr->slots[PPIR_INSTR_SLOT_STORE_TEMP]) {
+            for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) {
+               ppir_node *node = instr->slots[i];
+               if (!node)
+                  continue;
+               ppir_dest *dest = ppir_node_get_dest(node);
+               if (!dest)
+                  continue;
+               ppir_reg *reg = ppir_dest_get_reg(dest);
+               if (!reg)
+                  continue;
+
+               spill_costs[reg->regalloc_index] *= slot_scale;
+            }
+         }
+      }
+   }
+
+   for (int i = 0; i < list_length(&comp->reg_list); i++)
+      ra_set_node_spill_cost(g, i, spill_costs[i]);
+
    int r = ra_get_best_spill_node(g);
    if (r == -1)
       return NULL;
 
-   i = 0;
+   ppir_reg *chosen = NULL;
+   int i = 0;
    list_for_each_entry(ppir_reg, reg, &comp->reg_list, list) {
       if (i++ == r) {
          chosen = reg;