[Mesa-dev] [PATCH v2 5/6] i965/vec4: Adjust spilling cost for consecutive instructions

Francisco Jerez currojerez at riseup.net
Thu Jul 30 06:33:05 PDT 2015


Francisco Jerez <currojerez at riseup.net> writes:

> Iago Toral Quiroga <itoral at igalia.com> writes:
>
>> Previous patches made it so that we do not need to unspill the same vgrf
>> with every instruction as long as these instructions come right after
>> the register was spilled or unspilled. This means that actually spilling
>> the register is now cheaper in these scenarios, so adjust the spilling
>> cost calculation accordingly.
>> ---
>>  .../drivers/dri/i965/brw_vec4_reg_allocate.cpp     | 61 +++++++++++++++++++---
>>  1 file changed, 55 insertions(+), 6 deletions(-)
>>
>> diff --git a/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp b/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
>> index 9a69fac..652a68c 100644
>> --- a/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
>> +++ b/src/mesa/drivers/dri/i965/brw_vec4_reg_allocate.cpp
>> @@ -269,6 +269,21 @@ vec4_visitor::evaluate_spill_costs(float *spill_costs, bool *no_spill)
>>  {
>>     float loop_scale = 1.0;
>>  
>> +   /* If a spilled register is written (or unspilled) and then immediately read,
>> +    * we will avoid to emit scratch reads for that register for as long as
>> +    * consecutive instructions keep reading that register. This makes spilling
>> +    * the register cheaper, so we need to account for this here. Since any
>> +    * instruction can only have at most 3 src operands we can only have up to
>> +    * 3 cached registers (i.e. registers that we do not need to unspill if they
>> +    * are read in a consecutive instruction) at any given time.
>> +    *
>> +    * We keep two lists, cached[0] has the registers that are cached before
>> +    * the current instruction, and cached[1] has the registers that are
>> +    * cached after the current instruction. We copy cached[1] into cached[0]
>> +    * after processing each instruction.
>> +    */
>> +   int cached[2][3] = { -1, -1, -1,   -1, -1, -1 };
>> +
>
> Wouldn't it be easier to drop the array and just compare the sources of
> each instruction with the previous one?
>
>>     for (unsigned i = 0; i < this->alloc.count; i++) {
>>        spill_costs[i] = 0.0;
>>        no_spill[i] = alloc.sizes[i] != 1;
>> @@ -279,18 +294,52 @@ vec4_visitor::evaluate_spill_costs(float *spill_costs, bool *no_spill)
>>      * loops run 10 times.
>>      */
>>     foreach_block_and_inst(block, vec4_instruction, inst, cfg) {
>> +      memset(cached[1], -1, sizeof(cached[1]));
>> +
>>        for (unsigned int i = 0; i < 3; i++) {
>> -	 if (inst->src[i].file == GRF) {
>> -	    spill_costs[inst->src[i].reg] += loop_scale;
>> -	    assert(!inst->src[i].reladdr);
>> -	 }
>> +         if (inst->src[i].file == GRF) {
>> +            /* Don't increase spilling cost if src[i] isn't going
>> +             * to be unspilled
>> +             */
>> +            int slot;
>> +            for (slot = 0; slot < 3; slot++) {
>> +               if (inst->src[i].reg == cached[0][slot])
>
> I guess this should take the reg_offset and writemask of the cached
> register into account.  I suggest you use backend_reg::in_range() to
> check if there is overlap.
>

It also doesn't look like this handles the case in which the same
register is unspilled several times for the same instruction correctly,
as you've implemented it in PATCH 1.

>> +                  break;
>> +            }
>> +            if (slot == 3) {
>> +               /* Not cached, we will unspill src[i] */
>> +               spill_costs[inst->src[i].reg] += loop_scale;
>> +               assert(!inst->src[i].reladdr);
>> +            } else {
>> +               /* It is cached. Since it is read in this instruction it
>> +                * stays cached for the next.
>> +                */
>> +               cached[1][slot] = inst->src[i].reg;
>> +            }
>> +         }
>>        }
>>  
>>        if (inst->dst.file == GRF) {
>> -	 spill_costs[inst->dst.reg] += loop_scale;
>> -	 assert(!inst->dst.reladdr);
>> +         int slot;
>> +         /* Mark this reg as cached because if the next instruction reads it
>> +          * we won't unspill it.
>> +          */
>> +         for (slot = 0; slot < 3; slot++) {
>> +            if (cached[1][slot] == -1) {
>> +               cached[1][slot] = inst->dst.reg;
>> +               break;
>> +            }
>> +         }
>> +         assert(slot < 3);
>> +         spill_costs[inst->dst.reg] += loop_scale;
>> +         assert(!inst->dst.reladdr);
>>        }
>>  
>> +      /* Cached registers after this instruction are the cached registers
>> +       * for the next instruction
>> +       */
>> +      memcpy(cached[0], cached[1], sizeof(cached[0]));
>> +
>>        switch (inst->opcode) {
>>  
>>        case BRW_OPCODE_DO:
>> -- 
>> 1.9.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 212 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20150730/2de816d8/attachment.sig>


More information about the mesa-dev mailing list