summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/control_flow.h
diff options
context:
space:
mode:
authorGravatar bunnei2021-07-25 11:39:04 -0700
committerGravatar GitHub2021-07-25 11:39:04 -0700
commit98b26b6e126d4775fdf3f773fe8a8ac808a8ff8f (patch)
tree816faa96c2c4d291825063433331a8ea4b3d08f1 /src/shader_recompiler/frontend/maxwell/control_flow.h
parentMerge pull request #6699 from lat9nq/common-threads (diff)
parentshader: Support out of bound local memory reads and immediate writes (diff)
downloadyuzu-98b26b6e126d4775fdf3f773fe8a8ac808a8ff8f.tar.gz
yuzu-98b26b6e126d4775fdf3f773fe8a8ac808a8ff8f.tar.xz
yuzu-98b26b6e126d4775fdf3f773fe8a8ac808a8ff8f.zip
Merge pull request #6585 from ameerj/hades
Shader Decompiler Rewrite
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/control_flow.h')
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.h169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.h b/src/shader_recompiler/frontend/maxwell/control_flow.h
new file mode 100644
index 000000000..a6bd3e196
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.h
@@ -0,0 +1,169 @@
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 <compare>
8#include <optional>
9#include <span>
10#include <string>
11#include <vector>
12
13#include <boost/container/small_vector.hpp>
14#include <boost/intrusive/set.hpp>
15
16#include "shader_recompiler/environment.h"
17#include "shader_recompiler/frontend/ir/condition.h"
18#include "shader_recompiler/frontend/maxwell/instruction.h"
19#include "shader_recompiler/frontend/maxwell/location.h"
20#include "shader_recompiler/frontend/maxwell/opcodes.h"
21#include "shader_recompiler/object_pool.h"
22
23namespace Shader::Maxwell::Flow {
24
25struct Block;
26
27using FunctionId = size_t;
28
29enum class EndClass {
30 Branch,
31 IndirectBranch,
32 Call,
33 Exit,
34 Return,
35 Kill,
36};
37
38enum class Token {
39 SSY,
40 PBK,
41 PEXIT,
42 PRET,
43 PCNT,
44 PLONGJMP,
45};
46
47struct StackEntry {
48 auto operator<=>(const StackEntry&) const noexcept = default;
49
50 Token token;
51 Location target;
52};
53
54class Stack {
55public:
56 void Push(Token token, Location target);
57 [[nodiscard]] std::pair<Location, Stack> Pop(Token token) const;
58 [[nodiscard]] std::optional<Location> Peek(Token token) const;
59 [[nodiscard]] Stack Remove(Token token) const;
60
61private:
62 boost::container::small_vector<StackEntry, 3> entries;
63};
64
65struct IndirectBranch {
66 Block* block;
67 u32 address;
68};
69
70struct Block : boost::intrusive::set_base_hook<
71 // Normal link is ~2.5% faster compared to safe link
72 boost::intrusive::link_mode<boost::intrusive::normal_link>> {
73 [[nodiscard]] bool Contains(Location pc) const noexcept;
74
75 bool operator<(const Block& rhs) const noexcept {
76 return begin < rhs.begin;
77 }
78
79 Location begin;
80 Location end;
81 EndClass end_class{};
82 IR::Condition cond{};
83 Stack stack;
84 Block* branch_true{};
85 Block* branch_false{};
86 FunctionId function_call{};
87 Block* return_block{};
88 IR::Reg branch_reg{};
89 s32 branch_offset{};
90 std::vector<IndirectBranch> indirect_branches;
91};
92
93struct Label {
94 Location address;
95 Block* block;
96 Stack stack;
97};
98
99struct Function {
100 explicit Function(ObjectPool<Block>& block_pool, Location start_address);
101
102 Location entrypoint;
103 boost::container::small_vector<Label, 16> labels;
104 boost::intrusive::set<Block> blocks;
105};
106
107class CFG {
108 enum class AnalysisState {
109 Branch,
110 Continue,
111 };
112
113public:
114 explicit CFG(Environment& env, ObjectPool<Block>& block_pool, Location start_address,
115 bool exits_to_dispatcher = false);
116
117 CFG& operator=(const CFG&) = delete;
118 CFG(const CFG&) = delete;
119
120 CFG& operator=(CFG&&) = delete;
121 CFG(CFG&&) = delete;
122
123 [[nodiscard]] std::string Dot() const;
124
125 [[nodiscard]] std::span<const Function> Functions() const noexcept {
126 return std::span(functions.data(), functions.size());
127 }
128 [[nodiscard]] std::span<Function> Functions() noexcept {
129 return std::span(functions.data(), functions.size());
130 }
131
132 [[nodiscard]] bool ExitsToDispatcher() const {
133 return exits_to_dispatcher;
134 }
135
136private:
137 void AnalyzeLabel(FunctionId function_id, Label& label);
138
139 /// Inspect already visited blocks.
140 /// Return true when the block has already been visited
141 bool InspectVisitedBlocks(FunctionId function_id, const Label& label);
142
143 AnalysisState AnalyzeInst(Block* block, FunctionId function_id, Location pc);
144
145 void AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, EndClass insn_end_class,
146 IR::Condition cond);
147
148 /// Return true when the branch instruction is confirmed to be a branch
149 bool AnalyzeBranch(Block* block, FunctionId function_id, Location pc, Instruction inst,
150 Opcode opcode);
151
152 void AnalyzeBRA(Block* block, FunctionId function_id, Location pc, Instruction inst,
153 bool is_absolute);
154 AnalysisState AnalyzeBRX(Block* block, Location pc, Instruction inst, bool is_absolute,
155 FunctionId function_id);
156 AnalysisState AnalyzeEXIT(Block* block, FunctionId function_id, Location pc, Instruction inst);
157
158 /// Return the branch target block id
159 Block* AddLabel(Block* block, Stack stack, Location pc, FunctionId function_id);
160
161 Environment& env;
162 ObjectPool<Block>& block_pool;
163 boost::container::small_vector<Function, 1> functions;
164 Location program_start;
165 bool exits_to_dispatcher{};
166 Block* dispatch_block{};
167};
168
169} // namespace Shader::Maxwell::Flow