summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/ir_opt/verification_pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/ir_opt/verification_pass.cpp')
-rw-r--r--src/shader_recompiler/ir_opt/verification_pass.cpp98
1 files changed, 98 insertions, 0 deletions
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..975d5aadf
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/verification_pass.cpp
@@ -0,0 +1,98 @@
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#include <set>
7
8#include "shader_recompiler/exception.h"
9#include "shader_recompiler/frontend/ir/basic_block.h"
10#include "shader_recompiler/frontend/ir/value.h"
11#include "shader_recompiler/ir_opt/passes.h"
12
13namespace Shader::Optimization {
14
15static void ValidateTypes(const IR::Program& program) {
16 for (const auto& block : program.blocks) {
17 for (const IR::Inst& inst : *block) {
18 if (inst.GetOpcode() == IR::Opcode::Phi) {
19 // Skip validation on phi nodes
20 continue;
21 }
22 const size_t num_args{inst.NumArgs()};
23 for (size_t i = 0; i < num_args; ++i) {
24 const IR::Type t1{inst.Arg(i).Type()};
25 const IR::Type t2{IR::ArgTypeOf(inst.GetOpcode(), i)};
26 if (!IR::AreTypesCompatible(t1, t2)) {
27 throw LogicError("Invalid types in block:\n{}", IR::DumpBlock(*block));
28 }
29 }
30 }
31 }
32}
33
34static void ValidateUses(const IR::Program& program) {
35 std::map<IR::Inst*, int> actual_uses;
36 for (const auto& block : program.blocks) {
37 for (const IR::Inst& inst : *block) {
38 const size_t num_args{inst.NumArgs()};
39 for (size_t i = 0; i < num_args; ++i) {
40 const IR::Value arg{inst.Arg(i)};
41 if (!arg.IsImmediate()) {
42 ++actual_uses[arg.Inst()];
43 }
44 }
45 }
46 }
47 for (const auto [inst, uses] : actual_uses) {
48 if (inst->UseCount() != uses) {
49 throw LogicError("Invalid uses in block: {}", IR::DumpProgram(program));
50 }
51 }
52}
53
54static void ValidateForwardDeclarations(const IR::Program& program) {
55 std::set<const IR::Inst*> definitions;
56 for (const IR::Block* const block : program.blocks) {
57 for (const IR::Inst& inst : *block) {
58 definitions.emplace(&inst);
59 if (inst.GetOpcode() == IR::Opcode::Phi) {
60 // Phi nodes can have forward declarations
61 continue;
62 }
63 const size_t num_args{inst.NumArgs()};
64 for (size_t arg = 0; arg < num_args; ++arg) {
65 if (inst.Arg(arg).IsImmediate()) {
66 continue;
67 }
68 if (!definitions.contains(inst.Arg(arg).Inst())) {
69 throw LogicError("Forward declaration in block: {}", IR::DumpBlock(*block));
70 }
71 }
72 }
73 }
74}
75
76static void ValidatePhiNodes(const IR::Program& program) {
77 for (const IR::Block* const block : program.blocks) {
78 bool no_more_phis{false};
79 for (const IR::Inst& inst : *block) {
80 if (inst.GetOpcode() == IR::Opcode::Phi) {
81 if (no_more_phis) {
82 throw LogicError("Interleaved phi nodes: {}", IR::DumpBlock(*block));
83 }
84 } else {
85 no_more_phis = true;
86 }
87 }
88 }
89}
90
91void VerificationPass(const IR::Program& program) {
92 ValidateTypes(program);
93 ValidateUses(program);
94 ValidateForwardDeclarations(program);
95 ValidatePhiNodes(program);
96}
97
98} // namespace Shader::Optimization