summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/ir/microinstruction.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-01-09 03:30:07 -0300
committerGravatar ameerj2021-07-22 21:51:21 -0400
commit2d48a7b4d0666ad16d03a22d85712617a0849046 (patch)
treedd1069afca86f66e77e3438da77421a43adf5091 /src/shader_recompiler/frontend/ir/microinstruction.cpp
parentthread_worker: Fix compile time error (diff)
downloadyuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar.gz
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.tar.xz
yuzu-2d48a7b4d0666ad16d03a22d85712617a0849046.zip
shader: Initial recompiler work
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
new file mode 100644
index 000000000..553fec3b7
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -0,0 +1,189 @@
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 "shader_recompiler/exception.h"
6#include "shader_recompiler/frontend/ir/microinstruction.h"
7#include "shader_recompiler/frontend/ir/type.h"
8
9namespace Shader::IR {
10
11static void CheckPseudoInstruction(IR::Inst* inst, IR::Opcode opcode) {
12 if (inst && inst->Opcode() != opcode) {
13 throw LogicError("Invalid pseudo-instruction");
14 }
15}
16
17static void SetPseudoInstruction(IR::Inst*& dest_inst, IR::Inst* pseudo_inst) {
18 if (dest_inst) {
19 throw LogicError("Only one of each type of pseudo-op allowed");
20 }
21 dest_inst = pseudo_inst;
22}
23
24static void RemovePseudoInstruction(IR::Inst*& inst, IR::Opcode expected_opcode) {
25 if (inst->Opcode() != expected_opcode) {
26 throw LogicError("Undoing use of invalid pseudo-op");
27 }
28 inst = nullptr;
29}
30
31bool Inst::MayHaveSideEffects() const noexcept {
32 switch (op) {
33 case Opcode::SetAttribute:
34 case Opcode::SetAttributeIndexed:
35 case Opcode::WriteGlobalU8:
36 case Opcode::WriteGlobalS8:
37 case Opcode::WriteGlobalU16:
38 case Opcode::WriteGlobalS16:
39 case Opcode::WriteGlobal32:
40 case Opcode::WriteGlobal64:
41 case Opcode::WriteGlobal128:
42 return true;
43 default:
44 return false;
45 }
46}
47
48bool Inst::IsPseudoInstruction() const noexcept {
49 switch (op) {
50 case Opcode::GetZeroFromOp:
51 case Opcode::GetSignFromOp:
52 case Opcode::GetCarryFromOp:
53 case Opcode::GetOverflowFromOp:
54 case Opcode::GetZSCOFromOp:
55 return true;
56 default:
57 return false;
58 }
59}
60
61bool Inst::HasAssociatedPseudoOperation() const noexcept {
62 return zero_inst || sign_inst || carry_inst || overflow_inst || zsco_inst;
63}
64
65Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) {
66 // This is faster than doing a search through the block.
67 switch (opcode) {
68 case Opcode::GetZeroFromOp:
69 CheckPseudoInstruction(zero_inst, Opcode::GetZeroFromOp);
70 return zero_inst;
71 case Opcode::GetSignFromOp:
72 CheckPseudoInstruction(sign_inst, Opcode::GetSignFromOp);
73 return sign_inst;
74 case Opcode::GetCarryFromOp:
75 CheckPseudoInstruction(carry_inst, Opcode::GetCarryFromOp);
76 return carry_inst;
77 case Opcode::GetOverflowFromOp:
78 CheckPseudoInstruction(overflow_inst, Opcode::GetOverflowFromOp);
79 return overflow_inst;
80 case Opcode::GetZSCOFromOp:
81 CheckPseudoInstruction(zsco_inst, Opcode::GetZSCOFromOp);
82 return zsco_inst;
83 default:
84 throw InvalidArgument("{} is not a pseudo-instruction", opcode);
85 }
86}
87
88size_t Inst::NumArgs() const {
89 return NumArgsOf(op);
90}
91
92IR::Type Inst::Type() const {
93 return TypeOf(op);
94}
95
96Value Inst::Arg(size_t index) const {
97 if (index >= NumArgsOf(op)) {
98 throw InvalidArgument("Out of bounds argument index {} in opcode {}", index, op);
99 }
100 return args[index];
101}
102
103void Inst::SetArg(size_t index, Value value) {
104 if (index >= NumArgsOf(op)) {
105 throw InvalidArgument("Out of bounds argument index {} in opcode {}", index, op);
106 }
107 if (!args[index].IsImmediate()) {
108 UndoUse(args[index]);
109 }
110 if (!value.IsImmediate()) {
111 Use(value);
112 }
113 args[index] = value;
114}
115
116void Inst::Invalidate() {
117 ClearArgs();
118 op = Opcode::Void;
119}
120
121void Inst::ClearArgs() {
122 for (auto& value : args) {
123 if (!value.IsImmediate()) {
124 UndoUse(value);
125 }
126 value = {};
127 }
128}
129
130void Inst::ReplaceUsesWith(Value replacement) {
131 Invalidate();
132
133 op = Opcode::Identity;
134
135 if (!replacement.IsImmediate()) {
136 Use(replacement);
137 }
138 args[0] = replacement;
139}
140
141void Inst::Use(const Value& value) {
142 ++value.Inst()->use_count;
143
144 switch (op) {
145 case Opcode::GetZeroFromOp:
146 SetPseudoInstruction(value.Inst()->zero_inst, this);
147 break;
148 case Opcode::GetSignFromOp:
149 SetPseudoInstruction(value.Inst()->sign_inst, this);
150 break;
151 case Opcode::GetCarryFromOp:
152 SetPseudoInstruction(value.Inst()->carry_inst, this);
153 break;
154 case Opcode::GetOverflowFromOp:
155 SetPseudoInstruction(value.Inst()->overflow_inst, this);
156 break;
157 case Opcode::GetZSCOFromOp:
158 SetPseudoInstruction(value.Inst()->zsco_inst, this);
159 break;
160 default:
161 break;
162 }
163}
164
165void Inst::UndoUse(const Value& value) {
166 --value.Inst()->use_count;
167
168 switch (op) {
169 case Opcode::GetZeroFromOp:
170 RemovePseudoInstruction(value.Inst()->zero_inst, Opcode::GetZeroFromOp);
171 break;
172 case Opcode::GetSignFromOp:
173 RemovePseudoInstruction(value.Inst()->sign_inst, Opcode::GetSignFromOp);
174 break;
175 case Opcode::GetCarryFromOp:
176 RemovePseudoInstruction(value.Inst()->carry_inst, Opcode::GetCarryFromOp);
177 break;
178 case Opcode::GetOverflowFromOp:
179 RemovePseudoInstruction(value.Inst()->overflow_inst, Opcode::GetOverflowFromOp);
180 break;
181 case Opcode::GetZSCOFromOp:
182 RemovePseudoInstruction(value.Inst()->zsco_inst, Opcode::GetZSCOFromOp);
183 break;
184 default:
185 break;
186 }
187}
188
189} // namespace Shader::IR