Merge pull request #1410 from KhronosGroup/fix-1406
GLSL: Support switch more properly in legacy ESSL
diff --git a/reference/opt/shaders/asm/frag/loop-header-to-continue.asm.frag b/reference/opt/shaders/asm/frag/loop-header-to-continue.asm.frag
index c2dba92..6497ad7 100644
--- a/reference/opt/shaders/asm/frag/loop-header-to-continue.asm.frag
+++ b/reference/opt/shaders/asm/frag/loop-header-to-continue.asm.frag
@@ -22,8 +22,10 @@
void main()
{
+ vec2 _45 = vec2(0.0, _8.CB1.TextureSize.w);
vec4 _49 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv);
float _50 = _49.y;
+ float _53 = clamp(_50 * 0.06399999558925628662109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375);
float _55;
float _58;
_55 = 0.0;
@@ -31,8 +33,8 @@
for (int _60 = -3; _60 <= 3; )
{
float _64 = float(_60);
- vec4 _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (vec2(0.0, _8.CB1.TextureSize.w) * _64));
- float _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < clamp(_50 * 0.06399999558925628662109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375));
+ vec4 _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (_45 * _64));
+ float _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < _53);
_55 += (_72.x * _78);
_58 += _78;
_60++;
diff --git a/reference/opt/shaders/frag/avoid-expression-lowering-to-loop.frag b/reference/opt/shaders/frag/avoid-expression-lowering-to-loop.frag
new file mode 100644
index 0000000..9019ac0
--- /dev/null
+++ b/reference/opt/shaders/frag/avoid-expression-lowering-to-loop.frag
@@ -0,0 +1,29 @@
+#version 310 es
+precision mediump float;
+precision highp int;
+
+layout(binding = 1, std140) uniform Count
+{
+ float count;
+} _44;
+
+layout(binding = 0) uniform mediump sampler2D tex;
+
+layout(location = 0) in highp vec4 vertex;
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ highp float _24 = 1.0 / float(textureSize(tex, 0).x);
+ highp float _34 = dFdx(vertex.x);
+ float _62;
+ _62 = 0.0;
+ for (float _61 = 0.0; _61 < _44.count; )
+ {
+ _62 += (_24 * _34);
+ _61 += 1.0;
+ continue;
+ }
+ fragColor = vec4(_62);
+}
+
diff --git a/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp b/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp
index 4bf34ff..dafd6d5 100644
--- a/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp
+++ b/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp
@@ -33,6 +33,7 @@
{
device foo* _46 = select_buffer(buf, cb);
device foo* _45 = _46;
+ thread uint3* _47 = select_input(gl_GlobalInvocationID, gl_LocalInvocationID, cb);
device foo* _48 = _45;
device int* _52;
device int* _55;
@@ -46,7 +47,7 @@
_58 = *_55;
if (_57 != _58)
{
- int _66 = (_57 + _58) + int((*select_input(gl_GlobalInvocationID, gl_LocalInvocationID, cb)).x);
+ int _66 = (_57 + _58) + int((*_47).x);
*_52 = _66;
*_55 = _66;
_52 = &_52[1u];
diff --git a/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag b/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag
index 29653cb..4049c48 100644
--- a/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag
+++ b/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag
@@ -125,6 +125,7 @@
_151.UvStuds = IN_UvStuds_EdgeDistance2.xy;
SurfaceInput _156 = _151;
_156.UvStuds.y = (fract(_151.UvStuds.y) + IN_studIndex) * 0.25;
+ float _160 = clamp(1.0 - (_146.View_Depth.w * 0.00333332992158830165863037109375), 0.0, 1.0);
float _163 = _146.View_Depth.w * _19.CB0.RefractionBias_FadeDistance_GlowFactor.y;
float _165 = clamp(1.0 - _163, 0.0, 1.0);
vec2 _166 = IN_Uv_EdgeDistance1.xy * 1.0;
@@ -141,7 +142,7 @@
else
{
float _180 = 1.0 / (1.0 - 0.0);
- _193 = mix(texture(SPIRV_Cross_CombinedDiffuseMapTextureDiffuseMapSampler, _166 * 0.25), texture(SPIRV_Cross_CombinedDiffuseMapTextureDiffuseMapSampler, _166), vec4(clamp((clamp(1.0 - (_146.View_Depth.w * 0.00333332992158830165863037109375), 0.0, 1.0) * _180) - (0.0 * _180), 0.0, 1.0)));
+ _193 = mix(texture(SPIRV_Cross_CombinedDiffuseMapTextureDiffuseMapSampler, _166 * 0.25), texture(SPIRV_Cross_CombinedDiffuseMapTextureDiffuseMapSampler, _166), vec4(clamp((_160 * _180) - (0.0 * _180), 0.0, 1.0)));
break;
}
_193 = _192;
@@ -167,12 +168,14 @@
vec2 _223 = vec2(1.0);
vec2 _224 = (_220.wy * 2.0) - _223;
vec3 _232 = vec3(_224, sqrt(clamp(1.0 + dot(-_224, _224), 0.0, 1.0)));
- vec2 _240 = (texture(SPIRV_Cross_CombinedNormalDetailMapTextureNormalDetailMapSampler, _166 * 0.0).wy * 2.0) - _223;
+ vec4 _237 = texture(SPIRV_Cross_CombinedNormalDetailMapTextureNormalDetailMapSampler, _166 * 0.0);
+ vec2 _240 = (_237.wy * 2.0) - _223;
vec2 _252 = _232.xy + (vec3(_240, sqrt(clamp(1.0 + dot(-_240, _240), 0.0, 1.0))).xy * 0.0);
vec3 _253 = vec3(_252.x, _252.y, _232.z);
vec2 _255 = _253.xy * _165;
vec3 _256 = vec3(_255.x, _255.y, _253.z);
- vec3 _271 = ((IN_Color.xyz * (_193 * 1.0).xyz) * (1.0 + (_256.x * 0.300000011920928955078125))) * (texture(SPIRV_Cross_CombinedStudsMapTextureStudsMapSampler, _156.UvStuds).x * 2.0);
+ vec4 _268 = texture(SPIRV_Cross_CombinedStudsMapTextureStudsMapSampler, _156.UvStuds);
+ vec3 _271 = ((IN_Color.xyz * (_193 * 1.0).xyz) * (1.0 + (_256.x * 0.300000011920928955078125))) * (_268.x * 2.0);
vec4 _298;
for (;;)
{
diff --git a/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag b/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag
index 1af8db7..3a13024 100644
--- a/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag
+++ b/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag
@@ -216,11 +216,14 @@
{
main0_out out = {};
float4 _177 = float4((((gl_FragCoord.xy - View.View_ViewRectMin.xy) * View.View_ViewSizeAndInvSize.zw) - float2(0.5)) * float2(2.0, -2.0), _138, 1.0) * float4(gl_FragCoord.w);
+ float3 _179 = in.in_var_TEXCOORD8.xyz - float3(View.View_PreViewTranslation);
float3 _181 = normalize(-in.in_var_TEXCOORD8.xyz);
- float2 _190 = (Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (in.in_var_TEXCOORD0 * float2(10.0))).xy * float2(2.0)) - float2(1.0);
+ float4 _187 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (in.in_var_TEXCOORD0 * float2(10.0)));
+ float2 _190 = (_187.xy * float2(2.0)) - float2(1.0);
float3 _206 = normalize(float3x3(float3(1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 0.0, 1.0)) * (((float4(_190, sqrt(fast::clamp(1.0 - dot(_190, _190), 0.0, 1.0)), 1.0).xyz * float3(0.300000011920928955078125, 0.300000011920928955078125, 1.0)) * float3(View.View_NormalOverrideParameter.w)) + View.View_NormalOverrideParameter.xyz));
float _208 = dot(_206, _181);
- float _219 = mix(0.4000000059604644775390625, 1.0, Material_Texture2D_1.sample(Material_Texture2D_1Sampler, (in.in_var_TEXCOORD0 * float2(20.0))).x);
+ float4 _217 = Material_Texture2D_1.sample(Material_Texture2D_1Sampler, (in.in_var_TEXCOORD0 * float2(20.0)));
+ float _219 = mix(0.4000000059604644775390625, 1.0, _217.x);
float4 _223 = Material_Texture2D_1.sample(Material_Texture2D_1Sampler, (in.in_var_TEXCOORD0 * float2(5.0)));
float _224 = _177.w;
float _228 = fast::min(fast::max((_224 - 24.0) * 0.000666666659526526927947998046875, 0.0), 1.0);
@@ -328,7 +331,7 @@
{
if (_491 < _Globals.NumDynamicPointLights)
{
- float3 _501 = _Globals.LightPositionAndInvRadius[_491].xyz - (in.in_var_TEXCOORD8.xyz - float3(View.View_PreViewTranslation));
+ float3 _501 = _Globals.LightPositionAndInvRadius[_491].xyz - _179;
float _502 = dot(_501, _501);
float3 _505 = _501 * float3(rsqrt(_502));
_507 = normalize(_181 + _505);
diff --git a/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag b/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag
index 73dc2ee..bc40c7c 100644
--- a/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag
+++ b/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag
@@ -274,8 +274,11 @@
float3 _151 = normalize(-_148);
float3 _152 = _151 * float3x3(in.in_var_TEXCOORD10_centroid.xyz, cross(in.in_var_TEXCOORD11_centroid.xyz, in.in_var_TEXCOORD10_centroid.xyz) * float3(in.in_var_TEXCOORD11_centroid.w), in.in_var_TEXCOORD11_centroid.xyz);
float _170 = mix(Material.Material_ScalarExpressions[0].y, Material.Material_ScalarExpressions[0].z, fast::min(fast::max(abs(dot(_151, in.in_var_TEXCOORD11_centroid.xyz)), 0.0), 1.0));
+ float _171 = floor(_170);
float _172 = 1.0 / _170;
float2 _174 = (float2(Material.Material_ScalarExpressions[0].x) * ((_152.xy * float2(-1.0)) / float2(_152.z))) * float2(_172);
+ float2 _175 = dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y));
+ float2 _176 = dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y));
float _180_copy;
float2 _183;
_183 = float2(0.0);
@@ -288,9 +291,9 @@
float _189 = 1.0;
for (;;)
{
- if (float(_185) < (floor(_170) + 2.0))
+ if (float(_185) < (_171 + 2.0))
{
- _188 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _183), gradient2d(dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)), dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)))).y;
+ _188 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _183), gradient2d(_175, _176)).y;
if (_180 < _188)
{
float _201 = _188 - _180;
diff --git a/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag b/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag
index 73dc2ee..bc40c7c 100644
--- a/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag
+++ b/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag
@@ -274,8 +274,11 @@
float3 _151 = normalize(-_148);
float3 _152 = _151 * float3x3(in.in_var_TEXCOORD10_centroid.xyz, cross(in.in_var_TEXCOORD11_centroid.xyz, in.in_var_TEXCOORD10_centroid.xyz) * float3(in.in_var_TEXCOORD11_centroid.w), in.in_var_TEXCOORD11_centroid.xyz);
float _170 = mix(Material.Material_ScalarExpressions[0].y, Material.Material_ScalarExpressions[0].z, fast::min(fast::max(abs(dot(_151, in.in_var_TEXCOORD11_centroid.xyz)), 0.0), 1.0));
+ float _171 = floor(_170);
float _172 = 1.0 / _170;
float2 _174 = (float2(Material.Material_ScalarExpressions[0].x) * ((_152.xy * float2(-1.0)) / float2(_152.z))) * float2(_172);
+ float2 _175 = dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y));
+ float2 _176 = dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y));
float _180_copy;
float2 _183;
_183 = float2(0.0);
@@ -288,9 +291,9 @@
float _189 = 1.0;
for (;;)
{
- if (float(_185) < (floor(_170) + 2.0))
+ if (float(_185) < (_171 + 2.0))
{
- _188 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _183), gradient2d(dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)), dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)))).y;
+ _188 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _183), gradient2d(_175, _176)).y;
if (_180 < _188)
{
float _201 = _188 - _180;
diff --git a/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag b/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag
index 98cdda4..d73c30c 100644
--- a/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag
+++ b/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag
@@ -84,6 +84,7 @@
uint _107 = _103 + 1u;
if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102))
{
+ float3 _121 = float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz);
float _122 = _96.x;
float _123 = _96.y;
spvUnsafeArray<float3, 8> _73;
@@ -103,7 +104,7 @@
_158 = float3(500000.0);
for (int _160 = 0; _160 < 8; )
{
- float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz));
+ float3 _166 = _73[_160] - _121;
float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz));
_155 = fast::max(_155, _170);
_158 = fast::min(_158, _170);
diff --git a/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag b/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag
index 98cdda4..d73c30c 100644
--- a/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag
+++ b/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag
@@ -84,6 +84,7 @@
uint _107 = _103 + 1u;
if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102))
{
+ float3 _121 = float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz);
float _122 = _96.x;
float _123 = _96.y;
spvUnsafeArray<float3, 8> _73;
@@ -103,7 +104,7 @@
_158 = float3(500000.0);
for (int _160 = 0; _160 < 8; )
{
- float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz));
+ float3 _166 = _73[_160] - _121;
float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz));
_155 = fast::max(_155, _170);
_158 = fast::min(_158, _170);
diff --git a/reference/shaders/asm/frag/loop-header-to-continue.asm.frag b/reference/shaders/asm/frag/loop-header-to-continue.asm.frag
index a99322d..8a3b664 100644
--- a/reference/shaders/asm/frag/loop-header-to-continue.asm.frag
+++ b/reference/shaders/asm/frag/loop-header-to-continue.asm.frag
@@ -22,8 +22,10 @@
void main()
{
+ vec2 _45 = vec2(0.0, _8.CB1.TextureSize.w);
vec4 _49 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv);
float _50 = _49.y;
+ float _53 = clamp((_50 * 80.0) * 0.0007999999797903001308441162109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375);
float _55;
float _58;
_55 = 0.0;
@@ -31,8 +33,8 @@
for (int _60 = -3; _60 <= 3; )
{
float _64 = float(_60);
- vec4 _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (vec2(0.0, _8.CB1.TextureSize.w) * _64));
- float _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < clamp((_50 * 80.0) * 0.0007999999797903001308441162109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375));
+ vec4 _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (_45 * _64));
+ float _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < _53);
_55 += (_72.x * _78);
_58 += _78;
_60++;
diff --git a/reference/shaders/frag/avoid-expression-lowering-to-loop.frag b/reference/shaders/frag/avoid-expression-lowering-to-loop.frag
new file mode 100644
index 0000000..6313d89
--- /dev/null
+++ b/reference/shaders/frag/avoid-expression-lowering-to-loop.frag
@@ -0,0 +1,26 @@
+#version 310 es
+precision mediump float;
+precision highp int;
+
+layout(binding = 1, std140) uniform Count
+{
+ float count;
+} _44;
+
+layout(binding = 0) uniform mediump sampler2D tex;
+
+layout(location = 0) in highp vec4 vertex;
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ highp float size = 1.0 / float(textureSize(tex, 0).x);
+ float r = 0.0;
+ float d = dFdx(vertex.x);
+ for (float i = 0.0; i < _44.count; i += 1.0)
+ {
+ r += (size * d);
+ }
+ fragColor = vec4(r);
+}
+
diff --git a/shaders/frag/avoid-expression-lowering-to-loop.frag b/shaders/frag/avoid-expression-lowering-to-loop.frag
new file mode 100644
index 0000000..3473875
--- /dev/null
+++ b/shaders/frag/avoid-expression-lowering-to-loop.frag
@@ -0,0 +1,23 @@
+#version 310 es
+precision mediump float;
+precision mediump int;
+
+layout(binding = 0) uniform mediump sampler2D tex;
+layout(binding = 1) uniform Count
+{
+ float count;
+};
+
+layout(location = 0) in highp vec4 vertex;
+layout(location = 0) out vec4 fragColor;
+
+void main() {
+
+ highp float size = 1.0 / float(textureSize(tex, 0).x);
+ float r = 0.0;
+ float d = dFdx(vertex.x);
+ for (float i = 0.0; i < count ; i += 1.0)
+ r += size * d;
+
+ fragColor = vec4(r);
+}
diff --git a/spirv_common.hpp b/spirv_common.hpp
index af0d076..4f9bcab 100644
--- a/spirv_common.hpp
+++ b/spirv_common.hpp
@@ -262,6 +262,29 @@
return buf;
}
+template <typename T>
+struct ValueSaver
+{
+ explicit ValueSaver(T ¤t_)
+ : current(current_)
+ , saved(current_)
+ {
+ }
+
+ void release()
+ {
+ current = saved;
+ }
+
+ ~ValueSaver()
+ {
+ release();
+ }
+
+ T ¤t;
+ T saved;
+};
+
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
@@ -699,6 +722,9 @@
// Used by access chain Store and Load since we read multiple expressions in this case.
SmallVector<ID> implied_read_expressions;
+ // The expression was emitted at a certain scope. Lets us track when an expression read means multiple reads.
+ uint32_t emitted_loop_level = 0;
+
SPIRV_CROSS_DECLARE_CLONE(SPIRExpression)
};
diff --git a/spirv_cross.cpp b/spirv_cross.cpp
index 8abe19a..19c9e1a 100644
--- a/spirv_cross.cpp
+++ b/spirv_cross.cpp
@@ -4674,3 +4674,8 @@
return true;
return false;
}
+
+void Compiler::add_loop_level()
+{
+ current_loop_level++;
+}
diff --git a/spirv_cross.hpp b/spirv_cross.hpp
index e452ca6..17c0818 100644
--- a/spirv_cross.hpp
+++ b/spirv_cross.hpp
@@ -513,9 +513,22 @@
SPIRFunction *current_function = nullptr;
SPIRBlock *current_block = nullptr;
+ uint32_t current_loop_level = 0;
std::unordered_set<VariableID> active_interface_variables;
bool check_active_interface_variables = false;
+ void add_loop_level();
+
+ void set_initializers(SPIRExpression &e)
+ {
+ e.emitted_loop_level = current_loop_level;
+ }
+
+ template <typename T>
+ void set_initializers(const T &)
+ {
+ }
+
// If our IDs are out of range here as part of opcodes, throw instead of
// undefined behavior.
template <typename T, typename... P>
@@ -524,6 +537,7 @@
ir.add_typed_id(static_cast<Types>(T::type), id);
auto &var = variant_set<T>(ir.ids[id], std::forward<P>(args)...);
var.self = id;
+ set_initializers(var);
return var;
}
diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp
index 1bb961b..5f2a48f 100644
--- a/spirv_glsl.cpp
+++ b/spirv_glsl.cpp
@@ -341,6 +341,7 @@
statement_count = 0;
indent = 0;
+ current_loop_level = 0;
}
void CompilerGLSL::remap_pls_variables()
@@ -4550,6 +4551,17 @@
return suppressed_usage_tracking.count(id) != 0;
}
+bool CompilerGLSL::expression_read_implies_multiple_reads(uint32_t id) const
+{
+ auto *expr = maybe_get<SPIRExpression>(id);
+ if (!expr)
+ return false;
+
+ // If we're emitting code at a deeper loop level than when we emitted the expression,
+ // we're probably reading the same expression over and over.
+ return current_loop_level > expr->emitted_loop_level;
+}
+
SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id, const string &rhs, bool forwarding,
bool suppress_usage_tracking)
{
@@ -8172,6 +8184,13 @@
auto &v = expression_usage_counts[id];
v++;
+ // If we create an expression outside a loop,
+ // but access it inside a loop, we're implicitly reading it multiple times.
+ // If the expression in question is expensive, we should hoist it out to avoid relying on loop-invariant code motion
+ // working inside the backend compiler.
+ if (expression_read_implies_multiple_reads(id))
+ v++;
+
if (v >= 2)
{
//if (v == 2)
@@ -13003,6 +13022,10 @@
bool skip_direct_branch = false;
bool emitted_loop_header_variables = false;
bool force_complex_continue_block = false;
+ ValueSaver<uint32_t> loop_level_saver(current_loop_level);
+
+ if (block.merge == SPIRBlock::MergeLoop)
+ add_loop_level();
emit_hoisted_temporaries(block.declare_temporary);
@@ -13535,7 +13558,11 @@
// If we hit this case, we're dealing with an unconditional branch, which means we will output
// that block after this. If we had selection merge, we already flushed phi variables.
if (block.merge != SPIRBlock::MergeSelection)
+ {
flush_phi(block.self, block.next_block);
+ // For a direct branch, need to remember to invalidate expressions in the next linear block instead.
+ get<SPIRBlock>(block.next_block).invalidate_expressions = block.invalidate_expressions;
+ }
// For switch fallthrough cases, we terminate the chain here, but we still need to handle Phi.
if (!current_emitting_switch_fallthrough)
@@ -13589,6 +13616,8 @@
else
end_scope();
+ loop_level_saver.release();
+
// We cannot break out of two loops at once, so don't check for break; here.
// Using block.self as the "from" block isn't quite right, but it has the same scope
// and dominance structure, so it's fine.
diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp
index 351adae..47b6d0b 100644
--- a/spirv_glsl.hpp
+++ b/spirv_glsl.hpp
@@ -549,6 +549,7 @@
void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
bool expression_is_forwarded(uint32_t id) const;
bool expression_suppresses_usage_tracking(uint32_t id) const;
+ bool expression_read_implies_multiple_reads(uint32_t id) const;
SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,
bool suppress_usage_tracking = false);