tests: Add many SM3 loop tests.

After writing these tests, I realized it is possible to classify SM3 loops in two categories:

(A) Loops whose number of iterations is limited by a single int uniform. This happens when the loop's condition is of the form i < limit, where i is the iterator that starts at 0 and increases by 1 every iteration, and limit is an int uniform (or int component of thereof).

In this case, the shader CTAB shows the limit variable expected as an int on an i register. If the limit variable is also used outside the loop condition, it also has to be passed as float on a c register.

After making a shader that triggered some warnings, it seems that the native compiler uses an unroll attempt behind the scenes to verify that the number of iterations is always limited by limit.

(B) Loops that are not limited by a single uniform: For these cases, the compiler defines its own integer constant, usually with the value 255, like this:

defi i0, 255, 0, 0, 0,

This value can be lower, e.g. it can be s if an array with maximum size s is indexed using the iterator variable for relative addressing.

While at first glance it might seem that implementation (B) covers all cases of implementation (A), we still have to discern one from the other in the same way the native compiler does, for several reasons:

  • Case (A) might mean not having to rely on a break instruction, which allows to use gradient instructions (such as a Tex2D()) inside the loop, while (B) requires a break so it is not allowed to.
  • If a uniform is solely used as an iteration limit, it won't need to get a c register allocated, so, not skipping this allocation (because we would be using the float value in the c register instead of the int value in the i register) will mean pushing all other uniforms to different registers than the native compiler.
  • Conversely, if we allocate an i register when the native compiler doesn't, we will push the other i allocations to the next positions (albeit it might be rare to find more than i registers in the same shader).

Locally, I already have implemented the method to discern between these two cases and the HLSL side of case (B), which I intent to send after this. Also, I am currently writing vsir normalization passes required to lower the REP, DEFI, BREAK, and ENDREP instructions that come from the d3dbc parser.

After this, we can focus on case (A). My understanding is that we have to use push constant buffer 1 to pass the constant-int values from non Direct3D backends, but I am still understanding that mechanism.

Edited by Francisco Casas

Merge request reports

Loading