shader: Move loop safety tests to code emission
This commit is contained in:
parent
3877918e96
commit
808ef97a08
|
@ -71,6 +71,7 @@ public:
|
||||||
std::string_view stage_name = "invalid";
|
std::string_view stage_name = "invalid";
|
||||||
std::string_view attrib_name = "invalid";
|
std::string_view attrib_name = "invalid";
|
||||||
|
|
||||||
|
u32 num_safety_loop_vars{};
|
||||||
bool uses_y_direction{};
|
bool uses_y_direction{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "common/div_ceil.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "shader_recompiler/backend/bindings.h"
|
#include "shader_recompiler/backend/bindings.h"
|
||||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||||
#include "shader_recompiler/backend/glasm/emit_glasm.h"
|
#include "shader_recompiler/backend/glasm/emit_glasm.h"
|
||||||
|
@ -222,6 +224,14 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
|
||||||
ctx.Add("REP;");
|
ctx.Add("REP;");
|
||||||
break;
|
break;
|
||||||
case IR::AbstractSyntaxNode::Type::Repeat:
|
case IR::AbstractSyntaxNode::Type::Repeat:
|
||||||
|
if (!Settings::values.disable_shader_loop_safety_checks) {
|
||||||
|
const u32 loop_index{ctx.num_safety_loop_vars++};
|
||||||
|
const u32 vector_index{loop_index / 4};
|
||||||
|
const char component{"xyzw"[loop_index % 4]};
|
||||||
|
ctx.Add("SUB.S.CC loop{}.{},loop{}.{},1;"
|
||||||
|
"BRK(LT.{});",
|
||||||
|
vector_index, component, vector_index, component, component);
|
||||||
|
}
|
||||||
if (node.data.repeat.cond.IsImmediate()) {
|
if (node.data.repeat.cond.IsImmediate()) {
|
||||||
if (node.data.repeat.cond.U1()) {
|
if (node.data.repeat.cond.U1()) {
|
||||||
ctx.Add("ENDREP;");
|
ctx.Add("ENDREP;");
|
||||||
|
@ -425,6 +435,10 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
|
||||||
if (program.info.uses_fswzadd) {
|
if (program.info.uses_fswzadd) {
|
||||||
header += "FSWZA[4],FSWZB[4],";
|
header += "FSWZA[4],FSWZB[4],";
|
||||||
}
|
}
|
||||||
|
const u32 num_safety_loop_vectors{Common::DivCeil(ctx.num_safety_loop_vars, 4u)};
|
||||||
|
for (u32 index = 0; index < num_safety_loop_vectors; ++index) {
|
||||||
|
header += fmt::format("loop{},", index);
|
||||||
|
}
|
||||||
header += "RC;"
|
header += "RC;"
|
||||||
"LONG TEMP ";
|
"LONG TEMP ";
|
||||||
for (size_t index = 0; index < ctx.reg_alloc.NumUsedLongRegisters(); ++index) {
|
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
|
||||||
"MOV.F FSWZB[2],1;"
|
"MOV.F FSWZB[2],1;"
|
||||||
"MOV.F FSWZB[3],-1;";
|
"MOV.F FSWZB[3],-1;";
|
||||||
}
|
}
|
||||||
|
for (u32 index = 0; index < num_safety_loop_vectors; ++index) {
|
||||||
|
header += fmt::format("MOV.S loop{},{{0x2000,0x2000,0x2000,0x2000}};", index);
|
||||||
|
}
|
||||||
if (ctx.uses_y_direction) {
|
if (ctx.uses_y_direction) {
|
||||||
header += "PARAM y_direction[1]={state.material.front.ambient};";
|
header += "PARAM y_direction[1]={state.material.front.ambient};";
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
|
||||||
void EmitGetGotoVariable(EmitContext& ctx);
|
void EmitGetGotoVariable(EmitContext& ctx);
|
||||||
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitSetLoopSafetyVariable(EmitContext& ctx);
|
|
||||||
void EmitGetLoopSafetyVariable(EmitContext& ctx);
|
|
||||||
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
||||||
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
||||||
void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset);
|
||||||
|
|
|
@ -153,14 +153,6 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetLoopSafetyVariable(EmitContext& ctx) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitGetLoopSafetyVariable(EmitContext& ctx) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitGetZFlag(EmitContext& ctx) {
|
void EmitGetZFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,6 +153,8 @@ public:
|
||||||
std::vector<TextureImageDefinition> images;
|
std::vector<TextureImageDefinition> images;
|
||||||
std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
|
std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
|
||||||
|
|
||||||
|
u32 num_safety_loop_vars{};
|
||||||
|
|
||||||
bool uses_y_direction{};
|
bool uses_y_direction{};
|
||||||
bool uses_cc_carry{};
|
bool uses_cc_carry{};
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||||
#include "shader_recompiler/backend/glsl/emit_glsl.h"
|
#include "shader_recompiler/backend/glsl/emit_glsl.h"
|
||||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||||
|
@ -156,7 +157,12 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
|
||||||
ctx.Add("for(;;){{");
|
ctx.Add("for(;;){{");
|
||||||
break;
|
break;
|
||||||
case IR::AbstractSyntaxNode::Type::Repeat:
|
case IR::AbstractSyntaxNode::Type::Repeat:
|
||||||
ctx.Add("if(!{}){{break;}}}}", ctx.var_alloc.Consume(node.data.repeat.cond));
|
if (Settings::values.disable_shader_loop_safety_checks) {
|
||||||
|
ctx.Add("if(!{}){{break;}}}}", ctx.var_alloc.Consume(node.data.repeat.cond));
|
||||||
|
} else {
|
||||||
|
ctx.Add("if(--loop{}<0 || !{}){{break;}}}}", ctx.num_safety_loop_vars++,
|
||||||
|
ctx.var_alloc.Consume(node.data.repeat.cond));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException("AbstractSyntaxNode Type {}", node.type);
|
throw NotImplementedException("AbstractSyntaxNode Type {}", node.type);
|
||||||
|
@ -198,6 +204,9 @@ void DefineVariables(const EmitContext& ctx, std::string& header) {
|
||||||
ctx.var_alloc.Representation(index, type), type_name);
|
ctx.var_alloc.Representation(index, type), type_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (u32 i = 0; i < ctx.num_safety_loop_vars; ++i) {
|
||||||
|
header += fmt::format("int loop{}=0x2000;", i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
|
||||||
void EmitGetGotoVariable(EmitContext& ctx);
|
void EmitGetGotoVariable(EmitContext& ctx);
|
||||||
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitSetLoopSafetyVariable(EmitContext& ctx);
|
|
||||||
void EmitGetLoopSafetyVariable(EmitContext& ctx);
|
|
||||||
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||||
const IR::Value& offset);
|
const IR::Value& offset);
|
||||||
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||||
|
|
|
@ -46,14 +46,6 @@ void EmitGetIndirectBranchVariable(EmitContext& ctx) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetLoopSafetyVariable(EmitContext& ctx) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitGetLoopSafetyVariable(EmitContext& ctx) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitGetZFlag(EmitContext& ctx) {
|
void EmitGetZFlag(EmitContext& ctx) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/settings.h"
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||||
|
@ -151,9 +152,25 @@ void Traverse(EmitContext& ctx, IR::Program& program) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IR::AbstractSyntaxNode::Type::Repeat: {
|
case IR::AbstractSyntaxNode::Type::Repeat: {
|
||||||
|
Id cond{ctx.Def(node.data.repeat.cond)};
|
||||||
|
if (!Settings::values.disable_shader_loop_safety_checks) {
|
||||||
|
const Id pointer_type{ctx.TypePointer(spv::StorageClass::Private, ctx.U32[1])};
|
||||||
|
const Id safety_counter{ctx.AddGlobalVariable(
|
||||||
|
pointer_type, spv::StorageClass::Private, ctx.Const(0x2000u))};
|
||||||
|
if (ctx.profile.supported_spirv >= 0x00010400) {
|
||||||
|
ctx.interfaces.push_back(safety_counter);
|
||||||
|
}
|
||||||
|
const Id old_counter{ctx.OpLoad(ctx.U32[1], safety_counter)};
|
||||||
|
const Id new_counter{ctx.OpISub(ctx.U32[1], old_counter, ctx.Const(1u))};
|
||||||
|
ctx.OpStore(safety_counter, new_counter);
|
||||||
|
|
||||||
|
const Id safety_cond{
|
||||||
|
ctx.OpSGreaterThanEqual(ctx.U1, new_counter, ctx.u32_zero_value)};
|
||||||
|
cond = ctx.OpLogicalAnd(ctx.U1, cond, safety_cond);
|
||||||
|
}
|
||||||
const Id loop_header_label{node.data.repeat.loop_header->Definition<Id>()};
|
const Id loop_header_label{node.data.repeat.loop_header->Definition<Id>()};
|
||||||
const Id merge_label{node.data.repeat.merge->Definition<Id>()};
|
const Id merge_label{node.data.repeat.merge->Definition<Id>()};
|
||||||
ctx.OpBranchConditional(ctx.Def(node.data.repeat.cond), loop_header_label, merge_label);
|
ctx.OpBranchConditional(cond, loop_header_label, merge_label);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::AbstractSyntaxNode::Type::Return:
|
case IR::AbstractSyntaxNode::Type::Return:
|
||||||
|
|
|
@ -198,14 +198,6 @@ void EmitGetIndirectBranchVariable(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSetLoopSafetyVariable(EmitContext&) {
|
|
||||||
throw LogicError("Unreachable instruction");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitGetLoopSafetyVariable(EmitContext&) {
|
|
||||||
throw LogicError("Unreachable instruction");
|
|
||||||
}
|
|
||||||
|
|
||||||
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
|
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
|
||||||
const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)};
|
const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)};
|
||||||
|
|
|
@ -43,8 +43,6 @@ void EmitSetGotoVariable(EmitContext& ctx);
|
||||||
void EmitGetGotoVariable(EmitContext& ctx);
|
void EmitGetGotoVariable(EmitContext& ctx);
|
||||||
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
void EmitSetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
void EmitGetIndirectBranchVariable(EmitContext& ctx);
|
||||||
void EmitSetLoopSafetyVariable(EmitContext& ctx);
|
|
||||||
void EmitGetLoopSafetyVariable(EmitContext& ctx);
|
|
||||||
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
||||||
Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
||||||
Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
|
||||||
|
|
|
@ -147,14 +147,6 @@ void IREmitter::SetIndirectBranchVariable(const U32& value) {
|
||||||
Inst(Opcode::SetIndirectBranchVariable, value);
|
Inst(Opcode::SetIndirectBranchVariable, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 IREmitter::GetLoopSafetyVariable(u32 id) {
|
|
||||||
return Inst<U32>(Opcode::GetLoopSafetyVariable, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IREmitter::SetLoopSafetyVariable(u32 id, const U32& counter) {
|
|
||||||
Inst(Opcode::SetLoopSafetyVariable, id, counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) {
|
U32 IREmitter::GetCbuf(const U32& binding, const U32& byte_offset) {
|
||||||
return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset);
|
return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,6 @@ public:
|
||||||
[[nodiscard]] U32 GetIndirectBranchVariable();
|
[[nodiscard]] U32 GetIndirectBranchVariable();
|
||||||
void SetIndirectBranchVariable(const U32& value);
|
void SetIndirectBranchVariable(const U32& value);
|
||||||
|
|
||||||
[[nodiscard]] U32 GetLoopSafetyVariable(u32 id);
|
|
||||||
void SetLoopSafetyVariable(u32 id, const U32& counter);
|
|
||||||
|
|
||||||
[[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset);
|
[[nodiscard]] U32 GetCbuf(const U32& binding, const U32& byte_offset);
|
||||||
[[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
|
[[nodiscard]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
|
||||||
bool is_signed);
|
bool is_signed);
|
||||||
|
|
|
@ -32,8 +32,6 @@ OPCODE(GetGotoVariable, U1, U32,
|
||||||
OPCODE(SetGotoVariable, Void, U32, U1, )
|
OPCODE(SetGotoVariable, Void, U32, U1, )
|
||||||
OPCODE(GetIndirectBranchVariable, U32, )
|
OPCODE(GetIndirectBranchVariable, U32, )
|
||||||
OPCODE(SetIndirectBranchVariable, Void, U32, )
|
OPCODE(SetIndirectBranchVariable, Void, U32, )
|
||||||
OPCODE(GetLoopSafetyVariable, U32, U32, )
|
|
||||||
OPCODE(SetLoopSafetyVariable, Void, U32, U32, )
|
|
||||||
OPCODE(GetCbufU8, U32, U32, U32, )
|
OPCODE(GetCbufU8, U32, U32, U32, )
|
||||||
OPCODE(GetCbufS8, U32, U32, U32, )
|
OPCODE(GetCbufS8, U32, U32, U32, )
|
||||||
OPCODE(GetCbufU16, U32, U32, U32, )
|
OPCODE(GetCbufU16, U32, U32, U32, )
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include <boost/intrusive/list.hpp>
|
#include <boost/intrusive/list.hpp>
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "shader_recompiler/environment.h"
|
#include "shader_recompiler/environment.h"
|
||||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||||
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
||||||
|
@ -663,7 +662,7 @@ public:
|
||||||
Visit(root_stmt, nullptr, nullptr);
|
Visit(root_stmt, nullptr, nullptr);
|
||||||
|
|
||||||
IR::Block& first_block{*syntax_list.front().data.block};
|
IR::Block& first_block{*syntax_list.front().data.block};
|
||||||
IR::IREmitter ir = IR::IREmitter(first_block, first_block.begin());
|
IR::IREmitter ir(first_block, first_block.begin());
|
||||||
ir.Prologue();
|
ir.Prologue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,27 +740,8 @@ private:
|
||||||
}
|
}
|
||||||
case StatementType::Loop: {
|
case StatementType::Loop: {
|
||||||
IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
|
IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
|
||||||
const u32 this_loop_id{loop_id++};
|
if (current_block) {
|
||||||
|
current_block->AddBranch(loop_header_block);
|
||||||
if (Settings::values.disable_shader_loop_safety_checks) {
|
|
||||||
if (current_block) {
|
|
||||||
current_block->AddBranch(loop_header_block);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
IR::Block* const init_block{block_pool.Create(inst_pool)};
|
|
||||||
IR::IREmitter ir{*init_block};
|
|
||||||
|
|
||||||
static constexpr u32 SAFETY_THRESHOLD = 0x1000;
|
|
||||||
ir.SetLoopSafetyVariable(this_loop_id, ir.Imm32(SAFETY_THRESHOLD));
|
|
||||||
|
|
||||||
if (current_block) {
|
|
||||||
current_block->AddBranch(init_block);
|
|
||||||
}
|
|
||||||
init_block->AddBranch(loop_header_block);
|
|
||||||
|
|
||||||
auto& init_node{syntax_list.emplace_back()};
|
|
||||||
init_node.type = IR::AbstractSyntaxNode::Type::Block;
|
|
||||||
init_node.data.block = init_block;
|
|
||||||
}
|
}
|
||||||
auto& header_node{syntax_list.emplace_back()};
|
auto& header_node{syntax_list.emplace_back()};
|
||||||
header_node.type = IR::AbstractSyntaxNode::Type::Block;
|
header_node.type = IR::AbstractSyntaxNode::Type::Block;
|
||||||
|
@ -779,16 +759,7 @@ private:
|
||||||
|
|
||||||
// The continue block is located at the end of the loop
|
// The continue block is located at the end of the loop
|
||||||
IR::IREmitter ir{*continue_block};
|
IR::IREmitter ir{*continue_block};
|
||||||
IR::U1 cond{VisitExpr(ir, *stmt.cond)};
|
const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))};
|
||||||
if (!Settings::values.disable_shader_loop_safety_checks) {
|
|
||||||
const IR::U32 old_counter{ir.GetLoopSafetyVariable(this_loop_id)};
|
|
||||||
const IR::U32 new_counter{ir.ISub(old_counter, ir.Imm32(1))};
|
|
||||||
ir.SetLoopSafetyVariable(this_loop_id, new_counter);
|
|
||||||
|
|
||||||
const IR::U1 safety_cond{ir.INotEqual(new_counter, ir.Imm32(0))};
|
|
||||||
cond = ir.LogicalAnd(cond, safety_cond);
|
|
||||||
}
|
|
||||||
cond = ir.ConditionRef(cond);
|
|
||||||
|
|
||||||
IR::Block* const body_block{syntax_list.at(body_block_index).data.block};
|
IR::Block* const body_block{syntax_list.at(body_block_index).data.block};
|
||||||
loop_header_block->AddBranch(body_block);
|
loop_header_block->AddBranch(body_block);
|
||||||
|
|
|
@ -48,22 +48,12 @@ struct GotoVariable : FlagTag {
|
||||||
u32 index;
|
u32 index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LoopSafetyVariable {
|
|
||||||
LoopSafetyVariable() = default;
|
|
||||||
explicit LoopSafetyVariable(u32 index_) : index{index_} {}
|
|
||||||
|
|
||||||
auto operator<=>(const LoopSafetyVariable&) const noexcept = default;
|
|
||||||
|
|
||||||
u32 index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IndirectBranchVariable {
|
struct IndirectBranchVariable {
|
||||||
auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
|
auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Variant =
|
using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag,
|
||||||
std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag,
|
OverflowFlagTag, GotoVariable, IndirectBranchVariable>;
|
||||||
GotoVariable, LoopSafetyVariable, IndirectBranchVariable>;
|
|
||||||
using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>;
|
using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>;
|
||||||
|
|
||||||
struct DefTable {
|
struct DefTable {
|
||||||
|
@ -88,13 +78,6 @@ struct DefTable {
|
||||||
goto_vars[variable.index].insert_or_assign(block, value);
|
goto_vars[variable.index].insert_or_assign(block, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, LoopSafetyVariable variable) {
|
|
||||||
return loop_safety_vars[variable.index][block];
|
|
||||||
}
|
|
||||||
void SetDef(IR::Block* block, LoopSafetyVariable variable, const IR::Value& value) {
|
|
||||||
loop_safety_vars[variable.index].insert_or_assign(block, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const IR::Value& Def(IR::Block* block, IndirectBranchVariable) {
|
const IR::Value& Def(IR::Block* block, IndirectBranchVariable) {
|
||||||
return indirect_branch_var[block];
|
return indirect_branch_var[block];
|
||||||
}
|
}
|
||||||
|
@ -132,7 +115,6 @@ struct DefTable {
|
||||||
|
|
||||||
std::array<ValueMap, IR::NUM_USER_PREDS> preds;
|
std::array<ValueMap, IR::NUM_USER_PREDS> preds;
|
||||||
boost::container::flat_map<u32, ValueMap> goto_vars;
|
boost::container::flat_map<u32, ValueMap> goto_vars;
|
||||||
boost::container::flat_map<u32, ValueMap> loop_safety_vars;
|
|
||||||
ValueMap indirect_branch_var;
|
ValueMap indirect_branch_var;
|
||||||
ValueMap zero_flag;
|
ValueMap zero_flag;
|
||||||
ValueMap sign_flag;
|
ValueMap sign_flag;
|
||||||
|
@ -152,10 +134,6 @@ IR::Opcode UndefOpcode(const FlagTag&) noexcept {
|
||||||
return IR::Opcode::UndefU1;
|
return IR::Opcode::UndefU1;
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Opcode UndefOpcode(const LoopSafetyVariable&) noexcept {
|
|
||||||
return IR::Opcode::UndefU32;
|
|
||||||
}
|
|
||||||
|
|
||||||
IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
|
IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
|
||||||
return IR::Opcode::UndefU32;
|
return IR::Opcode::UndefU32;
|
||||||
}
|
}
|
||||||
|
@ -337,9 +315,6 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
|
||||||
case IR::Opcode::SetGotoVariable:
|
case IR::Opcode::SetGotoVariable:
|
||||||
pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
|
pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
|
||||||
break;
|
break;
|
||||||
case IR::Opcode::SetLoopSafetyVariable:
|
|
||||||
pass.WriteVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
|
|
||||||
break;
|
|
||||||
case IR::Opcode::SetIndirectBranchVariable:
|
case IR::Opcode::SetIndirectBranchVariable:
|
||||||
pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0));
|
pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0));
|
||||||
break;
|
break;
|
||||||
|
@ -368,9 +343,6 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
|
||||||
case IR::Opcode::GetGotoVariable:
|
case IR::Opcode::GetGotoVariable:
|
||||||
inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block));
|
inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block));
|
||||||
break;
|
break;
|
||||||
case IR::Opcode::GetLoopSafetyVariable:
|
|
||||||
inst.ReplaceUsesWith(pass.ReadVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block));
|
|
||||||
break;
|
|
||||||
case IR::Opcode::GetIndirectBranchVariable:
|
case IR::Opcode::GetIndirectBranchVariable:
|
||||||
inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block));
|
inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block));
|
||||||
break;
|
break;
|
||||||
|
|
Reference in New Issue