summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/ir_opt
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/ir_opt')
-rw-r--r--src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp23
-rw-r--r--src/shader_recompiler/ir_opt/get_set_elimination_pass.cpp87
-rw-r--r--src/shader_recompiler/ir_opt/identity_removal_pass.cpp37
-rw-r--r--src/shader_recompiler/ir_opt/passes.h16
-rw-r--r--src/shader_recompiler/ir_opt/verification_pass.cpp50
5 files changed, 213 insertions, 0 deletions
diff --git a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
new file mode 100644
index 000000000..bbaa412f6
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
@@ -0,0 +1,23 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <ranges>
6
7#include "shader_recompiler/frontend/ir/basic_block.h"
8#include "shader_recompiler/frontend/ir/microinstruction.h"
9#include "shader_recompiler/ir_opt/passes.h"
10
11namespace Shader::Optimization {
12
13void DeadCodeEliminationPass(IR::Block& block) {
14 // We iterate over the instructions in reverse order.
15 // This is because removing an instruction reduces the number of uses for earlier instructions.
16 for (IR::Inst& inst : std::views::reverse(block)) {
17 if (!inst.HasUses() && !inst.MayHaveSideEffects()) {
18 inst.Invalidate();
19 }
20 }
21}
22
23} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/ir_opt/get_set_elimination_pass.cpp b/src/shader_recompiler/ir_opt/get_set_elimination_pass.cpp
new file mode 100644
index 000000000..21b8526cd
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/get_set_elimination_pass.cpp
@@ -0,0 +1,87 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6
7#include "shader_recompiler/frontend/ir/basic_block.h"
8#include "shader_recompiler/frontend/ir/microinstruction.h"
9#include "shader_recompiler/ir_opt/passes.h"
10
11namespace Shader::Optimization {
12namespace {
13using Iterator = IR::Block::iterator;
14
15enum class TrackingType {
16 Reg,
17};
18
19struct RegisterInfo {
20 IR::Value register_value;
21 TrackingType tracking_type;
22 Iterator last_set_instruction;
23 bool set_instruction_present = false;
24};
25
26void DoSet(IR::Block& block, RegisterInfo& info, IR::Value value, Iterator set_inst,
27 TrackingType tracking_type) {
28 if (info.set_instruction_present) {
29 info.last_set_instruction->Invalidate();
30 block.Instructions().erase(info.last_set_instruction);
31 }
32 info.register_value = value;
33 info.tracking_type = tracking_type;
34 info.set_instruction_present = true;
35 info.last_set_instruction = set_inst;
36}
37
38RegisterInfo Nothing(Iterator get_inst, TrackingType tracking_type) {
39 RegisterInfo info{};
40 info.register_value = IR::Value{&*get_inst};
41 info.tracking_type = tracking_type;
42 return info;
43}
44
45void DoGet(RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
46 if (info.register_value.IsEmpty()) {
47 info = Nothing(get_inst, tracking_type);
48 return;
49 }
50 if (info.tracking_type == tracking_type) {
51 get_inst->ReplaceUsesWith(info.register_value);
52 return;
53 }
54 info = Nothing(get_inst, tracking_type);
55}
56} // Anonymous namespace
57
58void GetSetElimination(IR::Block& block) {
59 std::array<RegisterInfo, 255> reg_info;
60
61 for (Iterator inst = block.begin(); inst != block.end(); ++inst) {
62 switch (inst->Opcode()) {
63 case IR::Opcode::GetRegister: {
64 const IR::Reg reg{inst->Arg(0).Reg()};
65 if (reg == IR::Reg::RZ) {
66 break;
67 }
68 const size_t index{static_cast<size_t>(reg)};
69 DoGet(reg_info.at(index), inst, TrackingType::Reg);
70 break;
71 }
72 case IR::Opcode::SetRegister: {
73 const IR::Reg reg{inst->Arg(0).Reg()};
74 if (reg == IR::Reg::RZ) {
75 break;
76 }
77 const size_t index{static_cast<size_t>(reg)};
78 DoSet(block, reg_info.at(index), inst->Arg(1), inst, TrackingType::Reg);
79 break;
80 }
81 default:
82 break;
83 }
84 }
85}
86
87} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/ir_opt/identity_removal_pass.cpp b/src/shader_recompiler/ir_opt/identity_removal_pass.cpp
new file mode 100644
index 000000000..f9bb063fb
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/identity_removal_pass.cpp
@@ -0,0 +1,37 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "shader_recompiler/frontend/ir/basic_block.h"
8#include "shader_recompiler/frontend/ir/microinstruction.h"
9#include "shader_recompiler/ir_opt/passes.h"
10
11namespace Shader::Optimization {
12
13void IdentityRemovalPass(IR::Block& block) {
14 std::vector<IR::Inst*> to_invalidate;
15
16 for (auto inst = block.begin(); inst != block.end();) {
17 const size_t num_args{inst->NumArgs()};
18 for (size_t i = 0; i < num_args; ++i) {
19 IR::Value arg;
20 while ((arg = inst->Arg(i)).IsIdentity()) {
21 inst->SetArg(i, arg.Inst()->Arg(0));
22 }
23 }
24 if (inst->Opcode() == IR::Opcode::Identity || inst->Opcode() == IR::Opcode::Void) {
25 to_invalidate.push_back(&*inst);
26 inst = block.Instructions().erase(inst);
27 } else {
28 ++inst;
29 }
30 }
31
32 for (IR::Inst* const inst : to_invalidate) {
33 inst->Invalidate();
34 }
35}
36
37} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h
new file mode 100644
index 000000000..fe5454e9a
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/passes.h
@@ -0,0 +1,16 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "shader_recompiler/frontend/ir/basic_block.h"
8
9namespace Shader::Optimization {
10
11void DeadCodeEliminationPass(IR::Block& block);
12void GetSetElimination(IR::Block& block);
13void IdentityRemovalPass(IR::Block& block);
14void VerificationPass(const IR::Block& block);
15
16} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/ir_opt/verification_pass.cpp b/src/shader_recompiler/ir_opt/verification_pass.cpp
new file mode 100644
index 000000000..36d9ae39b
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/verification_pass.cpp
@@ -0,0 +1,50 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <map>
6
7#include "shader_recompiler/exception.h"
8#include "shader_recompiler/frontend/ir/basic_block.h"
9#include "shader_recompiler/frontend/ir/microinstruction.h"
10#include "shader_recompiler/ir_opt/passes.h"
11
12namespace Shader::Optimization {
13
14static void ValidateTypes(const IR::Block& block) {
15 for (const IR::Inst& inst : block) {
16 const size_t num_args{inst.NumArgs()};
17 for (size_t i = 0; i < num_args; ++i) {
18 const IR::Type t1{inst.Arg(i).Type()};
19 const IR::Type t2{IR::ArgTypeOf(inst.Opcode(), i)};
20 if (!IR::AreTypesCompatible(t1, t2)) {
21 throw LogicError("Invalid types in block:\n{}", IR::DumpBlock(block));
22 }
23 }
24 }
25}
26
27static void ValidateUses(const IR::Block& block) {
28 std::map<IR::Inst*, int> actual_uses;
29 for (const IR::Inst& inst : block) {
30 const size_t num_args{inst.NumArgs()};
31 for (size_t i = 0; i < num_args; ++i) {
32 const IR::Value arg{inst.Arg(i)};
33 if (!arg.IsImmediate()) {
34 ++actual_uses[arg.Inst()];
35 }
36 }
37 }
38 for (const auto [inst, uses] : actual_uses) {
39 if (inst->UseCount() != uses) {
40 throw LogicError("Invalid uses in block:\n{}", IR::DumpBlock(block));
41 }
42 }
43}
44
45void VerificationPass(const IR::Block& block) {
46 ValidateTypes(block);
47 ValidateUses(block);
48}
49
50} // namespace Shader::Optimization