What does this burst vectorization error (NonReductionValueUsedOutsideLoop) mean?

Hi, I’m writing some mesh generation code with the Jobs and Burst compiler. And I get this error:

Remark Type: Analysis
Message:     Plane.cs:26:0: loop not vectorized: value that could not be identified as reduction is used outside the loop
Pass:        loop-vectorize
Remark:      NonReductionValueUsedOutsideLoop
Function:    3c0c4b5cb9474a751b47671200d2ae18

Does anyone know what it means? I’ve been googling it all the time and I have found nothing about this error, literally no one talks about it. This is the code it’s complaining about:

public void Generate<Stream_T>(int row, Stream_T stream) where Stream_T : struct, IVertexStream
{
    int vi = row * (Resolution + 1), ti = (row - 1) * Resolution * 2;

    var vert = new Vertex();
    vert.position.z = ((float)row / Resolution - .5f) * Size;
    vert.uv.y = (float)row / Resolution;

    for (int col = 0; col <= Resolution; ++col, ++vi)
    {
        vert.position.x = ((float)col / Resolution - .5f) * Size;
        vert.uv.x = (float)col / Resolution;

        stream.SetVertex(vi, vert);

        if (row == 0 || col == 0) // <---- this is line 26.
            continue;

        stream.SetTriangle(ti++, vi + int3(-Resolution - 2, -1, -Resolution - 1));
        stream.SetTriangle(ti++, vi + int3(-Resolution - 1, -1, 0));
    }
}

Any help is much appreciated!

Hi, this isn’t (shouldn’t be?) an error, just a warning related to loop vectorization, which is an optimization that the compiler tries to apply in order to compute multiple loop iterations at the same time using SIMD. It should be safe to ignore it.

This type of assembly transformation can only be applied to loops with fairly simple structure. Not sure why the compiler gave up in this case - maybe some proper optimization nerd has some tips - but I think it’s more than likely that even without line 26 it would fail to vectorize for some other reason.

Here’s a talk that explains some of the stuff going on under the hood in Burst:

(The whole thing is worth a watch, but stuff most related to your case starts around 15:00)

You’re branching here and exit the loop iteration early. Vectorization does not like branches. If you can adapt your algorithm to allow the 0 cases through and perhaps filter them out afterwards (or even before the loop), the algorithm may potentially run several times faster thanks to vectorization.

You should also consider to add the [Hint] intrinsic telling the compiler that in most cases the condition is either false (probably) or true.

1 Like

Another concept is to make it ‘branchless’. Meaning that a loop is not exited, but always runs. In this case, SetTriangle always runs, but ti is only +2 if neither row or col is 0.

    int3 offset1 = new int3(-Resolution - 2, -1, -Resolution - 1);
    int3 offset2 = new int3(-Resolution - 1, -1, 0);

for...
        stream.SetTriangle(ti, vi + offset1);
        stream.SetTriangle(ti + 1, vi + offset2);
        ti += (row & col) > 0 ? 2 : 0;