diff options
author | Hans-Kristian Arntzen <post@arntzen-software.no> | 2022-01-17 16:12:01 +0300 |
---|---|---|
committer | Hans-Kristian Arntzen <post@arntzen-software.no> | 2022-01-17 16:12:01 +0300 |
commit | 1d13a3e36a56e446020057beedb82cdce6d23c58 (patch) | |
tree | 06285488c1ab8b50ecaeacb15c2bc8351ec2112a | |
parent | a1bb29ccbb285618028a24efb3fe4f6718cee0b5 (diff) |
Rework how loop iteration counts are validated.
Introduces an idea of a recompilation making forward progress.
There are some extreme edge cases where we need more than 3 loops, but
only allow this in specific circumstances where we can reason about
forward progress being made.
-rw-r--r-- | reference/shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag | 262 | ||||
-rw-r--r-- | reference/shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag | 54 | ||||
-rw-r--r-- | shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag | 625 | ||||
-rw-r--r-- | shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag | 109 | ||||
-rw-r--r-- | spirv_cpp.cpp | 5 | ||||
-rw-r--r-- | spirv_cross.cpp | 7 | ||||
-rw-r--r-- | spirv_cross.hpp | 2 | ||||
-rw-r--r-- | spirv_glsl.cpp | 31 | ||||
-rw-r--r-- | spirv_glsl.hpp | 2 | ||||
-rw-r--r-- | spirv_hlsl.cpp | 5 | ||||
-rw-r--r-- | spirv_msl.cpp | 5 |
11 files changed, 1085 insertions, 22 deletions
diff --git a/reference/shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag b/reference/shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag new file mode 100644 index 00000000..85bc540f --- /dev/null +++ b/reference/shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag @@ -0,0 +1,262 @@ +#version 320 es +#if defined(GL_EXT_control_flow_attributes) +#extension GL_EXT_control_flow_attributes : require +#define SPIRV_CROSS_FLATTEN [[flatten]] +#define SPIRV_CROSS_BRANCH [[dont_flatten]] +#define SPIRV_CROSS_UNROLL [[unroll]] +#define SPIRV_CROSS_LOOP [[dont_unroll]] +#else +#define SPIRV_CROSS_FLATTEN +#define SPIRV_CROSS_BRANCH +#define SPIRV_CROSS_UNROLL +#define SPIRV_CROSS_LOOP +#endif +precision mediump float; +precision highp int; + +layout(binding = 0, std140) uniform buf0 +{ + highp vec2 resolution; +} _7; + +layout(location = 0) out highp vec4 _GLF_color; +int map[256]; +highp mat2x4 _60 = mat2x4(vec4(0.0), vec4(0.0)); + +void main() +{ + int _68 = -(256 - 14); + highp vec2 pos = gl_FragCoord.xy / _7.resolution; + ivec2 ipos = ivec2(int(pos.x * 16.0), int(pos.y * 16.0)); + int i = 0; + for (; i < 256; i++) + { + map[i] = 0; + } + ivec2 p = ivec2(0); + int v = 0; + bool canwalk = true; + do + { + v++; + int directions = 0; + bool _98 = p.x > 0; + bool _111; + if (_98) + { + _111 = map[(p.x - 2) + (p.y * 16)] == 0; + } + else + { + _111 = _98; + } + if (_111) + { + directions++; + } + bool _118 = p.y > 0; + bool _131; + if (_118) + { + _131 = map[p.x + ((p.y - 2) * 16)] == 0; + } + else + { + _131 = _118; + } + if (_131) + { + directions++; + } + bool _138 = p.x < 14; + bool _151; + if (_138) + { + _151 = map[(p.x + 2) + (p.y * 16)] == 0; + } + else + { + _151 = _138; + } + if (_151) + { + directions++; + } + int _156 = 256 - _68; + bool _159 = p.y < 14; + bool _172; + if (_159) + { + _172 = map[p.x + ((p.y + 2) * 16)] == 0; + } + else + { + _172 = _159; + } + if (_172) + { + directions++; + } + if (directions == 0) + { + canwalk = false; + i = 0; + for (;;) + { + int _186 = i; + if (_186 < 8) + { + int j = 0; + _60 = mat2x4(vec4(0.0), vec4(0.0)); + if (false) + { + int _216 = i; + i = _216 + 1; + continue; + } + else + { + SPIRV_CROSS_UNROLL + for (; j < 8; j++) + { + if (map[(j * 2) + ((i * 2) * 16)] == 0) + { + p.x = j * 2; + p.y = i * 2; + canwalk = true; + } + } + int _216 = i; + i = _216 + 1; + continue; + } + } + else + { + break; + } + } + map[p.x + (p.y * 16)] = 1; + } + else + { + int d = v % directions; + v += directions; + bool _232 = d >= 0; + bool _238; + if (_232) + { + _238 = p.x > 0; + } + else + { + _238 = _232; + } + bool _251; + if (_238) + { + _251 = map[(p.x - 2) + (p.y * 16)] == 0; + } + else + { + _251 = _238; + } + if (_251) + { + d--; + map[p.x + (p.y * 16)] = 1; + map[(p.x - 1) + (p.y * 16)] = 1; + map[(p.x - 2) + (p.y * 16)] = 1; + p.x -= 2; + } + bool _284 = d >= 0; + bool _290; + if (_284) + { + _290 = p.y > 0; + } + else + { + _290 = _284; + } + bool _303; + if (_290) + { + _303 = map[p.x + ((p.y - 2) * 16)] == 0; + } + else + { + _303 = _290; + } + if (_303) + { + d--; + map[p.x + (p.y * 16)] = 1; + map[p.x + ((p.y - 1) * 16)] = 1; + map[p.x + ((p.y - 2) * 16)] = 1; + p.y -= 2; + } + bool _336 = d >= 0; + bool _342; + if (_336) + { + _342 = p.x < 14; + } + else + { + _342 = _336; + } + bool _355; + if (_342) + { + _355 = map[(p.x + 2) + (p.y * 16)] == 0; + } + else + { + _355 = _342; + } + if (_355) + { + d--; + map[p.x + (p.y * 16)] = 1; + map[(p.x + 1) + (p.y * 16)] = 1; + map[(p.x + 2) + (p.y * 16)] = 1; + p.x += 2; + } + bool _388 = d >= 0; + bool _394; + if (_388) + { + _394 = p.y < 14; + } + else + { + _394 = _388; + } + bool _407; + if (_394) + { + _407 = map[p.x + ((p.y + 2) * 16)] == 0; + } + else + { + _407 = _394; + } + if (_407) + { + d--; + map[p.x + (p.y * 16)] = 1; + map[p.x + ((p.y + 1) * 16)] = 1; + map[p.x + ((p.y + 2) * 16)] = 1; + p.y += 2; + } + } + if (map[(ipos.y * 16) + ipos.x] == 1) + { + _GLF_color = vec4(1.0); + return; + } + } while (canwalk); + _GLF_color = vec4(0.0, 0.0, 0.0, 1.0); +} + diff --git a/reference/shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag b/reference/shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag new file mode 100644 index 00000000..6522c651 --- /dev/null +++ b/reference/shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag @@ -0,0 +1,54 @@ +#version 310 es +precision mediump float; +precision highp int; + +const mat4 _34[4] = mat4[](mat4(vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0)), mat4(vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0)), mat4(vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0)), mat4(vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0))); + +layout(location = 0) out highp vec4 _GLF_color; + +void main() +{ + for (;;) + { + if (gl_FragCoord.x < 10.0) + { + _GLF_color = vec4(1.0, 0.0, 0.0, 1.0); + break; + } + for (int _46 = 0; _46 < 4; _46++) + { + int _53; + _53 = 0; + bool _56; + for (;;) + { + _56 = _53 < 4; + if (_56) + { + if (distance(vec2(1.0), vec2(1.0) / vec2(_34[int(_56)][_46].w)) < 1.0) + { + _GLF_color = vec4(1.0); + int _54 = _53 + 1; + _53 = _54; + continue; + } + else + { + int _54 = _53 + 1; + _53 = _54; + continue; + } + int _54 = _53 + 1; + _53 = _54; + continue; + } + else + { + break; + } + } + } + break; + } +} + diff --git a/shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag b/shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag new file mode 100644 index 00000000..a10970e9 --- /dev/null +++ b/shaders-no-opt/asm/frag/late-expression-invalidation-2.asm.frag @@ -0,0 +1,625 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos SPIR-V Tools Assembler; 0 +; Bound: 761 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord %_GLF_color + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 320 + OpName %main "main" + OpName %pos "pos" + OpName %gl_FragCoord "gl_FragCoord" + OpName %buf0 "buf0" + OpMemberName %buf0 0 "resolution" + OpName %_ "" + OpName %ipos "ipos" + OpName %i "i" + OpName %map "map" + OpName %p "p" + OpName %canwalk "canwalk" + OpName %v "v" + OpName %directions "directions" + OpName %j "j" + OpName %d "d" + OpName %_GLF_color "_GLF_color" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpMemberDecorate %buf0 0 Offset 0 + OpDecorate %buf0 Block + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %_GLF_color Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 +%_ptr_Function_v2float = OpTypePointer Function %v2float + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %buf0 = OpTypeStruct %v2float +%_ptr_Uniform_buf0 = OpTypePointer Uniform %buf0 + %_ = OpVariable %_ptr_Uniform_buf0 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float + %v2int = OpTypeVector %int 2 +%_ptr_Function_v2int = OpTypePointer Function %v2int + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Function_float = OpTypePointer Function %float + %float_16 = OpConstant %float 16 + %uint_1 = OpConstant %uint 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_256 = OpConstant %int 256 + %bool = OpTypeBool + %uint_256 = OpConstant %uint 256 +%_arr_int_uint_256 = OpTypeArray %int %uint_256 +%_ptr_Private__arr_int_uint_256 = OpTypePointer Private %_arr_int_uint_256 + %map = OpVariable %_ptr_Private__arr_int_uint_256 Private +%_ptr_Private_int = OpTypePointer Private %int + %int_1 = OpConstant %int 1 + %63 = OpConstantComposite %v2int %int_0 %int_0 +%_ptr_Function_bool = OpTypePointer Function %bool + %true = OpConstantTrue %bool + %int_2 = OpConstant %int 2 + %int_16 = OpConstant %int 16 + %int_14 = OpConstant %int 14 + %false = OpConstantFalse %bool + %int_8 = OpConstant %int 8 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %_GLF_color = OpVariable %_ptr_Output_v4float Output + %float_1 = OpConstant %float 1 + %437 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %float_0 = OpConstant %float 0 + %441 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1 +%mat2v4float = OpTypeMatrix %v4float 2 +%_ptr_Private_mat2v4float = OpTypePointer Private %mat2v4float + %556 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %557 = OpConstantComposite %mat2v4float %556 %556 + %558 = OpVariable %_ptr_Private_mat2v4float Private %557 + %760 = OpConstantNull %bool + %main = OpFunction %void None %3 + %5 = OpLabel + %pos = OpVariable %_ptr_Function_v2float Function + %ipos = OpVariable %_ptr_Function_v2int Function + %i = OpVariable %_ptr_Function_int Function + %p = OpVariable %_ptr_Function_v2int Function + %canwalk = OpVariable %_ptr_Function_bool Function + %v = OpVariable %_ptr_Function_int Function + %directions = OpVariable %_ptr_Function_int Function + %j = OpVariable %_ptr_Function_int Function + %d = OpVariable %_ptr_Function_int Function + %13 = OpLoad %v4float %gl_FragCoord + %14 = OpVectorShuffle %v2float %13 %13 0 1 + %564 = OpISub %int %int_256 %int_14 + %21 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 + %22 = OpLoad %v2float %21 + %566 = OpSNegate %int %564 + %23 = OpFDiv %v2float %14 %22 + OpStore %pos %23 + %30 = OpAccessChain %_ptr_Function_float %pos %uint_0 + %31 = OpLoad %float %30 + %33 = OpFMul %float %31 %float_16 + %34 = OpConvertFToS %int %33 + %36 = OpAccessChain %_ptr_Function_float %pos %uint_1 + %37 = OpLoad %float %36 + %38 = OpFMul %float %37 %float_16 + %39 = OpConvertFToS %int %38 + %40 = OpCompositeConstruct %v2int %34 %39 + OpStore %ipos %40 + OpStore %i %int_0 + OpBranch %43 + %43 = OpLabel + OpLoopMerge %45 %46 None + OpBranch %47 + %47 = OpLabel + %48 = OpLoad %int %i + %51 = OpSLessThan %bool %48 %int_256 + OpBranchConditional %51 %44 %45 + %44 = OpLabel + %56 = OpLoad %int %i + %58 = OpAccessChain %_ptr_Private_int %map %56 + OpStore %58 %int_0 + OpBranch %46 + %46 = OpLabel + %59 = OpLoad %int %i + %61 = OpIAdd %int %59 %int_1 + OpStore %i %61 + OpBranch %43 + %45 = OpLabel + OpStore %p %63 + OpStore %canwalk %true + OpStore %v %int_0 + OpBranch %68 + %68 = OpLabel + OpLoopMerge %70 %71 None + OpBranch %69 + %69 = OpLabel + %72 = OpLoad %int %v + %73 = OpIAdd %int %72 %int_1 + OpStore %v %73 + OpStore %directions %int_0 + %75 = OpAccessChain %_ptr_Function_int %p %uint_0 + %76 = OpLoad %int %75 + %77 = OpSGreaterThan %bool %76 %int_0 + OpSelectionMerge %79 None + OpBranchConditional %77 %78 %79 + %78 = OpLabel + %80 = OpAccessChain %_ptr_Function_int %p %uint_0 + %81 = OpLoad %int %80 + %83 = OpISub %int %81 %int_2 + %84 = OpAccessChain %_ptr_Function_int %p %uint_1 + %85 = OpLoad %int %84 + %87 = OpIMul %int %85 %int_16 + %88 = OpIAdd %int %83 %87 + %89 = OpAccessChain %_ptr_Private_int %map %88 + %90 = OpLoad %int %89 + %91 = OpIEqual %bool %90 %int_0 + OpBranch %79 + %79 = OpLabel + %92 = OpPhi %bool %77 %69 %91 %78 + OpSelectionMerge %94 None + OpBranchConditional %92 %93 %94 + %93 = OpLabel + %95 = OpLoad %int %directions + %96 = OpIAdd %int %95 %int_1 + OpStore %directions %96 + OpBranch %94 + %94 = OpLabel + %97 = OpAccessChain %_ptr_Function_int %p %uint_1 + %98 = OpLoad %int %97 + %99 = OpSGreaterThan %bool %98 %int_0 + OpSelectionMerge %101 None + OpBranchConditional %99 %100 %101 + %100 = OpLabel + %102 = OpAccessChain %_ptr_Function_int %p %uint_0 + %103 = OpLoad %int %102 + %104 = OpAccessChain %_ptr_Function_int %p %uint_1 + %105 = OpLoad %int %104 + %106 = OpISub %int %105 %int_2 + %107 = OpIMul %int %106 %int_16 + %108 = OpIAdd %int %103 %107 + %109 = OpAccessChain %_ptr_Private_int %map %108 + %110 = OpLoad %int %109 + %111 = OpIEqual %bool %110 %int_0 + OpBranch %101 + %101 = OpLabel + %112 = OpPhi %bool %99 %94 %111 %100 + OpSelectionMerge %114 None + OpBranchConditional %112 %113 %114 + %113 = OpLabel + %115 = OpLoad %int %directions + %116 = OpIAdd %int %115 %int_1 + OpStore %directions %116 + OpBranch %114 + %114 = OpLabel + %117 = OpAccessChain %_ptr_Function_int %p %uint_0 + %118 = OpLoad %int %117 + %120 = OpSLessThan %bool %118 %int_14 + OpSelectionMerge %122 None + OpBranchConditional %120 %121 %122 + %121 = OpLabel + %123 = OpAccessChain %_ptr_Function_int %p %uint_0 + %124 = OpLoad %int %123 + %125 = OpIAdd %int %124 %int_2 + %126 = OpAccessChain %_ptr_Function_int %p %uint_1 + %127 = OpLoad %int %126 + %128 = OpIMul %int %127 %int_16 + %129 = OpIAdd %int %125 %128 + %130 = OpAccessChain %_ptr_Private_int %map %129 + %131 = OpLoad %int %130 + %132 = OpIEqual %bool %131 %int_0 + OpBranch %122 + %122 = OpLabel + %133 = OpPhi %bool %120 %114 %132 %121 + OpSelectionMerge %135 None + OpBranchConditional %133 %134 %135 + %134 = OpLabel + %136 = OpLoad %int %directions + %137 = OpIAdd %int %136 %int_1 + OpStore %directions %137 + OpBranch %135 + %135 = OpLabel + %594 = OpISub %int %int_256 %566 + %138 = OpAccessChain %_ptr_Function_int %p %uint_1 + %139 = OpLoad %int %138 + %140 = OpSLessThan %bool %139 %int_14 + OpSelectionMerge %142 None + OpBranchConditional %140 %141 %142 + %141 = OpLabel + %143 = OpAccessChain %_ptr_Function_int %p %uint_0 + %144 = OpLoad %int %143 + %145 = OpAccessChain %_ptr_Function_int %p %uint_1 + %146 = OpLoad %int %145 + %147 = OpIAdd %int %146 %int_2 + %148 = OpIMul %int %147 %int_16 + %149 = OpIAdd %int %144 %148 + %150 = OpAccessChain %_ptr_Private_int %map %149 + %151 = OpLoad %int %150 + %152 = OpIEqual %bool %151 %int_0 + OpBranch %142 + %142 = OpLabel + %153 = OpPhi %bool %140 %135 %152 %141 + OpSelectionMerge %155 None + OpBranchConditional %153 %154 %155 + %154 = OpLabel + %156 = OpLoad %int %directions + %157 = OpIAdd %int %156 %int_1 + OpStore %directions %157 + OpBranch %155 + %155 = OpLabel + %158 = OpLoad %int %directions + %159 = OpIEqual %bool %158 %int_0 + OpSelectionMerge %161 None + OpBranchConditional %159 %160 %207 + %160 = OpLabel + OpStore %canwalk %false + OpStore %i %int_0 + OpBranch %163 + %163 = OpLabel + OpLoopMerge %165 %166 None + OpBranch %167 + %167 = OpLabel + %168 = OpLoad %int %i + %170 = OpSLessThan %bool %168 %int_8 + OpBranchConditional %170 %164 %165 + %164 = OpLabel + OpStore %j %int_0 + %609 = OpISub %int %594 %168 + OpStore %558 %557 + OpBranchConditional %760 %166 %172 + %172 = OpLabel + OpLoopMerge %174 %175 Unroll + OpBranch %176 + %176 = OpLabel + %177 = OpLoad %int %j + %178 = OpSLessThan %bool %177 %int_8 + OpBranchConditional %178 %173 %174 + %173 = OpLabel + %179 = OpLoad %int %j + %180 = OpIMul %int %179 %int_2 + %181 = OpLoad %int %i + %182 = OpIMul %int %181 %int_2 + %183 = OpIMul %int %182 %int_16 + %184 = OpIAdd %int %180 %183 + %185 = OpAccessChain %_ptr_Private_int %map %184 + %186 = OpLoad %int %185 + %187 = OpIEqual %bool %186 %int_0 + OpSelectionMerge %189 None + OpBranchConditional %187 %188 %189 + %188 = OpLabel + %190 = OpLoad %int %j + %191 = OpIMul %int %190 %int_2 + %192 = OpAccessChain %_ptr_Function_int %p %uint_0 + OpStore %192 %191 + %193 = OpLoad %int %i + %194 = OpIMul %int %193 %int_2 + %195 = OpAccessChain %_ptr_Function_int %p %uint_1 + OpStore %195 %194 + OpStore %canwalk %true + OpBranch %189 + %189 = OpLabel + OpBranch %175 + %175 = OpLabel + %196 = OpLoad %int %j + %197 = OpIAdd %int %196 %int_1 + OpStore %j %197 + OpBranch %172 + %174 = OpLabel + OpBranch %166 + %166 = OpLabel + %198 = OpLoad %int %i + %199 = OpIAdd %int %198 %int_1 + OpStore %i %199 + OpBranch %163 + %165 = OpLabel + %200 = OpAccessChain %_ptr_Function_int %p %uint_0 + %201 = OpLoad %int %200 + %202 = OpAccessChain %_ptr_Function_int %p %uint_1 + %203 = OpLoad %int %202 + %204 = OpIMul %int %203 %int_16 + %205 = OpIAdd %int %201 %204 + %206 = OpAccessChain %_ptr_Private_int %map %205 + OpStore %206 %int_1 + OpBranch %161 + %207 = OpLabel + %209 = OpLoad %int %v + %210 = OpLoad %int %directions + %211 = OpSMod %int %209 %210 + OpStore %d %211 + %212 = OpLoad %int %directions + %213 = OpLoad %int %v + %214 = OpIAdd %int %213 %212 + OpStore %v %214 + %215 = OpLoad %int %d + %216 = OpSGreaterThanEqual %bool %215 %int_0 + OpSelectionMerge %218 None + OpBranchConditional %216 %217 %218 + %217 = OpLabel + %219 = OpAccessChain %_ptr_Function_int %p %uint_0 + %220 = OpLoad %int %219 + %221 = OpSGreaterThan %bool %220 %int_0 + OpBranch %218 + %218 = OpLabel + %222 = OpPhi %bool %216 %207 %221 %217 + OpSelectionMerge %224 None + OpBranchConditional %222 %223 %224 + %223 = OpLabel + %225 = OpAccessChain %_ptr_Function_int %p %uint_0 + %226 = OpLoad %int %225 + %227 = OpISub %int %226 %int_2 + %228 = OpAccessChain %_ptr_Function_int %p %uint_1 + %229 = OpLoad %int %228 + %230 = OpIMul %int %229 %int_16 + %231 = OpIAdd %int %227 %230 + %232 = OpAccessChain %_ptr_Private_int %map %231 + %233 = OpLoad %int %232 + %234 = OpIEqual %bool %233 %int_0 + OpBranch %224 + %224 = OpLabel + %235 = OpPhi %bool %222 %218 %234 %223 + OpSelectionMerge %237 None + OpBranchConditional %235 %236 %237 + %236 = OpLabel + %238 = OpLoad %int %d + %239 = OpISub %int %238 %int_1 + OpStore %d %239 + %240 = OpAccessChain %_ptr_Function_int %p %uint_0 + %241 = OpLoad %int %240 + %242 = OpAccessChain %_ptr_Function_int %p %uint_1 + %243 = OpLoad %int %242 + %244 = OpIMul %int %243 %int_16 + %245 = OpIAdd %int %241 %244 + %246 = OpAccessChain %_ptr_Private_int %map %245 + OpStore %246 %int_1 + %247 = OpAccessChain %_ptr_Function_int %p %uint_0 + %248 = OpLoad %int %247 + %249 = OpISub %int %248 %int_1 + %250 = OpAccessChain %_ptr_Function_int %p %uint_1 + %251 = OpLoad %int %250 + %252 = OpIMul %int %251 %int_16 + %253 = OpIAdd %int %249 %252 + %254 = OpAccessChain %_ptr_Private_int %map %253 + OpStore %254 %int_1 + %255 = OpAccessChain %_ptr_Function_int %p %uint_0 + %256 = OpLoad %int %255 + %257 = OpISub %int %256 %int_2 + %258 = OpAccessChain %_ptr_Function_int %p %uint_1 + %259 = OpLoad %int %258 + %260 = OpIMul %int %259 %int_16 + %261 = OpIAdd %int %257 %260 + %262 = OpAccessChain %_ptr_Private_int %map %261 + OpStore %262 %int_1 + %263 = OpAccessChain %_ptr_Function_int %p %uint_0 + %264 = OpLoad %int %263 + %265 = OpISub %int %264 %int_2 + %266 = OpAccessChain %_ptr_Function_int %p %uint_0 + OpStore %266 %265 + OpBranch %237 + %237 = OpLabel + %267 = OpLoad %int %d + %268 = OpSGreaterThanEqual %bool %267 %int_0 + OpSelectionMerge %270 None + OpBranchConditional %268 %269 %270 + %269 = OpLabel + %271 = OpAccessChain %_ptr_Function_int %p %uint_1 + %272 = OpLoad %int %271 + %273 = OpSGreaterThan %bool %272 %int_0 + OpBranch %270 + %270 = OpLabel + %274 = OpPhi %bool %268 %237 %273 %269 + OpSelectionMerge %276 None + OpBranchConditional %274 %275 %276 + %275 = OpLabel + %277 = OpAccessChain %_ptr_Function_int %p %uint_0 + %278 = OpLoad %int %277 + %279 = OpAccessChain %_ptr_Function_int %p %uint_1 + %280 = OpLoad %int %279 + %281 = OpISub %int %280 %int_2 + %282 = OpIMul %int %281 %int_16 + %283 = OpIAdd %int %278 %282 + %284 = OpAccessChain %_ptr_Private_int %map %283 + %285 = OpLoad %int %284 + %286 = OpIEqual %bool %285 %int_0 + OpBranch %276 + %276 = OpLabel + %287 = OpPhi %bool %274 %270 %286 %275 + OpSelectionMerge %289 None + OpBranchConditional %287 %288 %289 + %288 = OpLabel + %290 = OpLoad %int %d + %291 = OpISub %int %290 %int_1 + OpStore %d %291 + %292 = OpAccessChain %_ptr_Function_int %p %uint_0 + %293 = OpLoad %int %292 + %294 = OpAccessChain %_ptr_Function_int %p %uint_1 + %295 = OpLoad %int %294 + %296 = OpIMul %int %295 %int_16 + %297 = OpIAdd %int %293 %296 + %298 = OpAccessChain %_ptr_Private_int %map %297 + OpStore %298 %int_1 + %299 = OpAccessChain %_ptr_Function_int %p %uint_0 + %300 = OpLoad %int %299 + %301 = OpAccessChain %_ptr_Function_int %p %uint_1 + %302 = OpLoad %int %301 + %303 = OpISub %int %302 %int_1 + %304 = OpIMul %int %303 %int_16 + %305 = OpIAdd %int %300 %304 + %306 = OpAccessChain %_ptr_Private_int %map %305 + OpStore %306 %int_1 + %307 = OpAccessChain %_ptr_Function_int %p %uint_0 + %308 = OpLoad %int %307 + %309 = OpAccessChain %_ptr_Function_int %p %uint_1 + %310 = OpLoad %int %309 + %311 = OpISub %int %310 %int_2 + %312 = OpIMul %int %311 %int_16 + %313 = OpIAdd %int %308 %312 + %314 = OpAccessChain %_ptr_Private_int %map %313 + OpStore %314 %int_1 + %315 = OpAccessChain %_ptr_Function_int %p %uint_1 + %316 = OpLoad %int %315 + %317 = OpISub %int %316 %int_2 + %318 = OpAccessChain %_ptr_Function_int %p %uint_1 + OpStore %318 %317 + OpBranch %289 + %289 = OpLabel + %319 = OpLoad %int %d + %320 = OpSGreaterThanEqual %bool %319 %int_0 + OpSelectionMerge %322 None + OpBranchConditional %320 %321 %322 + %321 = OpLabel + %323 = OpAccessChain %_ptr_Function_int %p %uint_0 + %324 = OpLoad %int %323 + %325 = OpSLessThan %bool %324 %int_14 + OpBranch %322 + %322 = OpLabel + %326 = OpPhi %bool %320 %289 %325 %321 + OpSelectionMerge %328 None + OpBranchConditional %326 %327 %328 + %327 = OpLabel + %329 = OpAccessChain %_ptr_Function_int %p %uint_0 + %330 = OpLoad %int %329 + %331 = OpIAdd %int %330 %int_2 + %332 = OpAccessChain %_ptr_Function_int %p %uint_1 + %333 = OpLoad %int %332 + %334 = OpIMul %int %333 %int_16 + %335 = OpIAdd %int %331 %334 + %336 = OpAccessChain %_ptr_Private_int %map %335 + %337 = OpLoad %int %336 + %338 = OpIEqual %bool %337 %int_0 + OpBranch %328 + %328 = OpLabel + %339 = OpPhi %bool %326 %322 %338 %327 + OpSelectionMerge %341 None + OpBranchConditional %339 %340 %341 + %340 = OpLabel + %342 = OpLoad %int %d + %343 = OpISub %int %342 %int_1 + OpStore %d %343 + %344 = OpAccessChain %_ptr_Function_int %p %uint_0 + %345 = OpLoad %int %344 + %346 = OpAccessChain %_ptr_Function_int %p %uint_1 + %347 = OpLoad %int %346 + %348 = OpIMul %int %347 %int_16 + %349 = OpIAdd %int %345 %348 + %350 = OpAccessChain %_ptr_Private_int %map %349 + OpStore %350 %int_1 + %351 = OpAccessChain %_ptr_Function_int %p %uint_0 + %352 = OpLoad %int %351 + %353 = OpIAdd %int %352 %int_1 + %354 = OpAccessChain %_ptr_Function_int %p %uint_1 + %355 = OpLoad %int %354 + %356 = OpIMul %int %355 %int_16 + %357 = OpIAdd %int %353 %356 + %358 = OpAccessChain %_ptr_Private_int %map %357 + OpStore %358 %int_1 + %359 = OpAccessChain %_ptr_Function_int %p %uint_0 + %360 = OpLoad %int %359 + %361 = OpIAdd %int %360 %int_2 + %362 = OpAccessChain %_ptr_Function_int %p %uint_1 + %363 = OpLoad %int %362 + %364 = OpIMul %int %363 %int_16 + %365 = OpIAdd %int %361 %364 + %366 = OpAccessChain %_ptr_Private_int %map %365 + OpStore %366 %int_1 + %367 = OpAccessChain %_ptr_Function_int %p %uint_0 + %368 = OpLoad %int %367 + %369 = OpIAdd %int %368 %int_2 + %370 = OpAccessChain %_ptr_Function_int %p %uint_0 + OpStore %370 %369 + OpBranch %341 + %341 = OpLabel + %371 = OpLoad %int %d + %372 = OpSGreaterThanEqual %bool %371 %int_0 + OpSelectionMerge %374 None + OpBranchConditional %372 %373 %374 + %373 = OpLabel + %375 = OpAccessChain %_ptr_Function_int %p %uint_1 + %376 = OpLoad %int %375 + %377 = OpSLessThan %bool %376 %int_14 + OpBranch %374 + %374 = OpLabel + %378 = OpPhi %bool %372 %341 %377 %373 + OpSelectionMerge %380 None + OpBranchConditional %378 %379 %380 + %379 = OpLabel + %381 = OpAccessChain %_ptr_Function_int %p %uint_0 + %382 = OpLoad %int %381 + %383 = OpAccessChain %_ptr_Function_int %p %uint_1 + %384 = OpLoad %int %383 + %385 = OpIAdd %int %384 %int_2 + %386 = OpIMul %int %385 %int_16 + %387 = OpIAdd %int %382 %386 + %388 = OpAccessChain %_ptr_Private_int %map %387 + %389 = OpLoad %int %388 + %390 = OpIEqual %bool %389 %int_0 + OpBranch %380 + %380 = OpLabel + %391 = OpPhi %bool %378 %374 %390 %379 + OpSelectionMerge %393 None + OpBranchConditional %391 %392 %393 + %392 = OpLabel + %394 = OpLoad %int %d + %395 = OpISub %int %394 %int_1 + OpStore %d %395 + %396 = OpAccessChain %_ptr_Function_int %p %uint_0 + %397 = OpLoad %int %396 + %398 = OpAccessChain %_ptr_Function_int %p %uint_1 + %399 = OpLoad %int %398 + %400 = OpIMul %int %399 %int_16 + %401 = OpIAdd %int %397 %400 + %402 = OpAccessChain %_ptr_Private_int %map %401 + OpStore %402 %int_1 + %403 = OpAccessChain %_ptr_Function_int %p %uint_0 + %404 = OpLoad %int %403 + %405 = OpAccessChain %_ptr_Function_int %p %uint_1 + %406 = OpLoad %int %405 + %407 = OpIAdd %int %406 %int_1 + %408 = OpIMul %int %407 %int_16 + %409 = OpIAdd %int %404 %408 + %410 = OpAccessChain %_ptr_Private_int %map %409 + OpStore %410 %int_1 + %411 = OpAccessChain %_ptr_Function_int %p %uint_0 + %412 = OpLoad %int %411 + %413 = OpAccessChain %_ptr_Function_int %p %uint_1 + %414 = OpLoad %int %413 + %415 = OpIAdd %int %414 %int_2 + %416 = OpIMul %int %415 %int_16 + %417 = OpIAdd %int %412 %416 + %418 = OpAccessChain %_ptr_Private_int %map %417 + OpStore %418 %int_1 + %419 = OpAccessChain %_ptr_Function_int %p %uint_1 + %420 = OpLoad %int %419 + %421 = OpIAdd %int %420 %int_2 + %422 = OpAccessChain %_ptr_Function_int %p %uint_1 + OpStore %422 %421 + OpBranch %393 + %393 = OpLabel + OpBranch %161 + %161 = OpLabel + %423 = OpAccessChain %_ptr_Function_int %ipos %uint_1 + %424 = OpLoad %int %423 + %425 = OpIMul %int %424 %int_16 + %426 = OpAccessChain %_ptr_Function_int %ipos %uint_0 + %427 = OpLoad %int %426 + %428 = OpIAdd %int %425 %427 + %429 = OpAccessChain %_ptr_Private_int %map %428 + %430 = OpLoad %int %429 + %431 = OpIEqual %bool %430 %int_1 + OpSelectionMerge %433 None + OpBranchConditional %431 %432 %433 + %432 = OpLabel + OpStore %_GLF_color %437 + OpReturn + %433 = OpLabel + OpBranch %71 + %71 = OpLabel + %439 = OpLoad %bool %canwalk + OpBranchConditional %439 %68 %70 + %70 = OpLabel + OpStore %_GLF_color %441 + OpReturn + OpFunctionEnd diff --git a/shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag b/shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag new file mode 100644 index 00000000..6f9192cd --- /dev/null +++ b/shaders-no-opt/asm/frag/late-expression-invalidation.asm.frag @@ -0,0 +1,109 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos SPIR-V Tools Assembler; 0 +; Bound: 68 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord %_GLF_color + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %gl_FragCoord "gl_FragCoord" + OpName %_GLF_color "_GLF_color" + OpName %m "m" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_GLF_color Location 0 + %void = OpTypeVoid + %7 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %float_10 = OpConstant %float 10 + %bool = OpTypeBool +%_ptr_Output_v4float = OpTypePointer Output %v4float + %_GLF_color = OpVariable %_ptr_Output_v4float Output + %float_1 = OpConstant %float 1 + %float_0 = OpConstant %float 0 + %19 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1 +%mat4v4float = OpTypeMatrix %v4float 4 + %21 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %22 = OpConstantComposite %mat4v4float %21 %21 %21 %21 + %uint_4 = OpConstant %uint 4 +%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4 +%_ptr_Function__arr_mat4v4float_uint_4 = OpTypePointer Function %_arr_mat4v4float_uint_4 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_4 = OpConstant %int 4 + %v2float = OpTypeVector %float 2 + %30 = OpConstantComposite %v2float %float_1 %float_1 + %int_1 = OpConstant %int 1 + %uint_3 = OpConstant %uint 3 +%_ptr_Function_float = OpTypePointer Function %float + %34 = OpConstantComposite %_arr_mat4v4float_uint_4 %22 %22 %22 %22 + %main = OpFunction %void None %7 + %35 = OpLabel + %m = OpVariable %_ptr_Function__arr_mat4v4float_uint_4 Function + OpBranch %36 + %36 = OpLabel + OpLoopMerge %37 %38 None + OpBranch %39 + %39 = OpLabel + %40 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %41 = OpLoad %float %40 + %42 = OpFOrdLessThan %bool %41 %float_10 + OpSelectionMerge %43 None + OpBranchConditional %42 %44 %43 + %44 = OpLabel + OpStore %_GLF_color %19 + OpBranch %37 + %43 = OpLabel + OpStore %m %34 + OpBranch %45 + %45 = OpLabel + %46 = OpPhi %int %int_0 %43 %47 %48 + %49 = OpSLessThan %bool %46 %int_4 + OpLoopMerge %50 %48 None + OpBranchConditional %49 %51 %50 + %51 = OpLabel + OpBranch %52 + %52 = OpLabel + %53 = OpPhi %int %int_0 %51 %54 %55 + %56 = OpSLessThan %bool %53 %int_4 + OpLoopMerge %57 %55 None + OpBranchConditional %56 %58 %57 + %58 = OpLabel + %59 = OpSelect %int %56 %int_1 %int_0 + %60 = OpAccessChain %_ptr_Function_float %m %59 %46 %uint_3 + %61 = OpLoad %float %60 + %62 = OpCompositeConstruct %v2float %61 %61 + %63 = OpFDiv %v2float %30 %62 + %64 = OpExtInst %float %1 Distance %30 %63 + %65 = OpFOrdLessThan %bool %64 %float_1 + OpSelectionMerge %66 None + OpBranchConditional %65 %67 %55 + %67 = OpLabel + OpStore %_GLF_color %21 + OpBranch %55 + %66 = OpLabel + OpBranch %55 + %55 = OpLabel + %54 = OpIAdd %int %53 %int_1 + OpBranch %52 + %57 = OpLabel + OpBranch %48 + %48 = OpLabel + %47 = OpIAdd %int %46 %int_1 + OpBranch %45 + %50 = OpLabel + OpBranch %37 + %38 = OpLabel + OpBranch %36 + %37 = OpLabel + OpReturn + OpFunctionEnd diff --git a/spirv_cpp.cpp b/spirv_cpp.cpp index b7946bf3..8d934d2c 100644 --- a/spirv_cpp.cpp +++ b/spirv_cpp.cpp @@ -338,11 +338,8 @@ string CompilerCPP::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - resource_registrations.clear(); - reset(); + reset(pass_count); // Move constructor for this type is broken on GCC 4.9 ... buffer.reset(); diff --git a/spirv_cross.cpp b/spirv_cross.cpp index db18bb44..cf60197e 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -4828,6 +4828,12 @@ void Compiler::force_recompile() is_force_recompile = true; } +void Compiler::force_recompile_guarantee_forward_progress() +{ + force_recompile(); + is_force_recompile_forward_progress = true; +} + bool Compiler::is_forcing_recompilation() const { return is_force_recompile; @@ -4836,6 +4842,7 @@ bool Compiler::is_forcing_recompilation() const void Compiler::clear_force_recompile() { is_force_recompile = false; + is_force_recompile_forward_progress = false; } Compiler::PhysicalStorageBufferPointerHandler::PhysicalStorageBufferPointerHandler(Compiler &compiler_) diff --git a/spirv_cross.hpp b/spirv_cross.hpp index af8283d9..4a881197 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -735,9 +735,11 @@ protected: SPIRBlock::ContinueBlockType continue_block_type(const SPIRBlock &continue_block) const; void force_recompile(); + void force_recompile_guarantee_forward_progress(); void clear_force_recompile(); bool is_forcing_recompilation() const; bool is_force_recompile = false; + bool is_force_recompile_forward_progress = false; bool block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method method) const; diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index a96c9671..aae23803 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -296,8 +296,19 @@ const char *CompilerGLSL::vector_swizzle(int vecsize, int index) return swizzle[vecsize - 1][index]; } -void CompilerGLSL::reset() -{ +void CompilerGLSL::reset(uint32_t iteration_count) +{ + // Sanity check the iteration count to be robust against a certain class of bugs where + // we keep forcing recompilations without making clear forward progress. + // In buggy situations we will loop forever, or loop for an unbounded number of iterations. + // Certain types of recompilations are considered to make forward progress, + // but in almost all situations, we'll never see more than 3 iterations. + // It is highly context-sensitive when we need to force recompilation, + // and it is not practical with the current architecture + // to resolve everything up front. + if (iteration_count >= 3 && !is_force_recompile_forward_progress) + SPIRV_CROSS_THROW("Over 3 compilation loops detected and no forward progress was made. Must be a bug!"); + // We do some speculative optimizations which should pretty much always work out, // but just in case the SPIR-V is rather weird, recompile until it's happy. // This typically only means one extra pass. @@ -664,10 +675,7 @@ string CompilerGLSL::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - - reset(); + reset(pass_count); buffer.reset(); @@ -4291,8 +4299,13 @@ void CompilerGLSL::handle_invalid_expression(uint32_t id) { // We tried to read an invalidated expression. // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated. - forced_temporaries.insert(id); - force_recompile(); + auto res = forced_temporaries.insert(id); + + // Forcing new temporaries guarantees forward progress. + if (res.second) + force_recompile_guarantee_forward_progress(); + else + force_recompile(); } // Converts the format of the current expression from packed to unpacked, @@ -14752,7 +14765,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) // as writes to said loop variables might have been masked out, we need a recompile. if (!emitted_loop_header_variables && !block.loop_variables.empty()) { - force_recompile(); + force_recompile_guarantee_forward_progress(); for (auto var : block.loop_variables) get<SPIRVariable>(var).loop_variable = false; block.loop_variables.clear(); diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index bf7bf38f..496d8cf9 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -342,7 +342,7 @@ protected: // TODO remove this function when all subgroup ops are supported (or make it always return true) static bool is_supported_subgroup_op_in_opengl(spv::Op op); - void reset(); + void reset(uint32_t iteration_count); void emit_function(SPIRFunction &func, const Bitset &return_flags); bool has_extension(const std::string &ext) const; diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp index f8171a24..efd8f99f 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp @@ -5801,10 +5801,7 @@ string CompilerHLSL::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - - reset(); + reset(pass_count); // Move constructor for this type is broken on GCC 4.9 ... buffer.reset(); diff --git a/spirv_msl.cpp b/spirv_msl.cpp index c0bfc5e3..4abb437f 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -1446,10 +1446,7 @@ string CompilerMSL::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - - reset(); + reset(pass_count); // Start bindings at zero. next_metal_resource_index_buffer = 0; |