From 808ef97a086e7cc58a3ceded1de516ad6a6be5d3 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Mon, 21 Jun 2021 01:07:10 -0300
Subject: [PATCH] shader: Move loop safety tests to code emission

---
 .../backend/glasm/emit_context.h              |  1 +
 .../backend/glasm/emit_glasm.cpp              | 17 +++++++++
 .../backend/glasm/emit_glasm_instructions.h   |  2 -
 .../glasm/emit_glasm_not_implemented.cpp      |  8 ----
 .../backend/glsl/emit_context.h               |  2 +
 .../backend/glsl/emit_glsl.cpp                | 11 +++++-
 .../backend/glsl/emit_glsl_instructions.h     |  2 -
 .../glsl/emit_glsl_not_implemented.cpp        |  8 ----
 .../backend/spirv/emit_spirv.cpp              | 19 +++++++++-
 .../spirv/emit_spirv_context_get_set.cpp      |  8 ----
 .../backend/spirv/emit_spirv_instructions.h   |  2 -
 .../frontend/ir/ir_emitter.cpp                |  8 ----
 .../frontend/ir/ir_emitter.h                  |  3 --
 src/shader_recompiler/frontend/ir/opcodes.inc |  2 -
 .../maxwell/structured_control_flow.cpp       | 37 ++-----------------
 .../ir_opt/ssa_rewrite_pass.cpp               | 32 +---------------
 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:
     std::string_view stage_name = "invalid";
     std::string_view attrib_name = "invalid";
 
+    u32 num_safety_loop_vars{};
     bool uses_y_direction{};
 };
 
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 @@
 #include <string>
 #include <tuple>
 
+#include "common/div_ceil.h"
+#include "common/settings.h"
 #include "shader_recompiler/backend/bindings.h"
 #include "shader_recompiler/backend/glasm/emit_context.h"
 #include "shader_recompiler/backend/glasm/emit_glasm.h"
@@ -222,6 +224,14 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
             ctx.Add("REP;");
             break;
         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.U1()) {
                     ctx.Add("ENDREP;");
@@ -425,6 +435,10 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
     if (program.info.uses_fswzadd) {
         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;"
               "LONG TEMP ";
     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[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) {
         header += "PARAM y_direction[1]={state.material.front.ambient};";
     }
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);
 void EmitGetGotoVariable(EmitContext& ctx);
 void EmitSetIndirectBranchVariable(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 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);
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) {
     NotImplemented();
 }
 
-void EmitSetLoopSafetyVariable(EmitContext& ctx) {
-    NotImplemented();
-}
-
-void EmitGetLoopSafetyVariable(EmitContext& ctx) {
-    NotImplemented();
-}
-
 void EmitGetZFlag(EmitContext& ctx) {
     NotImplemented();
 }
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:
     std::vector<TextureImageDefinition> images;
     std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
 
+    u32 num_safety_loop_vars{};
+
     bool uses_y_direction{};
     bool uses_cc_carry{};
 
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 @@
 #include <string>
 
 #include "common/alignment.h"
+#include "common/settings.h"
 #include "shader_recompiler/backend/glsl/emit_context.h"
 #include "shader_recompiler/backend/glsl/emit_glsl.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(;;){{");
             break;
         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;
         default:
             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);
         }
     }
+    for (u32 i = 0; i < ctx.num_safety_loop_vars; ++i) {
+        header += fmt::format("int loop{}=0x2000;", i);
+    }
 }
 } // Anonymous namespace
 
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);
 void EmitGetGotoVariable(EmitContext& ctx);
 void EmitSetIndirectBranchVariable(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,
                    const IR::Value& offset);
 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) {
     NotImplemented();
 }
 
-void EmitSetLoopSafetyVariable(EmitContext& ctx) {
-    NotImplemented();
-}
-
-void EmitGetLoopSafetyVariable(EmitContext& ctx) {
-    NotImplemented();
-}
-
 void EmitGetZFlag(EmitContext& ctx) {
     NotImplemented();
 }
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 @@
 #include <utility>
 #include <vector>
 
+#include "common/settings.h"
 #include "shader_recompiler/backend/spirv/emit_spirv.h"
 #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
 #include "shader_recompiler/frontend/ir/basic_block.h"
@@ -151,9 +152,25 @@ void Traverse(EmitContext& ctx, IR::Program& program) {
             }
             break;
         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 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;
         }
         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&) {
     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) {
     if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
         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);
 void EmitGetGotoVariable(EmitContext& ctx);
 void EmitSetIndirectBranchVariable(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 EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
 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) {
     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) {
     return Inst<U32>(Opcode::GetCbufU32, binding, byte_offset);
 }
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:
     [[nodiscard]] U32 GetIndirectBranchVariable();
     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]] Value GetCbuf(const U32& binding, const U32& byte_offset, size_t bitsize,
                                 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,
 OPCODE(SetGotoVariable,                                     Void,           U32,            U1,                                                             )
 OPCODE(GetIndirectBranchVariable,                           U32,                                                                                            )
 OPCODE(SetIndirectBranchVariable,                           Void,           U32,                                                                            )
-OPCODE(GetLoopSafetyVariable,                               U32,            U32,                                                                            )
-OPCODE(SetLoopSafetyVariable,                               Void,           U32,            U32,                                                            )
 OPCODE(GetCbufU8,                                           U32,            U32,            U32,                                                            )
 OPCODE(GetCbufS8,                                           U32,            U32,            U32,                                                            )
 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 @@
 
 #include <boost/intrusive/list.hpp>
 
-#include "common/settings.h"
 #include "shader_recompiler/environment.h"
 #include "shader_recompiler/frontend/ir/basic_block.h"
 #include "shader_recompiler/frontend/ir/ir_emitter.h"
@@ -663,7 +662,7 @@ public:
         Visit(root_stmt, nullptr, nullptr);
 
         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();
     }
 
@@ -741,27 +740,8 @@ private:
             }
             case StatementType::Loop: {
                 IR::Block* const loop_header_block{block_pool.Create(inst_pool)};
-                const u32 this_loop_id{loop_id++};
-
-                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;
+                if (current_block) {
+                    current_block->AddBranch(loop_header_block);
                 }
                 auto& header_node{syntax_list.emplace_back()};
                 header_node.type = IR::AbstractSyntaxNode::Type::Block;
@@ -779,16 +759,7 @@ private:
 
                 // The continue block is located at the end of the loop
                 IR::IREmitter ir{*continue_block};
-                IR::U1 cond{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);
+                const IR::U1 cond{ir.ConditionRef(VisitExpr(ir, *stmt.cond))};
 
                 IR::Block* const body_block{syntax_list.at(body_block_index).data.block};
                 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 {
     u32 index;
 };
 
-struct LoopSafetyVariable {
-    LoopSafetyVariable() = default;
-    explicit LoopSafetyVariable(u32 index_) : index{index_} {}
-
-    auto operator<=>(const LoopSafetyVariable&) const noexcept = default;
-
-    u32 index;
-};
-
 struct IndirectBranchVariable {
     auto operator<=>(const IndirectBranchVariable&) const noexcept = default;
 };
 
-using Variant =
-    std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag,
-                 GotoVariable, LoopSafetyVariable, IndirectBranchVariable>;
+using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag,
+                             OverflowFlagTag, GotoVariable, IndirectBranchVariable>;
 using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>;
 
 struct DefTable {
@@ -88,13 +78,6 @@ struct DefTable {
         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) {
         return indirect_branch_var[block];
     }
@@ -132,7 +115,6 @@ struct DefTable {
 
     std::array<ValueMap, IR::NUM_USER_PREDS> preds;
     boost::container::flat_map<u32, ValueMap> goto_vars;
-    boost::container::flat_map<u32, ValueMap> loop_safety_vars;
     ValueMap indirect_branch_var;
     ValueMap zero_flag;
     ValueMap sign_flag;
@@ -152,10 +134,6 @@ IR::Opcode UndefOpcode(const FlagTag&) noexcept {
     return IR::Opcode::UndefU1;
 }
 
-IR::Opcode UndefOpcode(const LoopSafetyVariable&) noexcept {
-    return IR::Opcode::UndefU32;
-}
-
 IR::Opcode UndefOpcode(IndirectBranchVariable) noexcept {
     return IR::Opcode::UndefU32;
 }
@@ -337,9 +315,6 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
     case IR::Opcode::SetGotoVariable:
         pass.WriteVariable(GotoVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
         break;
-    case IR::Opcode::SetLoopSafetyVariable:
-        pass.WriteVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block, inst.Arg(1));
-        break;
     case IR::Opcode::SetIndirectBranchVariable:
         pass.WriteVariable(IndirectBranchVariable{}, block, inst.Arg(0));
         break;
@@ -368,9 +343,6 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
     case IR::Opcode::GetGotoVariable:
         inst.ReplaceUsesWith(pass.ReadVariable(GotoVariable{inst.Arg(0).U32()}, block));
         break;
-    case IR::Opcode::GetLoopSafetyVariable:
-        inst.ReplaceUsesWith(pass.ReadVariable(LoopSafetyVariable{inst.Arg(0).U32()}, block));
-        break;
     case IR::Opcode::GetIndirectBranchVariable:
         inst.ReplaceUsesWith(pass.ReadVariable(IndirectBranchVariable{}, block));
         break;