summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/ir
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/frontend/ir/basic_block.cpp51
-rw-r--r--src/shader_recompiler/frontend/ir/basic_block.h20
-rw-r--r--src/shader_recompiler/frontend/ir/function.cpp5
-rw-r--r--src/shader_recompiler/frontend/ir/function.h25
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp22
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.h10
-rw-r--r--src/shader_recompiler/frontend/ir/opcode.inc8
-rw-r--r--src/shader_recompiler/frontend/ir/pred.h7
-rw-r--r--src/shader_recompiler/frontend/ir/reg.h9
-rw-r--r--src/shader_recompiler/frontend/ir/value.cpp37
-rw-r--r--src/shader_recompiler/frontend/ir/value.h3
11 files changed, 178 insertions, 19 deletions
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp
index 0406726ad..e795618fc 100644
--- a/src/shader_recompiler/frontend/ir/basic_block.cpp
+++ b/src/shader_recompiler/frontend/ir/basic_block.cpp
@@ -37,6 +37,10 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op,
37 return result_it; 37 return result_it;
38} 38}
39 39
40void Block::AddImmediatePredecessor(IR::Block* immediate_predecessor) {
41 imm_predecessors.push_back(immediate_predecessor);
42}
43
40u32 Block::LocationBegin() const noexcept { 44u32 Block::LocationBegin() const noexcept {
41 return location_begin; 45 return location_begin;
42} 46}
@@ -53,6 +57,18 @@ const Block::InstructionList& Block::Instructions() const noexcept {
53 return instructions; 57 return instructions;
54} 58}
55 59
60std::span<IR::Block* const> Block::ImmediatePredecessors() const noexcept {
61 return imm_predecessors;
62}
63
64static std::string BlockToIndex(const std::map<const Block*, size_t>& block_to_index,
65 Block* block) {
66 if (const auto it{block_to_index.find(block)}; it != block_to_index.end()) {
67 return fmt::format("{{Block ${}}}", it->second);
68 }
69 return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(block));
70}
71
56static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index, 72static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index,
57 const std::map<const Inst*, size_t>& inst_to_index, 73 const std::map<const Inst*, size_t>& inst_to_index,
58 const Value& arg) { 74 const Value& arg) {
@@ -60,10 +76,7 @@ static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_ind
60 return "<null>"; 76 return "<null>";
61 } 77 }
62 if (arg.IsLabel()) { 78 if (arg.IsLabel()) {
63 if (const auto it{block_to_index.find(arg.Label())}; it != block_to_index.end()) { 79 return BlockToIndex(block_to_index, arg.Label());
64 return fmt::format("{{Block ${}}}", it->second);
65 }
66 return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(arg.Label()));
67 } 80 }
68 if (!arg.IsImmediate()) { 81 if (!arg.IsImmediate()) {
69 if (const auto it{inst_to_index.find(arg.Inst())}; it != inst_to_index.end()) { 82 if (const auto it{inst_to_index.find(arg.Inst())}; it != inst_to_index.end()) {
@@ -115,16 +128,26 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>&
115 } else { 128 } else {
116 ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces 129 ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
117 } 130 }
118 const size_t arg_count{NumArgsOf(op)}; 131 if (op == Opcode::Phi) {
119 for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) { 132 size_t val_index{0};
120 const Value arg{inst.Arg(arg_index)}; 133 for (const auto& [phi_block, phi_val] : inst.PhiOperands()) {
121 ret += arg_index != 0 ? ", " : " "; 134 ret += val_index != 0 ? ", " : " ";
122 ret += ArgToIndex(block_to_index, inst_to_index, arg); 135 ret += fmt::format("[ {}, {} ]", ArgToIndex(block_to_index, inst_to_index, phi_val),
123 136 BlockToIndex(block_to_index, phi_block));
124 const Type actual_type{arg.Type()}; 137 ++val_index;
125 const Type expected_type{ArgTypeOf(op, arg_index)}; 138 }
126 if (!AreTypesCompatible(actual_type, expected_type)) { 139 } else {
127 ret += fmt::format("<type error: {} != {}>", actual_type, expected_type); 140 const size_t arg_count{NumArgsOf(op)};
141 for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) {
142 const Value arg{inst.Arg(arg_index)};
143 ret += arg_index != 0 ? ", " : " ";
144 ret += ArgToIndex(block_to_index, inst_to_index, arg);
145
146 const Type actual_type{arg.Type()};
147 const Type expected_type{ArgTypeOf(op, arg_index)};
148 if (!AreTypesCompatible(actual_type, expected_type)) {
149 ret += fmt::format("<type error: {} != {}>", actual_type, expected_type);
150 }
128 } 151 }
129 } 152 }
130 if (TypeOf(op) != Type::Void) { 153 if (TypeOf(op) != Type::Void) {
diff --git a/src/shader_recompiler/frontend/ir/basic_block.h b/src/shader_recompiler/frontend/ir/basic_block.h
index 3ed2eb957..4b6b80c4b 100644
--- a/src/shader_recompiler/frontend/ir/basic_block.h
+++ b/src/shader_recompiler/frontend/ir/basic_block.h
@@ -6,6 +6,8 @@
6 6
7#include <initializer_list> 7#include <initializer_list>
8#include <map> 8#include <map>
9#include <span>
10#include <vector>
9 11
10#include <boost/intrusive/list.hpp> 12#include <boost/intrusive/list.hpp>
11#include <boost/pool/pool_alloc.hpp> 13#include <boost/pool/pool_alloc.hpp>
@@ -36,7 +38,11 @@ public:
36 void AppendNewInst(Opcode op, std::initializer_list<Value> args); 38 void AppendNewInst(Opcode op, std::initializer_list<Value> args);
37 39
38 /// Prepends a new instruction to this basic block before the insertion point. 40 /// Prepends a new instruction to this basic block before the insertion point.
39 iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args); 41 iterator PrependNewInst(iterator insertion_point, Opcode op,
42 std::initializer_list<Value> args = {});
43
44 /// Adds a new immediate predecessor to the basic block.
45 void AddImmediatePredecessor(IR::Block* immediate_predecessor);
40 46
41 /// Gets the starting location of this basic block. 47 /// Gets the starting location of this basic block.
42 [[nodiscard]] u32 LocationBegin() const noexcept; 48 [[nodiscard]] u32 LocationBegin() const noexcept;
@@ -44,9 +50,12 @@ public:
44 [[nodiscard]] u32 LocationEnd() const noexcept; 50 [[nodiscard]] u32 LocationEnd() const noexcept;
45 51
46 /// Gets a mutable reference to the instruction list for this basic block. 52 /// Gets a mutable reference to the instruction list for this basic block.
47 InstructionList& Instructions() noexcept; 53 [[nodiscard]] InstructionList& Instructions() noexcept;
48 /// Gets an immutable reference to the instruction list for this basic block. 54 /// Gets an immutable reference to the instruction list for this basic block.
49 const InstructionList& Instructions() const noexcept; 55 [[nodiscard]] const InstructionList& Instructions() const noexcept;
56
57 /// Gets an immutable span to the immediate predecessors.
58 [[nodiscard]] std::span<IR::Block* const> ImmediatePredecessors() const noexcept;
50 59
51 [[nodiscard]] bool empty() const { 60 [[nodiscard]] bool empty() const {
52 return instructions.empty(); 61 return instructions.empty();
@@ -115,13 +124,16 @@ private:
115 /// End location of this block 124 /// End location of this block
116 u32 location_end; 125 u32 location_end;
117 126
118 /// List of instructions in this block. 127 /// List of instructions in this block
119 InstructionList instructions; 128 InstructionList instructions;
120 129
121 /// Memory pool for instruction list 130 /// Memory pool for instruction list
122 boost::fast_pool_allocator<Inst, boost::default_user_allocator_malloc_free, 131 boost::fast_pool_allocator<Inst, boost::default_user_allocator_malloc_free,
123 boost::details::pool::null_mutex> 132 boost::details::pool::null_mutex>
124 instruction_alloc_pool; 133 instruction_alloc_pool;
134
135 /// Block immediate predecessors
136 std::vector<IR::Block*> imm_predecessors;
125}; 137};
126 138
127[[nodiscard]] std::string DumpBlock(const Block& block); 139[[nodiscard]] std::string DumpBlock(const Block& block);
diff --git a/src/shader_recompiler/frontend/ir/function.cpp b/src/shader_recompiler/frontend/ir/function.cpp
new file mode 100644
index 000000000..d1fc9461d
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/function.cpp
@@ -0,0 +1,5 @@
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/frontend/ir/function.h"
diff --git a/src/shader_recompiler/frontend/ir/function.h b/src/shader_recompiler/frontend/ir/function.h
new file mode 100644
index 000000000..2d4dc5b98
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/function.h
@@ -0,0 +1,25 @@
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 <memory>
8#include <vector>
9
10#include "shader_recompiler/frontend/ir/basic_block.h"
11
12namespace Shader::IR {
13
14struct Function {
15 struct InplaceDelete {
16 void operator()(IR::Block* block) const noexcept {
17 std::destroy_at(block);
18 }
19 };
20 using UniqueBlock = std::unique_ptr<IR::Block, InplaceDelete>;
21
22 std::vector<UniqueBlock> blocks;
23};
24
25} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index 553fec3b7..ecf76e23d 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -30,6 +30,11 @@ static void RemovePseudoInstruction(IR::Inst*& inst, IR::Opcode expected_opcode)
30 30
31bool Inst::MayHaveSideEffects() const noexcept { 31bool Inst::MayHaveSideEffects() const noexcept {
32 switch (op) { 32 switch (op) {
33 case Opcode::Branch:
34 case Opcode::BranchConditional:
35 case Opcode::Exit:
36 case Opcode::Return:
37 case Opcode::Unreachable:
33 case Opcode::SetAttribute: 38 case Opcode::SetAttribute:
34 case Opcode::SetAttributeIndexed: 39 case Opcode::SetAttributeIndexed:
35 case Opcode::WriteGlobalU8: 40 case Opcode::WriteGlobalU8:
@@ -113,6 +118,17 @@ void Inst::SetArg(size_t index, Value value) {
113 args[index] = value; 118 args[index] = value;
114} 119}
115 120
121std::span<const std::pair<Block*, Value>> Inst::PhiOperands() const noexcept {
122 return phi_operands;
123}
124
125void Inst::AddPhiOperand(Block* predecessor, const Value& value) {
126 if (!value.IsImmediate()) {
127 Use(value);
128 }
129 phi_operands.emplace_back(predecessor, value);
130}
131
116void Inst::Invalidate() { 132void Inst::Invalidate() {
117 ClearArgs(); 133 ClearArgs();
118 op = Opcode::Void; 134 op = Opcode::Void;
@@ -125,6 +141,12 @@ void Inst::ClearArgs() {
125 } 141 }
126 value = {}; 142 value = {};
127 } 143 }
144 for (auto& [phi_block, phi_op] : phi_operands) {
145 if (!phi_op.IsImmediate()) {
146 UndoUse(phi_op);
147 }
148 }
149 phi_operands.clear();
128} 150}
129 151
130void Inst::ReplaceUsesWith(Value replacement) { 152void Inst::ReplaceUsesWith(Value replacement) {
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h
index 43460b950..7f1ed6710 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.h
+++ b/src/shader_recompiler/frontend/ir/microinstruction.h
@@ -5,6 +5,8 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <span>
9#include <vector>
8 10
9#include <boost/intrusive/list.hpp> 11#include <boost/intrusive/list.hpp>
10 12
@@ -15,6 +17,8 @@
15 17
16namespace Shader::IR { 18namespace Shader::IR {
17 19
20class Block;
21
18constexpr size_t MAX_ARG_COUNT = 4; 22constexpr size_t MAX_ARG_COUNT = 4;
19 23
20class Inst : public boost::intrusive::list_base_hook<> { 24class Inst : public boost::intrusive::list_base_hook<> {
@@ -59,6 +63,11 @@ public:
59 /// Set the value of a given argument index. 63 /// Set the value of a given argument index.
60 void SetArg(size_t index, Value value); 64 void SetArg(size_t index, Value value);
61 65
66 /// Get an immutable span to the phi operands.
67 [[nodiscard]] std::span<const std::pair<Block*, Value>> PhiOperands() const noexcept;
68 /// Add phi operand to a phi instruction.
69 void AddPhiOperand(Block* predecessor, const Value& value);
70
62 void Invalidate(); 71 void Invalidate();
63 void ClearArgs(); 72 void ClearArgs();
64 73
@@ -76,6 +85,7 @@ private:
76 Inst* carry_inst{}; 85 Inst* carry_inst{};
77 Inst* overflow_inst{}; 86 Inst* overflow_inst{};
78 Inst* zsco_inst{}; 87 Inst* zsco_inst{};
88 std::vector<std::pair<Block*, Value>> phi_operands;
79 u64 flags{}; 89 u64 flags{};
80}; 90};
81 91
diff --git a/src/shader_recompiler/frontend/ir/opcode.inc b/src/shader_recompiler/frontend/ir/opcode.inc
index 371064bf3..40759e96a 100644
--- a/src/shader_recompiler/frontend/ir/opcode.inc
+++ b/src/shader_recompiler/frontend/ir/opcode.inc
@@ -5,6 +5,7 @@
5// opcode name, return type, arg1 type, arg2 type, arg3 type, arg4 type, ... 5// opcode name, return type, arg1 type, arg2 type, arg3 type, arg4 type, ...
6OPCODE(Void, Void, ) 6OPCODE(Void, Void, )
7OPCODE(Identity, Opaque, Opaque, ) 7OPCODE(Identity, Opaque, Opaque, )
8OPCODE(Phi, Opaque, /*todo*/ )
8 9
9// Control flow 10// Control flow
10OPCODE(Branch, Void, Label, ) 11OPCODE(Branch, Void, Label, )
@@ -35,6 +36,13 @@ OPCODE(SetSFlag, Void, U1,
35OPCODE(SetCFlag, Void, U1, ) 36OPCODE(SetCFlag, Void, U1, )
36OPCODE(SetOFlag, Void, U1, ) 37OPCODE(SetOFlag, Void, U1, )
37 38
39// Undefined
40OPCODE(Undef1, U1, )
41OPCODE(Undef8, U8, )
42OPCODE(Undef16, U16, )
43OPCODE(Undef32, U32, )
44OPCODE(Undef64, U64, )
45
38// Memory operations 46// Memory operations
39OPCODE(WriteGlobalU8, Void, U64, U32, ) 47OPCODE(WriteGlobalU8, Void, U64, U32, )
40OPCODE(WriteGlobalS8, Void, U64, U32, ) 48OPCODE(WriteGlobalS8, Void, U64, U32, )
diff --git a/src/shader_recompiler/frontend/ir/pred.h b/src/shader_recompiler/frontend/ir/pred.h
index 37cc53006..daf23193f 100644
--- a/src/shader_recompiler/frontend/ir/pred.h
+++ b/src/shader_recompiler/frontend/ir/pred.h
@@ -10,6 +10,13 @@ namespace Shader::IR {
10 10
11enum class Pred { P0, P1, P2, P3, P4, P5, P6, PT }; 11enum class Pred { P0, P1, P2, P3, P4, P5, P6, PT };
12 12
13constexpr size_t NUM_USER_PREDS = 6;
14constexpr size_t NUM_PREDS = 7;
15
16[[nodiscard]] constexpr size_t PredIndex(Pred pred) noexcept {
17 return static_cast<size_t>(pred);
18}
19
13} // namespace Shader::IR 20} // namespace Shader::IR
14 21
15template <> 22template <>
diff --git a/src/shader_recompiler/frontend/ir/reg.h b/src/shader_recompiler/frontend/ir/reg.h
index 316fc4be8..771094eb9 100644
--- a/src/shader_recompiler/frontend/ir/reg.h
+++ b/src/shader_recompiler/frontend/ir/reg.h
@@ -271,6 +271,9 @@ enum class Reg : u64 {
271}; 271};
272static_assert(static_cast<int>(Reg::RZ) == 255); 272static_assert(static_cast<int>(Reg::RZ) == 255);
273 273
274constexpr size_t NUM_USER_REGS = 255;
275constexpr size_t NUM_REGS = 256;
276
274[[nodiscard]] constexpr Reg operator+(Reg reg, int num) { 277[[nodiscard]] constexpr Reg operator+(Reg reg, int num) {
275 if (reg == Reg::RZ) { 278 if (reg == Reg::RZ) {
276 // Adding or subtracting registers from RZ yields RZ 279 // Adding or subtracting registers from RZ yields RZ
@@ -290,8 +293,12 @@ static_assert(static_cast<int>(Reg::RZ) == 255);
290 return reg + (-num); 293 return reg + (-num);
291} 294}
292 295
296[[nodiscard]] constexpr size_t RegIndex(Reg reg) noexcept {
297 return static_cast<size_t>(reg);
298}
299
293[[nodiscard]] constexpr bool IsAligned(Reg reg, size_t align) { 300[[nodiscard]] constexpr bool IsAligned(Reg reg, size_t align) {
294 return (static_cast<size_t>(reg) / align) * align == static_cast<size_t>(reg); 301 return (RegIndex(reg) / align) * align == RegIndex(reg);
295} 302}
296 303
297} // namespace Shader::IR 304} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp
index 7b5b35d6c..1e974e88c 100644
--- a/src/shader_recompiler/frontend/ir/value.cpp
+++ b/src/shader_recompiler/frontend/ir/value.cpp
@@ -115,6 +115,43 @@ u64 Value::U64() const {
115 return imm_u64; 115 return imm_u64;
116} 116}
117 117
118bool Value::operator==(const Value& other) const {
119 if (type != other.type) {
120 return false;
121 }
122 switch (type) {
123 case Type::Void:
124 return true;
125 case Type::Opaque:
126 return inst == other.inst;
127 case Type::Label:
128 return label == other.label;
129 case Type::Reg:
130 return reg == other.reg;
131 case Type::Pred:
132 return pred == other.pred;
133 case Type::Attribute:
134 return attribute == other.attribute;
135 case Type::U1:
136 return imm_u1 == other.imm_u1;
137 case Type::U8:
138 return imm_u8 == other.imm_u8;
139 case Type::U16:
140 return imm_u16 == other.imm_u16;
141 case Type::U32:
142 return imm_u32 == other.imm_u32;
143 case Type::U64:
144 return imm_u64 == other.imm_u64;
145 case Type::ZSCO:
146 throw NotImplementedException("ZSCO comparison");
147 }
148 throw LogicError("Invalid type {}", type);
149}
150
151bool Value::operator!=(const Value& other) const {
152 return !operator==(other);
153}
154
118void Value::ValidateAccess(IR::Type expected) const { 155void Value::ValidateAccess(IR::Type expected) const {
119 if (type != expected) { 156 if (type != expected) {
120 throw LogicError("Reading {} out of {}", expected, type); 157 throw LogicError("Reading {} out of {}", expected, type);
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index 664dacf9d..368119921 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -48,6 +48,9 @@ public:
48 [[nodiscard]] u32 U32() const; 48 [[nodiscard]] u32 U32() const;
49 [[nodiscard]] u64 U64() const; 49 [[nodiscard]] u64 U64() const;
50 50
51 [[nodiscard]] bool operator==(const Value& other) const;
52 [[nodiscard]] bool operator!=(const Value& other) const;
53
51private: 54private:
52 void ValidateAccess(IR::Type expected) const; 55 void ValidateAccess(IR::Type expected) const;
53 56