summaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/backend/glasm/emit_context.h1
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.cpp17
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp8
-rw-r--r--src/shader_recompiler/backend/glsl/emit_context.h2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl.cpp11
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_instructions.h2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp19
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp8
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h2
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp8
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h3
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc2
-rw-r--r--src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp37
-rw-r--r--src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp32
16 files changed, 54 insertions, 108 deletions
diff --git a/src/shader_recompiler/backend/glasm/emit_context.h b/src/shader_recompiler/backend/glasm/emit_context.h
index cd4213cb7..9f86e55d3 100644
--- a/src/shader_recompiler/backend/glasm/emit_context.h
+++ b/src/shader_recompiler/backend/glasm/emit_context.h
@@ -71,6 +71,7 @@ public:
71 std::string_view stage_name = "invalid"; 71 std::string_view stage_name = "invalid";
72 std::string_view attrib_name = "invalid"; 72 std::string_view attrib_name = "invalid";
73 73
74 u32 num_safety_loop_vars{};
74 bool uses_y_direction{}; 75 bool uses_y_direction{};
75}; 76};
76 77
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index f39b02f77..79314f130 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -6,6 +6,8 @@
6#include <string> 6#include <string>
7#include <tuple> 7#include <tuple>
8 8
9#include "common/div_ceil.h"
10#include "common/settings.h"
9#include "shader_recompiler/backend/bindings.h" 11#include "shader_recompiler/backend/bindings.h"
10#include "shader_recompiler/backend/glasm/emit_context.h" 12#include "shader_recompiler/backend/glasm/emit_context.h"
11#include "shader_recompiler/backend/glasm/emit_glasm.h" 13#include "shader_recompiler/backend/glasm/emit_glasm.h"
@@ -222,6 +224,14 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
222 ctx.Add("REP;"); 224 ctx.Add("REP;");
223 break; 225 break;
224 case IR::AbstractSyntaxNode::Type::Repeat: 226 case IR::AbstractSyntaxNode::Type::Repeat:
227 if (!Settings::values.disable_shader_loop_safety_checks) {
228 const u32 loop_index{ctx.num_safety_loop_vars++};
229 const u32 vector_index{loop_index / 4};
230 const char component{"xyzw"[loop_index % 4]};
231 ctx.Add("SUB.S.CC loop{}.{},loop{}.{},1;"
232 "BRK(LT.{});",
233 vector_index, component, vector_index, component, component);
234 }
225 if (node.data.repeat.cond.IsImmediate()) { 235 if (node.data.repeat.cond.IsImmediate()) {
226 if (node.data.repeat.cond.U1()) { 236 if (node.data.repeat.cond.U1()) {
227 ctx.Add("ENDREP;"); 237 ctx.Add("ENDREP;");
@@ -425,6 +435,10 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
425 if (program.info.uses_fswzadd) { 435 if (program.info.uses_fswzadd) {
426 header += "FSWZA[4],FSWZB[4],"; 436 header += "FSWZA[4],FSWZB[4],";
427 } 437 }
438 const u32 num_safety_loop_vectors{Common::DivCeil(ctx.num_safety_loop_vars, 4u)};
439 for (u32 index = 0; index < num_safety_loop_vectors; ++index) {
440 header += fmt::format("loop{},", index);
441 }
428 header += "RC;" 442 header += "RC;"
429 "LONG TEMP "; 443 "LONG TEMP ";
430 for (size_t index = 0; index < ctx.reg_alloc.NumUsedLongRegisters(); ++index) { 444 for (size_t index = 0; index < ctx.reg_alloc.NumUsedLongRegisters(); ++index) {
@@ -441,6 +455,9 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
441 "MOV.F FSWZB[2],1;" 455 "MOV.F FSWZB[2],1;"
442 "MOV.F FSWZB[3],-1;"; 456 "MOV.F FSWZB[3],-1;";
443 } 457 }
458 for (u32 index = 0; index < num_safety_loop_vectors; ++index) {
459 header += fmt::format("MOV.S loop{},{{0x2000,0x2000,0x2000,0x2000}};", index);
460 }
444 if (ctx.uses_y_direction) { 461 if (ctx.uses_y_direction) {
445 header += "PARAM y_direction[1]={state.material.front.ambient};"; 462 header += "PARAM y_direction[1]={state.material.front.ambient};";
446 } 463 }
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index fef9ff9be..c9f4826ce 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -42,8 +42,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
42void EmitGetGotoVariable(EmitContext& ctx); 42void EmitGetGotoVariable(EmitContext& ctx);
43void EmitSetIndirectBranchVariable(EmitContext& ctx); 43void EmitSetIndirectBranchVariable(EmitContext& ctx);
44void EmitGetIndirectBranchVariable(EmitContext& ctx); 44void EmitGetIndirectBranchVariable(EmitContext& ctx);
45void EmitSetLoopSafetyVariable(EmitContext& ctx);
46void EmitGetLoopSafetyVariable(EmitContext& ctx);
47void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 45void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
48void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 46void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
49void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); 47void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
index a487a0744..ff64c6924 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp
@@ -153,14 +153,6 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
153 NotImplemented(); 153 NotImplemented();
154} 154}
155 155
156void EmitSetLoopSafetyVariable(EmitContext& ctx) {
157 NotImplemented();
158}
159
160void EmitGetLoopSafetyVariable(EmitContext& ctx) {
161 NotImplemented();
162}
163
164void EmitGetZFlag(EmitContext& ctx) { 156void EmitGetZFlag(EmitContext& ctx) {
165 NotImplemented(); 157 NotImplemented();
166} 158}
diff --git a/src/shader_recompiler/backend/glsl/emit_context.h b/src/shader_recompiler/backend/glsl/emit_context.h
index 8fa87c02c..ecdf6e5bc 100644
--- a/src/shader_recompiler/backend/glsl/emit_context.h
+++ b/src/shader_recompiler/backend/glsl/emit_context.h
@@ -153,6 +153,8 @@ public:
153 std::vector<TextureImageDefinition> images; 153 std::vector<TextureImageDefinition> images;
154 std::array<std::array<GenericElementInfo, 4>, 32> output_generics{}; 154 std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
155 155
156 u32 num_safety_loop_vars{};
157
156 bool uses_y_direction{}; 158 bool uses_y_direction{};
157 bool uses_cc_carry{}; 159 bool uses_cc_carry{};
158 160
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
index ff869923f..32c4f1da2 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
@@ -6,6 +6,7 @@
6#include <string> 6#include <string>
7 7
8#include "common/alignment.h" 8#include "common/alignment.h"
9#include "common/settings.h"
9#include "shader_recompiler/backend/glsl/emit_context.h" 10#include "shader_recompiler/backend/glsl/emit_context.h"
10#include "shader_recompiler/backend/glsl/emit_glsl.h" 11#include "shader_recompiler/backend/glsl/emit_glsl.h"
11#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" 12#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
@@ -156,7 +157,12 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
156 ctx.Add("for(;;){{"); 157 ctx.Add("for(;;){{");
157 break; 158 break;
158 case IR::AbstractSyntaxNode::Type::Repeat: 159 case IR::AbstractSyntaxNode::Type::Repeat:
159 ctx.Add("if(!{}){{break;}}}}", ctx.var_alloc.Consume(node.data.repeat.cond)); 160 if (Settings::values.disable_shader_loop_safety_checks) {
161 ctx.Add("if(!{}){{break;}}}}", ctx.var_alloc.Consume(node.data.repeat.cond));
162 } else {
163 ctx.Add("if(--loop{}<0 || !{}){{break;}}}}", ctx.num_safety_loop_vars++,
164 ctx.var_alloc.Consume(node.data.repeat.cond));
165 }
160 break; 166 break;
161 default: 167 default:
162 throw NotImplementedException("AbstractSyntaxNode Type {}", node.type); 168 throw NotImplementedException("AbstractSyntaxNode Type {}", node.type);
@@ -198,6 +204,9 @@ void DefineVariables(const EmitContext& ctx, std::string& header) {
198 ctx.var_alloc.Representation(index, type), type_name); 204 ctx.var_alloc.Representation(index, type), type_name);
199 } 205 }
200 } 206 }
207 for (u32 i = 0; i < ctx.num_safety_loop_vars; ++i) {
208 header += fmt::format("int loop{}=0x2000;", i);
209 }
201} 210}
202} // Anonymous namespace 211} // Anonymous namespace
203 212
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index df28036e4..6a30785bb 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -44,8 +44,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
44void EmitGetGotoVariable(EmitContext& ctx); 44void EmitGetGotoVariable(EmitContext& ctx);
45void EmitSetIndirectBranchVariable(EmitContext& ctx); 45void EmitSetIndirectBranchVariable(EmitContext& ctx);
46void EmitGetIndirectBranchVariable(EmitContext& ctx); 46void EmitGetIndirectBranchVariable(EmitContext& ctx);
47void EmitSetLoopSafetyVariable(EmitContext& ctx);
48void EmitGetLoopSafetyVariable(EmitContext& ctx);
49void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 47void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
50 const IR::Value& offset); 48 const IR::Value& offset);
51void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, 49void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
index 0a28a1ffc..f420fe388 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
@@ -46,14 +46,6 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
46 NotImplemented(); 46 NotImplemented();
47} 47}
48 48
49void EmitSetLoopSafetyVariable(EmitContext& ctx) {
50 NotImplemented();
51}
52
53void EmitGetLoopSafetyVariable(EmitContext& ctx) {
54 NotImplemented();
55}
56
57void EmitGetZFlag(EmitContext& ctx) { 49void EmitGetZFlag(EmitContext& ctx) {
58 NotImplemented(); 50 NotImplemented();
59} 51}
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index fd59b4d0a..278c262f8 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -8,6 +8,7 @@
8#include <utility> 8#include <utility>
9#include <vector> 9#include <vector>
10 10
11#include "common/settings.h"
11#include "shader_recompiler/backend/spirv/emit_spirv.h" 12#include "shader_recompiler/backend/spirv/emit_spirv.h"
12#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" 13#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
13#include "shader_recompiler/frontend/ir/basic_block.h" 14#include "shader_recompiler/frontend/ir/basic_block.h"
@@ -151,9 +152,25 @@ void Traverse(EmitContext& ctx, IR::Program& program) {
151 } 152 }
152 break; 153 break;
153 case IR::AbstractSyntaxNode::Type::Repeat: { 154 case IR::AbstractSyntaxNode::Type::Repeat: {
155 Id cond{ctx.Def(node.data.repeat.cond)};
156 if (!Settings::values.disable_shader_loop_safety_checks) {
157 const Id pointer_type{ctx.TypePointer(spv::StorageClass::Private, ctx.U32[1])};
158 const Id safety_counter{ctx.AddGlobalVariable(
159 pointer_type, spv::StorageClass::Private, ctx.Const(0x2000u))};
160 if (ctx.profile.supported_spirv >= 0x00010400) {
161 ctx.interfaces.push_back(safety_counter);
162 }
163 const Id old_counter{ctx.OpLoad(ctx.U32[1], safety_counter)};
164 const Id new_counter{ctx.OpISub(ctx.U32[1], old_counter, ctx.Const(1u))};
165 ctx.OpStore(safety_counter, new_counter);
166
167 const Id safety_cond{
168 ctx.OpSGreaterThanEqual(ctx.U1, new_counter, ctx.u32_zero_value)};
169 cond = ctx.OpLogicalAnd(ctx.U1, cond, safety_cond);
170 }
154 const Id loop_header_label{node.data.repeat.loop_header->Definition<Id>()}; 171 const Id loop_header_label{node.data.repeat.loop_header->Definition<Id>()};
155 const Id merge_label{node.data.repeat.merge->Definition<Id>()}; 172 const Id merge_label{node.data.repeat.merge->Definition<Id>()};
156 ctx.OpBranchConditional(ctx.Def(node.data.repeat.cond), loop_header_label, merge_label); 173 ctx.OpBranchConditional(cond, loop_header_label, merge_label);
157 break; 174 break;
158 } 175 }
159 case IR::AbstractSyntaxNode::Type::Return: 176 case IR::AbstractSyntaxNode::Type::Return:
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 2e364baec..85bd72389 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -198,14 +198,6 @@ void EmitGetIndirectBranchVariable(EmitContext&) {
198 throw LogicError("Unreachable instruction"); 198 throw LogicError("Unreachable instruction");
199} 199}
200 200
201void EmitSetLoopSafetyVariable(EmitContext&) {
202 throw LogicError("Unreachable instruction");
203}
204
205void EmitGetLoopSafetyVariable(EmitContext&) {
206 throw LogicError("Unreachable instruction");
207}
208
209Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 201Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
210 if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) { 202 if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
211 const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)}; 203 const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)};
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index e3e5b03fe..1181e7b4f 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -43,8 +43,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
43void EmitGetGotoVariable(EmitContext& ctx); 43void EmitGetGotoVariable(EmitContext& ctx);
44void EmitSetIndirectBranchVariable(EmitContext& ctx); 44void EmitSetIndirectBranchVariable(EmitContext& ctx);
45void EmitGetIndirectBranchVariable(EmitContext& ctx); 45void EmitGetIndirectBranchVariable(EmitContext& ctx);
46void EmitSetLoopSafetyVariable(EmitContext& ctx);
47void EmitGetLoopSafetyVariable(EmitContext& ctx);
48Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 46Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
49Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 47Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
50Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 48Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index d2ac2acac..2e75208e6 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -147,14 +147,6 @@ void IREmitter::SetIndirectBranchVariable(const U32& value) {
147 Inst(Opcode::SetIndirectBranchVariable, value); 147 Inst(Opcode::SetIndirectBranchVariable, value);
148} 148}
149 149
150U32 IREmitter::GetLoopSafetyVariable(u32 id) {
151 return Inst<U32>(Opcode::GetLoopSafetyVariable, id);
152}
153
154void IREmitter::SetLoopSafetyVariable(u32 id, const U32& counter) {
155 Inst(Opcode::SetLoopSafetyVariable, id, counter);
156}
157
158U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) { 150U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) {
159 return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset); 151 return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset);
160} 152}
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 7caab1f61..bb3500c54 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -55,9 +55,6 @@ public:
55 [[nodiscard]] U32 GetIndirectBranchVariable(); 55 [[nodiscard]] U32 GetIndirectBranchVariable();
56 void SetIndirectBranchVariable(const U32& value); 56 void SetIndirectBranchVariable(const U32& value);
57 57
58 [[nodiscard]] U32 GetLoopSafetyVariable(u32 id);
59 void SetLoopSafetyVariable(u32 id, const U32& counter);
60
61 [[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset); 58 [[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset);
62 [[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize, 59 [[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
63 bool is_signed); 60 bool is_signed);
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index e87aeddd5..8a8d0d759 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -32,8 +32,6 @@ OPCODE(GetGotoVariable, U1, U32,
32OPCODE(SetGotoVariable, Void, U32, U1, ) 32OPCODE(SetGotoVariable, Void, U32, U1, )
33OPCODE(GetIndirectBranchVariable, U32, ) 33OPCODE(GetIndirectBranchVariable, U32, )
34OPCODE(SetIndirectBranchVariable, Void, U32, ) 34OPCODE(SetIndirectBranchVariable, Void, U32, )
35OPCODE(GetLoopSafetyVariable, U32, U32, )
36OPCODE(SetLoopSafetyVariable, Void, U32, U32, )
37OPCODE(GetCbufU8, U32, U32, U32, ) 35OPCODE(GetCbufU8, U32, U32, U32, )
38OPCODE(GetCbufS8, U32, U32, U32, ) 36OPCODE(GetCbufS8, U32, U32, U32, )
39OPCODE(GetCbufU16, U32, U32, U32, ) 37OPCODE(GetCbufU16, U32, U32, U32, )
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index 0fb870a69..10d05dc4c 100644
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -15,7 +15,6 @@
15 15
16#include <boost/intrusive/list.hpp> 16#include <boost/intrusive/list.hpp>
17 17
18#include "common/settings.h"
19#include "shader_recompiler/environment.h" 18#include "shader_recompiler/environment.h"
20#include "shader_recompiler/frontend/ir/basic_block.h" 19#include "shader_recompiler/frontend/ir/basic_block.h"
21#include "shader_recompiler/frontend/ir/ir_emitter.h" 20#include "shader_recompiler/frontend/ir/ir_emitter.h"
@@ -663,7 +662,7 @@ public:
663 Visit(root_stmt, nullptr, nullptr); 662 Visit(root_stmt, nullptr, nullptr);
664 663
665 IR::Block& first_block{*syntax_list.front().data.block}; 664 IR::Block& first_block{*syntax_list.front().data.block};
666 IR::IREmitter ir = IR::IREmitter(first_block, first_block.begin()); 665 IR::IREmitter ir(first_block, first_block.begin());
667 ir.Prologue(); 666 ir.Prologue();
668 } 667 }
669 668
@@ -741,27 +740,8 @@ private:
741 } 740 }
742 case StatementType::Loop: { 741 case StatementType::Loop: {
743 IR::Block* const loop_header_block{block_pool.Create(inst_pool)}; 742 IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
744 const u32 this_loop_id{loop_id++}; 743 if (current_block) {
745 744 current_block->AddBranch(loop_header_block);
746 if (Settings::values.disable_shader_loop_safety_checks) {
747 if (current_block) {
748 current_block->AddBranch(loop_header_block);
749 }
750 } else {
751 IR::Block* const init_block{block_pool.Create(inst_pool)};
752 IR::IREmitter ir{*init_block};
753
754 static constexpr u32 SAFETY_THRESHOLD = 0x1000;
755 ir.SetLoopSafetyVariable(this_loop_id, ir.Imm32(SAFETY_THRESHOLD));
756
757 if (current_block) {
758 current_block->AddBranch(init_block);
759 }
760 init_block->AddBranch(loop_header_block);
761
762 auto& init_node{syntax_list.emplace_back()};
763 init_node.type = IR::AbstractSyntaxNode::Type::Block;
764 init_node.data.block = init_block;
765 } 745 }
766 auto& header_node{syntax_list.emplace_back()}; 746 auto& header_node{syntax_list.emplace_back()};
767 header_node.type = IR::AbstractSyntaxNode::Type::Block; 747 header_node.type = IR::AbstractSyntaxNode::Type::Block;
@@ -779,16 +759,7 @@ private:
779 759
780 // The continue block is located at the end of the loop 760 // The continue block is located at the end of the loop
781 IR::IREmitter ir{*continue_block}; 761 IR::IREmitter ir{*continue_block};
782 IR::U1 cond{VisitExpr(ir, *stmt.cond)}; 762 const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))};
783 if (!Settings::values.disable_shader_loop_safety_checks) {
784 const IR::U32 old_counter{ir.GetLoopSafetyVariable(this_loop_id)};
785 const IR::U32 new_counter{ir.ISub(old_counter, ir.Imm32(1))};
786 ir.SetLoopSafetyVariable(this_loop_id, new_counter);
787
788 const IR::U1 safety_cond{ir.INotEqual(new_counter, ir.Imm32(0))};
789 cond = ir.LogicalAnd(cond, safety_cond);
790 }
791 cond = ir.ConditionRef(cond);
792 763
793 IR::Block* const body_block{syntax_list.at(body_block_index).data.block}; 764 IR::Block* const body_block{syntax_list.at(body_block_index).data.block};
794 loop_header_block->AddBranch(body_block); 765 loop_header_block->AddBranch(body_block);
diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
index fff25c4a2..dcaced83f 100644
--- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
+++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp
@@ -48,22 +48,12 @@ struct GotoVariable : FlagTag {
48 u32 index; 48 u32 index;
49}; 49};
50 50
51struct LoopSafetyVariable {
52 LoopSafetyVariable() = default;
53 explicit LoopSafetyVariable(u32 index_) : index{index_} {}
54
55 auto operator<=>(const LoopSafetyVariable&) const noexcept = default;
56
57 u32 index;
58};
59
60struct IndirectBranchVariable { 51struct IndirectBranchVariable {
61 auto operator<=>(const IndirectBranchVariable&) const noexcept = default; 52 auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
62}; 53};
63 54
64using Variant = 55using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag,
65 std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag, 56 OverflowFlagTag, GotoVariable, IndirectBranchVariable>;
66 GotoVariable, LoopSafetyVariable, IndirectBranchVariable>;
67using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>; 57using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>;
68 58
69struct DefTable { 59struct DefTable {
@@ -88,13 +78,6 @@ struct DefTable {
88 goto_vars[variable.index].insert_or_assign(block, value); 78 goto_vars[variable.index].insert_or_assign(block, value);
89 } 79 }
90 80
91 const IR::Value& Def(IR::Block* block, LoopSafetyVariable variable) {
92 return loop_safety_vars[variable.index][block];
93 }
94 void SetDef(IR::Block* block, LoopSafetyVariable variable, const IR::Value& value) {
95 loop_safety_vars[variable.index].insert_or_assign(block, value);
96 }
97
98 const IR::Value& Def(IR::Block* block, IndirectBranchVariable) { 81 const IR::Value& Def(IR::Block* block, IndirectBranchVariable) {
99 return indirect_branch_var[block]; 82 return indirect_branch_var[block];
100 } 83 }
@@ -132,7 +115,6 @@ struct DefTable {
132 115
133 std::array<ValueMap, IR::NUM_USER_PREDS> preds; 116 std::array<ValueMap, IR::NUM_USER_PREDS> preds;
134 boost::container::flat_map<u32, ValueMap> goto_vars; 117 boost::container::flat_map<u32, ValueMap> goto_vars;
135 boost::container::flat_map<u32, ValueMap> loop_safety_vars;
136 ValueMap indirect_branch_var; 118 ValueMap indirect_branch_var;
137 ValueMap zero_flag; 119 ValueMap zero_flag;
138 ValueMap sign_flag; 120 ValueMap sign_flag;
@@ -152,10 +134,6 @@ IR::Opcode UndefOpcode(const FlagTag&) noexcept {
152 return IR::Opcode::UndefU1; 134 return IR::Opcode::UndefU1;
153} 135}
154 136
155IR::Opcode UndefOpcode(const LoopSafetyVariable&) noexcept {
156 return IR::Opcode::UndefU32;
157}
158
159IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept { 137IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
160 return IR::Opcode::UndefU32; 138 return IR::Opcode::UndefU32;
161} 139}
@@ -337,9 +315,6 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
337 case IR::Opcode::SetGotoVariable: 315 case IR::Opcode::SetGotoVariable:
338 pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1)); 316 pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
339 break; 317 break;
340 case IR::Opcode::SetLoopSafetyVariable:
341 pass.WriteVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
342 break;
343 case IR::Opcode::SetIndirectBranchVariable: 318 case IR::Opcode::SetIndirectBranchVariable:
344 pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0)); 319 pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0));
345 break; 320 break;
@@ -368,9 +343,6 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
368 case IR::Opcode::GetGotoVariable: 343 case IR::Opcode::GetGotoVariable:
369 inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block)); 344 inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block));
370 break; 345 break;
371 case IR::Opcode::GetLoopSafetyVariable:
372 inst.ReplaceUsesWith(pass.ReadVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block));
373 break;
374 case IR::Opcode::GetIndirectBranchVariable: 346 case IR::Opcode::GetIndirectBranchVariable:
375 inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block)); 347 inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block));
376 break; 348 break;