diff options
| author | 2021-06-21 01:07:10 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:39 -0400 | |
| commit | 808ef97a086e7cc58a3ceded1de516ad6a6be5d3 (patch) | |
| tree | b79be02801ddadb44940d2c77fa0ae5c571dc557 /src | |
| parent | gl_graphics_pipeline: Fix assembly shaders check for transform feedbacks (diff) | |
| download | yuzu-808ef97a086e7cc58a3ceded1de516ad6a6be5d3.tar.gz yuzu-808ef97a086e7cc58a3ceded1de516ad6a6be5d3.tar.xz yuzu-808ef97a086e7cc58a3ceded1de516ad6a6be5d3.zip | |
shader: Move loop safety tests to code emission
Diffstat (limited to 'src')
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); | |||
| 42 | void EmitGetGotoVariable(EmitContext& ctx); | 42 | void EmitGetGotoVariable(EmitContext& ctx); |
| 43 | void EmitSetIndirectBranchVariable(EmitContext& ctx); | 43 | void EmitSetIndirectBranchVariable(EmitContext& ctx); |
| 44 | void EmitGetIndirectBranchVariable(EmitContext& ctx); | 44 | void EmitGetIndirectBranchVariable(EmitContext& ctx); |
| 45 | void EmitSetLoopSafetyVariable(EmitContext& ctx); | ||
| 46 | void EmitGetLoopSafetyVariable(EmitContext& ctx); | ||
| 47 | void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); | 45 | void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); |
| 48 | void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); | 46 | void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); |
| 49 | void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); | 47 | void 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 | ||
| 156 | void EmitSetLoopSafetyVariable(EmitContext& ctx) { | ||
| 157 | NotImplemented(); | ||
| 158 | } | ||
| 159 | |||
| 160 | void EmitGetLoopSafetyVariable(EmitContext& ctx) { | ||
| 161 | NotImplemented(); | ||
| 162 | } | ||
| 163 | |||
| 164 | void EmitGetZFlag(EmitContext& ctx) { | 156 | void 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); | |||
| 44 | void EmitGetGotoVariable(EmitContext& ctx); | 44 | void EmitGetGotoVariable(EmitContext& ctx); |
| 45 | void EmitSetIndirectBranchVariable(EmitContext& ctx); | 45 | void EmitSetIndirectBranchVariable(EmitContext& ctx); |
| 46 | void EmitGetIndirectBranchVariable(EmitContext& ctx); | 46 | void EmitGetIndirectBranchVariable(EmitContext& ctx); |
| 47 | void EmitSetLoopSafetyVariable(EmitContext& ctx); | ||
| 48 | void EmitGetLoopSafetyVariable(EmitContext& ctx); | ||
| 49 | void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 47 | void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 50 | const IR::Value& offset); | 48 | const IR::Value& offset); |
| 51 | void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 49 | void 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 | ||
| 49 | void EmitSetLoopSafetyVariable(EmitContext& ctx) { | ||
| 50 | NotImplemented(); | ||
| 51 | } | ||
| 52 | |||
| 53 | void EmitGetLoopSafetyVariable(EmitContext& ctx) { | ||
| 54 | NotImplemented(); | ||
| 55 | } | ||
| 56 | |||
| 57 | void EmitGetZFlag(EmitContext& ctx) { | 49 | void 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 | ||
| 201 | void EmitSetLoopSafetyVariable(EmitContext&) { | ||
| 202 | throw LogicError("Unreachable instruction"); | ||
| 203 | } | ||
| 204 | |||
| 205 | void EmitGetLoopSafetyVariable(EmitContext&) { | ||
| 206 | throw LogicError("Unreachable instruction"); | ||
| 207 | } | ||
| 208 | |||
| 209 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 201 | Id 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); | |||
| 43 | void EmitGetGotoVariable(EmitContext& ctx); | 43 | void EmitGetGotoVariable(EmitContext& ctx); |
| 44 | void EmitSetIndirectBranchVariable(EmitContext& ctx); | 44 | void EmitSetIndirectBranchVariable(EmitContext& ctx); |
| 45 | void EmitGetIndirectBranchVariable(EmitContext& ctx); | 45 | void EmitGetIndirectBranchVariable(EmitContext& ctx); |
| 46 | void EmitSetLoopSafetyVariable(EmitContext& ctx); | ||
| 47 | void EmitGetLoopSafetyVariable(EmitContext& ctx); | ||
| 48 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | 46 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); |
| 49 | Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | 47 | Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); |
| 50 | Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | 48 | Id 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 | ||
| 150 | U32 IREmitter::GetLoopSafetyVariable(u32 id) { | ||
| 151 | return Inst<U32>(Opcode::GetLoopSafetyVariable, id); | ||
| 152 | } | ||
| 153 | |||
| 154 | void IREmitter::SetLoopSafetyVariable(u32 id, const U32& counter) { | ||
| 155 | Inst(Opcode::SetLoopSafetyVariable, id, counter); | ||
| 156 | } | ||
| 157 | |||
| 158 | U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) { | 150 | U32 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, | |||
| 32 | OPCODE(SetGotoVariable, Void, U32, U1, ) | 32 | OPCODE(SetGotoVariable, Void, U32, U1, ) |
| 33 | OPCODE(GetIndirectBranchVariable, U32, ) | 33 | OPCODE(GetIndirectBranchVariable, U32, ) |
| 34 | OPCODE(SetIndirectBranchVariable, Void, U32, ) | 34 | OPCODE(SetIndirectBranchVariable, Void, U32, ) |
| 35 | OPCODE(GetLoopSafetyVariable, U32, U32, ) | ||
| 36 | OPCODE(SetLoopSafetyVariable, Void, U32, U32, ) | ||
| 37 | OPCODE(GetCbufU8, U32, U32, U32, ) | 35 | OPCODE(GetCbufU8, U32, U32, U32, ) |
| 38 | OPCODE(GetCbufS8, U32, U32, U32, ) | 36 | OPCODE(GetCbufS8, U32, U32, U32, ) |
| 39 | OPCODE(GetCbufU16, U32, U32, U32, ) | 37 | OPCODE(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 | ||
| 51 | struct 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 | |||
| 60 | struct IndirectBranchVariable { | 51 | struct IndirectBranchVariable { |
| 61 | auto operator<=>(const IndirectBranchVariable&) const noexcept = default; | 52 | auto operator<=>(const IndirectBranchVariable&) const noexcept = default; |
| 62 | }; | 53 | }; |
| 63 | 54 | ||
| 64 | using Variant = | 55 | using 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>; | ||
| 67 | using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>; | 57 | using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>; |
| 68 | 58 | ||
| 69 | struct DefTable { | 59 | struct 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 | ||
| 155 | IR::Opcode UndefOpcode(const LoopSafetyVariable&) noexcept { | ||
| 156 | return IR::Opcode::UndefU32; | ||
| 157 | } | ||
| 158 | |||
| 159 | IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept { | 137 | IR::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; |