Skip to content

ir3: add support for repeated instructions

Job Noorman requested to merge jnoorman/mesa:ir3-rpt into main

ir3 is a scalar architecture and as such most instructions cannot be vectorized. However, many instructions support the (rptN) modifier that allows us to mimic vector instructions. Whenever an instruction has the (rptN) modifier set it will execute N more time, incrementing its destination register for each repetition. Additionally, source registers with the (r) flag set will also be incremented.

For example:

(rpt1)add.f r0.x, (r)r1.x, r2.x

is the same as:

add.f r0.x, r1.x, r2.x
add.f r0.y, r1.y, r2.x

The main benefit of using repeated instructions is a reduction in code size. Since every iteration is still executed as a scalar instruction, there's no direct benefit in terms of runtime. The only exception seems to be for 3-source instructions pre-a7xx: if one of the sources is constant (i.e., without the (r) flag), a repeated instruction executes faster than the equivalent expanded sequence. Presumably, this is because the ALU only has 2 register read ports. I have not been able to measure this difference on a7xx though.

Support for repeated instructions consists of two parts. First, we need to make sure NIR is (mostly) vectorized when translating to ir3. I have not been able to find a way to keep NIR vectorized all the way and still generate decent code. Therefore, I have taken the approach of vectorizing the (scalarized) NIR right before translating it to ir3.

Secondly, ir3 needs to be adapted to ingest vectorized NIR and translate it to repeated instructions. To this end, I have introduced the concept of "repeat groups" to ir3. A repeat group is a group of instructions that were produced from a vectorized NIR operation and linked together. They are, however, still separate scalar instructions until quite late.

More concretely:

  1. Instruction emission: for every vectorized NIR operation, emit separate scalar instructions for its components and link them together in a repeat group. For every instruction builder ir3_X, a new repeat builder ir3_X_rpt has been added to facilitate this.
  2. Optimization passes: for now, repeat groups are completely ignored by optimizations.
  3. Pre-RA: clean up repeat groups that can never be merged into an actual rptN instruction (e.g., because their instructions are not consecutive anymore). This ensures no useless merge sets will be created in the next step.
  4. RA: create merge sets for the sources and defs of the instructions in repeat groups. This way, RA will try to allocate consecutive registers for them. This will not be forced though because we prefer to split-up repeat groups over creating movs to reorder registers.
  5. Post-RA: create actual rptN instructions for repeat groups where the allocated registers allow it.

The idea for step 2 is that we prefer that any potential optimizations take precedence over creating rptN instructions as the latter will only yield a code size benefit. However, it might be interesting to investigate if we could make some optimizations repeat aware. For example, the scheduler could try to schedule instructions of a repeat group together.

Results

The total code size reduction on shader-db is 7.85%. Full results

Edited by Job Noorman

Merge request reports