summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/ir/microinstruction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend/ir/microinstruction.cpp')
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp73
1 files changed, 48 insertions, 25 deletions
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index d6a9be87d..88e186f21 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -10,26 +10,27 @@
10#include "shader_recompiler/frontend/ir/type.h" 10#include "shader_recompiler/frontend/ir/type.h"
11 11
12namespace Shader::IR { 12namespace Shader::IR {
13 13namespace {
14static void CheckPseudoInstruction(IR::Inst* inst, IR::Opcode opcode) { 14void CheckPseudoInstruction(IR::Inst* inst, IR::Opcode opcode) {
15 if (inst && inst->Opcode() != opcode) { 15 if (inst && inst->Opcode() != opcode) {
16 throw LogicError("Invalid pseudo-instruction"); 16 throw LogicError("Invalid pseudo-instruction");
17 } 17 }
18} 18}
19 19
20static void SetPseudoInstruction(IR::Inst*& dest_inst, IR::Inst* pseudo_inst) { 20void SetPseudoInstruction(IR::Inst*& dest_inst, IR::Inst* pseudo_inst) {
21 if (dest_inst) { 21 if (dest_inst) {
22 throw LogicError("Only one of each type of pseudo-op allowed"); 22 throw LogicError("Only one of each type of pseudo-op allowed");
23 } 23 }
24 dest_inst = pseudo_inst; 24 dest_inst = pseudo_inst;
25} 25}
26 26
27static void RemovePseudoInstruction(IR::Inst*& inst, IR::Opcode expected_opcode) { 27void RemovePseudoInstruction(IR::Inst*& inst, IR::Opcode expected_opcode) {
28 if (inst->Opcode() != expected_opcode) { 28 if (inst->Opcode() != expected_opcode) {
29 throw LogicError("Undoing use of invalid pseudo-op"); 29 throw LogicError("Undoing use of invalid pseudo-op");
30 } 30 }
31 inst = nullptr; 31 inst = nullptr;
32} 32}
33} // Anonymous namespace
33 34
34Inst::Inst(IR::Opcode op_, u32 flags_) noexcept : op{op_}, flags{flags_} { 35Inst::Inst(IR::Opcode op_, u32 flags_) noexcept : op{op_}, flags{flags_} {
35 if (op == Opcode::Phi) { 36 if (op == Opcode::Phi) {
@@ -82,6 +83,7 @@ bool Inst::IsPseudoInstruction() const noexcept {
82 case Opcode::GetSignFromOp: 83 case Opcode::GetSignFromOp:
83 case Opcode::GetCarryFromOp: 84 case Opcode::GetCarryFromOp:
84 case Opcode::GetOverflowFromOp: 85 case Opcode::GetOverflowFromOp:
86 case Opcode::GetSparseFromOp:
85 return true; 87 return true;
86 default: 88 default:
87 return false; 89 return false;
@@ -96,25 +98,26 @@ bool Inst::AreAllArgsImmediates() const {
96 [](const IR::Value& value) { return value.IsImmediate(); }); 98 [](const IR::Value& value) { return value.IsImmediate(); });
97} 99}
98 100
99bool Inst::HasAssociatedPseudoOperation() const noexcept {
100 return zero_inst || sign_inst || carry_inst || overflow_inst;
101}
102
103Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) { 101Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) {
104 // This is faster than doing a search through the block. 102 if (!associated_insts) {
103 return nullptr;
104 }
105 switch (opcode) { 105 switch (opcode) {
106 case Opcode::GetZeroFromOp: 106 case Opcode::GetZeroFromOp:
107 CheckPseudoInstruction(zero_inst, Opcode::GetZeroFromOp); 107 CheckPseudoInstruction(associated_insts->zero_inst, Opcode::GetZeroFromOp);
108 return zero_inst; 108 return associated_insts->zero_inst;
109 case Opcode::GetSignFromOp: 109 case Opcode::GetSignFromOp:
110 CheckPseudoInstruction(sign_inst, Opcode::GetSignFromOp); 110 CheckPseudoInstruction(associated_insts->sign_inst, Opcode::GetSignFromOp);
111 return sign_inst; 111 return associated_insts->sign_inst;
112 case Opcode::GetCarryFromOp: 112 case Opcode::GetCarryFromOp:
113 CheckPseudoInstruction(carry_inst, Opcode::GetCarryFromOp); 113 CheckPseudoInstruction(associated_insts->carry_inst, Opcode::GetCarryFromOp);
114 return carry_inst; 114 return associated_insts->carry_inst;
115 case Opcode::GetOverflowFromOp: 115 case Opcode::GetOverflowFromOp:
116 CheckPseudoInstruction(overflow_inst, Opcode::GetOverflowFromOp); 116 CheckPseudoInstruction(associated_insts->overflow_inst, Opcode::GetOverflowFromOp);
117 return overflow_inst; 117 return associated_insts->overflow_inst;
118 case Opcode::GetSparseFromOp:
119 CheckPseudoInstruction(associated_insts->sparse_inst, Opcode::GetSparseFromOp);
120 return associated_insts->sparse_inst;
118 default: 121 default:
119 throw InvalidArgument("{} is not a pseudo-instruction", opcode); 122 throw InvalidArgument("{} is not a pseudo-instruction", opcode);
120 } 123 }
@@ -220,22 +223,37 @@ void Inst::ReplaceOpcode(IR::Opcode opcode) {
220 op = opcode; 223 op = opcode;
221} 224}
222 225
226void AllocAssociatedInsts(std::unique_ptr<AssociatedInsts>& associated_insts) {
227 if (!associated_insts) {
228 associated_insts = std::make_unique<AssociatedInsts>();
229 }
230}
231
223void Inst::Use(const Value& value) { 232void Inst::Use(const Value& value) {
224 Inst* const inst{value.Inst()}; 233 Inst* const inst{value.Inst()};
225 ++inst->use_count; 234 ++inst->use_count;
226 235
236 std::unique_ptr<AssociatedInsts>& assoc_inst{inst->associated_insts};
227 switch (op) { 237 switch (op) {
228 case Opcode::GetZeroFromOp: 238 case Opcode::GetZeroFromOp:
229 SetPseudoInstruction(inst->zero_inst, this); 239 AllocAssociatedInsts(assoc_inst);
240 SetPseudoInstruction(assoc_inst->zero_inst, this);
230 break; 241 break;
231 case Opcode::GetSignFromOp: 242 case Opcode::GetSignFromOp:
232 SetPseudoInstruction(inst->sign_inst, this); 243 AllocAssociatedInsts(assoc_inst);
244 SetPseudoInstruction(assoc_inst->sign_inst, this);
233 break; 245 break;
234 case Opcode::GetCarryFromOp: 246 case Opcode::GetCarryFromOp:
235 SetPseudoInstruction(inst->carry_inst, this); 247 AllocAssociatedInsts(assoc_inst);
248 SetPseudoInstruction(assoc_inst->carry_inst, this);
236 break; 249 break;
237 case Opcode::GetOverflowFromOp: 250 case Opcode::GetOverflowFromOp:
238 SetPseudoInstruction(inst->overflow_inst, this); 251 AllocAssociatedInsts(assoc_inst);
252 SetPseudoInstruction(assoc_inst->overflow_inst, this);
253 break;
254 case Opcode::GetSparseFromOp:
255 AllocAssociatedInsts(assoc_inst);
256 SetPseudoInstruction(assoc_inst->sparse_inst, this);
239 break; 257 break;
240 default: 258 default:
241 break; 259 break;
@@ -246,18 +264,23 @@ void Inst::UndoUse(const Value& value) {
246 Inst* const inst{value.Inst()}; 264 Inst* const inst{value.Inst()};
247 --inst->use_count; 265 --inst->use_count;
248 266
267 std::unique_ptr<AssociatedInsts>& assoc_inst{inst->associated_insts};
249 switch (op) { 268 switch (op) {
250 case Opcode::GetZeroFromOp: 269 case Opcode::GetZeroFromOp:
251 RemovePseudoInstruction(inst->zero_inst, Opcode::GetZeroFromOp); 270 AllocAssociatedInsts(assoc_inst);
271 RemovePseudoInstruction(assoc_inst->zero_inst, Opcode::GetZeroFromOp);
252 break; 272 break;
253 case Opcode::GetSignFromOp: 273 case Opcode::GetSignFromOp:
254 RemovePseudoInstruction(inst->sign_inst, Opcode::GetSignFromOp); 274 AllocAssociatedInsts(assoc_inst);
275 RemovePseudoInstruction(assoc_inst->sign_inst, Opcode::GetSignFromOp);
255 break; 276 break;
256 case Opcode::GetCarryFromOp: 277 case Opcode::GetCarryFromOp:
257 RemovePseudoInstruction(inst->carry_inst, Opcode::GetCarryFromOp); 278 AllocAssociatedInsts(assoc_inst);
279 RemovePseudoInstruction(assoc_inst->carry_inst, Opcode::GetCarryFromOp);
258 break; 280 break;
259 case Opcode::GetOverflowFromOp: 281 case Opcode::GetOverflowFromOp:
260 RemovePseudoInstruction(inst->overflow_inst, Opcode::GetOverflowFromOp); 282 AllocAssociatedInsts(assoc_inst);
283 RemovePseudoInstruction(assoc_inst->overflow_inst, Opcode::GetOverflowFromOp);
261 break; 284 break;
262 default: 285 default:
263 break; 286 break;