<p>It really depends on the individual compiler. The GPU vendor is responsible for the compiler as part of their driver, so it's really a total crapshoot as to how things get optimized, and you would need vendor-specific tools (if available) to get the compiled shader and disassemble it.</p>
<p>If the GLSL is compiled to SPIR-V (i.e. for Vulkan) then you can at least look at the SPIR-V and see what optimizations were done at that level. If the loop gets unrolled by the SPIR-V compiler, it's unlikely that it would be re-rolled by the driver compiler. However, ultimately when it's submitted to the driver it will still go through another compile stage which may transform the code further, so whatever you see in the SPIR-V isn't necessarily definitive.</p>
<p>In general, you're right that the compiler has to assume that uniform values are arbitrary. So if, for instance, you loop from 0 up to some 32-bit int uniform value, then it won't be able to unroll the loop as it could have in principle billions of iterations.</p>
<p>Sometimes, if you put a compiler-visible upper bound on the loop count then the compiler will be able to unroll it:</p>
<pre><code>uniform int iterCount;
...
int count = min(iterCount, 4);
for (int i = 0; i &lt; count; ++i)
{
    ...
}
</code></pre>
<p>Here, it's possible for the compiler to prove that the count can't be more than 4, so it would be safe to unroll the loop 4x, with conditionals to jump over parts of it based on the actual value of <code>iterCount</code>. But again, whether the compiler actually does that in any given instance is going to be down to the individual compiler's analysis and heuristics. Generally if the loop body is long, or the iteration count is high, it will be less profitable to unroll it.</p>
<p>By the way, in your example the value of <code>maxIter</code> is always either 2 or 3, and so the loop count is either 5 or 7, and the compiler should be able to see that, so it would be a reasonable expectation that it could unroll that loop if it decides it's a good idea.</p>
<p>Also, if you have access to <a href="https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_control_flow_attributes.txt" rel="nofollow noreferrer">GL_EXT_control_flow_attributes</a> then you can mark up loops with the <code>[[unroll]]</code> annotation to explicitly request the compiler to unroll it—although the compiler may still refuse to honor that if it doesn't have a compiler-visible upper bound.</p>

CC BY-SA 4.0
2021-10-22T20:32:43.543Z
Marked as the correct answer but I guess it didn't really solve the question per se, not because the answer wasn't well structured but because hardware vendors don't disclose their compilers AFAIK, so basically proved what I thought. The Spir-V trick might be handy though. Regards
Felipe Gutierrez
CC BY-SA 4.0
2021-10-14T00:15:52.857Z
2021-10-14T00:15:52.857Z
Nathan Reed
<p>My question is fairly simple but I guess it contains two questions, one is how to arrive at an answer (imagine a similar one and you want to deduce it using existing tools like a GLSL compiler or the like, I wasn't able to as I couldn't find any loop unrolling on trivial loops from the compilers I found online) and the question per se is: at what point does doing arithmetic/logic on a uniform becomes non trivial for the driver and stuff like loop unrolling stops happening. Imagine the scenario were you have a uniform on which the kernel size of a convolution depends on, something like</p>
<pre><code>
int maxIter = fract( log2( float( whatever ) ) ) == 0. ? 3 : 2;

for (int i = -maxIter; i &lt;= maxIter; ++i) 
{ 
</code></pre>
<p>will this get unrolled? I am fairly certain that simply having a <code>min( 0, whatever );</code> won't unroll the loop as the compiler takes the uniform as a blackbox if I am correct.</p>

<shader><glsl>
Dynamic Loop Based on Uniform
Felipe Gutierrez
# Dynamic Loop Based on Uniform

(Asked by: username_0 on 2021-10-13)

My question is fairly simple but I guess it contains two questions, one is how to arrive at an answer (imagine a similar one and you want to deduce it using existing tools like a GLSL compiler or the like, I wasn't able to as I couldn't find any loop unrolling on trivial loops from the compilers I found online) and the question per se is: at what point does doing arithmetic/logic on a uniform becomes non trivial for the driver and stuff like loop unrolling stops happening. Imagine the scenario were you have a uniform on which the kernel size of a convolution depends on, something like

```

int maxIter = fract( log2( float( whatever ) ) ) == 0. ? 3 : 2;

for (int i = -maxIter; i <= maxIter; ++i) 
{ 

```

will this get unrolled? I am fairly certain that simply having a `min( 0, whatever );` won't unroll the loop as the compiler takes the uniform as a blackbox if I am correct.

**Tags:** shader, glsl


---

## 1 answers

### Answer by username_1 on 2021-10-14. Score: 1 | Accepted answer

It really depends on the individual compiler. The GPU vendor is responsible for the compiler as part of their driver, so it's really a total crapshoot as to how things get optimized, and you would need vendor-specific tools (if available) to get the compiled shader and disassemble it.

If the GLSL is compiled to SPIR-V (i.e. for Vulkan) then you can at least look at the SPIR-V and see what optimizations were done at that level. If the loop gets unrolled by the SPIR-V compiler, it's unlikely that it would be re-rolled by the driver compiler. However, ultimately when it's submitted to the driver it will still go through another compile stage which may transform the code further, so whatever you see in the SPIR-V isn't necessarily definitive.

In general, you're right that the compiler has to assume that uniform values are arbitrary. So if, for instance, you loop from 0 up to some 32-bit int uniform value, then it won't be able to unroll the loop as it could have in principle billions of iterations.

Sometimes, if you put a compiler-visible upper bound on the loop count then the compiler will be able to unroll it:

```
uniform int iterCount;
...
int count = min(iterCount, 4);
for (int i = 0; i < count; ++i)
{
    ...
}

```

Here, it's possible for the compiler to prove that the count can't be more than 4, so it would be safe to unroll the loop 4x, with conditionals to jump over parts of it based on the actual value of `iterCount`. But again, whether the compiler actually does that in any given instance is going to be down to the individual compiler's analysis and heuristics. Generally if the loop body is long, or the iteration count is high, it will be less profitable to unroll it.

By the way, in your example the value of `maxIter` is always either 2 or 3, and so the loop count is either 5 or 7, and the compiler should be able to see that, so it would be a reasonable expectation that it could unroll that loop if it decides it's a good idea.

Also, if you have access to [GL\_EXT\_control\_flow\_attributes](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_control_flow_attributes.txt) then you can mark up loops with the `[[unroll]]` annotation to explicitly request the compiler to unroll it—although the compiler may still refuse to honor that if it doesn't have a compiler-visible upper bound.

> **Comments:**
> **username_0**: Marked as the correct answer but I guess it didn't really solve the question per se, not because the answer wasn't well structured but because hardware vendors don't disclose their compilers AFAIK, so basically proved what I thought. The Spir-V trick might be handy though. Regards  

---

