summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/ir/basic_block.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/frontend/ir/basic_block.cpp')
-rw-r--r--src/shader_recompiler/frontend/ir/basic_block.cpp142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp
new file mode 100644
index 000000000..0406726ad
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/basic_block.cpp
@@ -0,0 +1,142 @@
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 <algorithm>
6#include <initializer_list>
7#include <map>
8#include <memory>
9
10#include "common/bit_cast.h"
11#include "common/common_types.h"
12#include "shader_recompiler/frontend/ir/basic_block.h"
13#include "shader_recompiler/frontend/ir/value.h"
14
15namespace Shader::IR {
16
17Block::Block(u32 begin, u32 end) : location_begin{begin}, location_end{end} {}
18
19Block::~Block() = default;
20
21void Block::AppendNewInst(Opcode op, std::initializer_list<Value> args) {
22 PrependNewInst(end(), op, args);
23}
24
25Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op,
26 std::initializer_list<Value> args) {
27 Inst* const inst{std::construct_at(instruction_alloc_pool.allocate(), op)};
28 const auto result_it{instructions.insert(insertion_point, *inst)};
29
30 if (inst->NumArgs() != args.size()) {
31 throw InvalidArgument("Invalid number of arguments {} in {}", args.size(), op);
32 }
33 std::ranges::for_each(args, [inst, index = size_t{0}](const Value& arg) mutable {
34 inst->SetArg(index, arg);
35 ++index;
36 });
37 return result_it;
38}
39
40u32 Block::LocationBegin() const noexcept {
41 return location_begin;
42}
43
44u32 Block::LocationEnd() const noexcept {
45 return location_end;
46}
47
48Block::InstructionList& Block::Instructions() noexcept {
49 return instructions;
50}
51
52const Block::InstructionList& Block::Instructions() const noexcept {
53 return instructions;
54}
55
56static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index,
57 const std::map<const Inst*, size_t>& inst_to_index,
58 const Value& arg) {
59 if (arg.IsEmpty()) {
60 return "<null>";
61 }
62 if (arg.IsLabel()) {
63 if (const auto it{block_to_index.find(arg.Label())}; it != block_to_index.end()) {
64 return fmt::format("{{Block ${}}}", it->second);
65 }
66 return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(arg.Label()));
67 }
68 if (!arg.IsImmediate()) {
69 if (const auto it{inst_to_index.find(arg.Inst())}; it != inst_to_index.end()) {
70 return fmt::format("%{}", it->second);
71 }
72 return fmt::format("%<unknown inst {:016x}>", reinterpret_cast<u64>(arg.Inst()));
73 }
74 switch (arg.Type()) {
75 case Type::U1:
76 return fmt::format("#{}", arg.U1() ? '1' : '0');
77 case Type::U8:
78 return fmt::format("#{}", arg.U8());
79 case Type::U16:
80 return fmt::format("#{}", arg.U16());
81 case Type::U32:
82 return fmt::format("#{}", arg.U32());
83 case Type::U64:
84 return fmt::format("#{}", arg.U64());
85 case Type::Reg:
86 return fmt::format("{}", arg.Reg());
87 case Type::Pred:
88 return fmt::format("{}", arg.Pred());
89 case Type::Attribute:
90 return fmt::format("{}", arg.Attribute());
91 default:
92 return "<unknown immediate type>";
93 }
94}
95
96std::string DumpBlock(const Block& block) {
97 size_t inst_index{0};
98 std::map<const Inst*, size_t> inst_to_index;
99 return DumpBlock(block, {}, inst_to_index, inst_index);
100}
101
102std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>& block_to_index,
103 std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index) {
104 std::string ret{"Block"};
105 if (const auto it{block_to_index.find(&block)}; it != block_to_index.end()) {
106 ret += fmt::format(" ${}", it->second);
107 }
108 ret += fmt::format(": begin={:04x} end={:04x}\n", block.LocationBegin(), block.LocationEnd());
109
110 for (const Inst& inst : block) {
111 const Opcode op{inst.Opcode()};
112 ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst));
113 if (TypeOf(op) != Type::Void) {
114 ret += fmt::format("%{:<5} = {}", inst_index, op);
115 } else {
116 ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
117 }
118 const size_t arg_count{NumArgsOf(op)};
119 for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) {
120 const Value arg{inst.Arg(arg_index)};
121 ret += arg_index != 0 ? ", " : " ";
122 ret += ArgToIndex(block_to_index, inst_to_index, arg);
123
124 const Type actual_type{arg.Type()};
125 const Type expected_type{ArgTypeOf(op, arg_index)};
126 if (!AreTypesCompatible(actual_type, expected_type)) {
127 ret += fmt::format("<type error: {} != {}>", actual_type, expected_type);
128 }
129 }
130 if (TypeOf(op) != Type::Void) {
131 ret += fmt::format(" (uses: {})\n", inst.UseCount());
132 } else {
133 ret += '\n';
134 }
135
136 inst_to_index.emplace(&inst, inst_index);
137 ++inst_index;
138 }
139 return ret;
140}
141
142} // namespace Shader::IR