i965/vec4: support basic spilling of 64-bit registers
[mesa.git] / src / mesa / drivers / dri / i965 / brw_vec4_reg_allocate.cpp
index afc326612a2812f3ff0b667a356788e6fcdab48a..242e6664623b15a148151e2ee2247d3f3fc8de2f 100644 (file)
@@ -33,8 +33,8 @@ static void
 assign(unsigned int *reg_hw_locations, backend_reg *reg)
 {
    if (reg->file == VGRF) {
-      reg->nr = reg_hw_locations[reg->nr] + reg->reg_offset;
-      reg->reg_offset = 0;
+      reg->nr = reg_hw_locations[reg->nr] + reg->offset / REG_SIZE;
+      reg->offset %= REG_SIZE;
    }
 }
 
@@ -376,7 +376,7 @@ vec4_visitor::evaluate_spill_costs(float *spill_costs, bool *no_spill)
 
    for (unsigned i = 0; i < this->alloc.count; i++) {
       spill_costs[i] = 0.0;
-      no_spill[i] = alloc.sizes[i] != 1;
+      no_spill[i] = alloc.sizes[i] != 1 && alloc.sizes[i] != 2;
    }
 
    /* Calculate costs for spilling nodes.  Call it a cost of 1 per
@@ -385,22 +385,42 @@ vec4_visitor::evaluate_spill_costs(float *spill_costs, bool *no_spill)
     */
    foreach_block_and_inst(block, vec4_instruction, inst, cfg) {
       for (unsigned int i = 0; i < 3; i++) {
-         if (inst->src[i].file == VGRF) {
+         if (inst->src[i].file == VGRF && !no_spill[inst->src[i].nr]) {
             /* We will only unspill src[i] it it wasn't unspilled for the
              * previous instruction, in which case we'll just reuse the scratch
              * reg for this instruction.
              */
             if (!can_use_scratch_for_source(inst, i, inst->src[i].nr)) {
                spill_costs[inst->src[i].nr] += loop_scale;
-               if (inst->src[i].reladdr)
+               if (inst->src[i].reladdr ||
+                   inst->src[i].offset >= REG_SIZE)
+                  no_spill[inst->src[i].nr] = true;
+
+               /* We don't support unspills of partial DF reads.
+                *
+                * Our 64-bit unspills are implemented with two 32-bit scratch
+                * messages, each one reading that for both SIMD4x2 threads that
+                * we need to shuffle into correct 64-bit data. Ensure that we
+                * are reading data for both threads.
+                */
+               if (type_sz(inst->src[i].type) == 8 && inst->exec_size != 8)
                   no_spill[inst->src[i].nr] = true;
             }
          }
       }
 
-      if (inst->dst.file == VGRF) {
+      if (inst->dst.file == VGRF && !no_spill[inst->dst.nr]) {
          spill_costs[inst->dst.nr] += loop_scale;
-         if (inst->dst.reladdr)
+         if (inst->dst.reladdr || inst->dst.offset >= REG_SIZE)
+            no_spill[inst->dst.nr] = true;
+
+         /* We don't support spills of partial DF writes.
+          *
+          * Our 64-bit spills are implemented with two 32-bit scratch messages,
+          * each one writing that for both SIMD4x2 threads. Ensure that we
+          * are writing data for both threads.
+          */
+         if (type_sz(inst->dst.type) == 8 && inst->exec_size != 8)
             no_spill[inst->dst.nr] = true;
       }
 
@@ -449,8 +469,9 @@ vec4_visitor::choose_spill_reg(struct ra_graph *g)
 void
 vec4_visitor::spill_reg(int spill_reg_nr)
 {
-   assert(alloc.sizes[spill_reg_nr] == 1);
-   unsigned int spill_offset = last_scratch++;
+   assert(alloc.sizes[spill_reg_nr] == 1 || alloc.sizes[spill_reg_nr] == 2);
+   unsigned int spill_offset = last_scratch;
+   last_scratch += alloc.sizes[spill_reg_nr];
 
    /* Generate spill/unspill instructions for the objects being spilled. */
    int scratch_reg = -1;
@@ -464,12 +485,14 @@ vec4_visitor::spill_reg(int spill_reg_nr)
                 * for consecutive instructions that read different channels of
                 * the same vec4.
                 */
-               scratch_reg = alloc.allocate(1);
+               scratch_reg = alloc.allocate(alloc.sizes[spill_reg_nr]);
                src_reg temp = inst->src[i];
                temp.nr = scratch_reg;
+               temp.offset = 0;
                temp.swizzle = BRW_SWIZZLE_XYZW;
                emit_scratch_read(block, inst,
                                  dst_reg(temp), inst->src[i], spill_offset);
+               temp.offset = inst->src[i].offset;
             }
             assert(scratch_reg != -1);
             inst->src[i].nr = scratch_reg;