add use tracking for Insts

This commit is contained in:
Frodo Baggins 2024-10-21 16:41:02 -07:00
parent 7b16085c59
commit 6036cc8f79
3 changed files with 29 additions and 22 deletions

View File

@ -1,6 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <span> #include <span>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

View File

@ -116,10 +116,10 @@ void Inst::SetArg(size_t index, Value value) {
} }
const IR::Value arg{Arg(index)}; const IR::Value arg{Arg(index)};
if (!arg.IsImmediate()) { if (!arg.IsImmediate()) {
UndoUse(arg); UndoUse(arg.Inst());
} }
if (!value.IsImmediate()) { if (!value.IsImmediate()) {
Use(value); Use(value.Inst(), index);
} }
if (op == Opcode::Phi) { if (op == Opcode::Phi) {
phi_args[index].second = value; phi_args[index].second = value;
@ -140,12 +140,13 @@ Block* Inst::PhiBlock(size_t index) const {
void Inst::AddPhiOperand(Block* predecessor, const Value& value) { void Inst::AddPhiOperand(Block* predecessor, const Value& value) {
if (!value.IsImmediate()) { if (!value.IsImmediate()) {
Use(value); Use(value.Inst(), phi_args.size());
} }
phi_args.emplace_back(predecessor, value); phi_args.emplace_back(predecessor, value);
} }
void Inst::Invalidate() { void Inst::Invalidate() {
ASSERT(uses.empty());
ClearArgs(); ClearArgs();
ReplaceOpcode(Opcode::Void); ReplaceOpcode(Opcode::Void);
} }
@ -155,14 +156,14 @@ void Inst::ClearArgs() {
for (auto& pair : phi_args) { for (auto& pair : phi_args) {
IR::Value& value{pair.second}; IR::Value& value{pair.second};
if (!value.IsImmediate()) { if (!value.IsImmediate()) {
UndoUse(value); UndoUse(value.Inst());
} }
} }
phi_args.clear(); phi_args.clear();
} else { } else {
for (auto& value : args) { for (auto& value : args) {
if (!value.IsImmediate()) { if (!value.IsImmediate()) {
UndoUse(value); UndoUse(value.Inst());
} }
} }
// Reset arguments to null // Reset arguments to null
@ -172,12 +173,13 @@ void Inst::ClearArgs() {
} }
void Inst::ReplaceUsesWith(Value replacement) { void Inst::ReplaceUsesWith(Value replacement) {
Invalidate();
ReplaceOpcode(Opcode::Identity);
if (!replacement.IsImmediate()) { if (!replacement.IsImmediate()) {
Use(replacement); for (auto& [user, operand] : uses) {
user->SetArg(operand, replacement);
}
} }
args[0] = replacement; uses.clear();
Invalidate();
} }
void Inst::ReplaceOpcode(IR::Opcode opcode) { void Inst::ReplaceOpcode(IR::Opcode opcode) {
@ -192,14 +194,12 @@ void Inst::ReplaceOpcode(IR::Opcode opcode) {
op = opcode; op = opcode;
} }
void Inst::Use(const Value& value) { void Inst::Use(Inst* used, u32 operand) {
Inst* const inst{value.Inst()}; used->uses.emplace_front(this, operand);
++inst->use_count;
} }
void Inst::UndoUse(const Value& value) { void Inst::UndoUse(Inst* used) {
Inst* const inst{value.Inst()}; used->uses.remove_if([this](const IR::Use& use) { return use.user == this; });
--inst->use_count;
} }
} // namespace Shader::IR } // namespace Shader::IR

View File

@ -8,6 +8,7 @@
#include <cstring> #include <cstring>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <boost/container/list.hpp>
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include <boost/intrusive/list.hpp> #include <boost/intrusive/list.hpp>
@ -15,6 +16,7 @@
#include "shader_recompiler/exception.h" #include "shader_recompiler/exception.h"
#include "shader_recompiler/ir/attribute.h" #include "shader_recompiler/ir/attribute.h"
#include "shader_recompiler/ir/opcodes.h" #include "shader_recompiler/ir/opcodes.h"
#include "shader_recompiler/ir/patch.h"
#include "shader_recompiler/ir/reg.h" #include "shader_recompiler/ir/reg.h"
#include "shader_recompiler/ir/type.h" #include "shader_recompiler/ir/type.h"
@ -104,6 +106,11 @@ public:
explicit TypedValue(IR::Inst* inst_) : TypedValue(Value(inst_)) {} explicit TypedValue(IR::Inst* inst_) : TypedValue(Value(inst_)) {}
}; };
struct Use {
Inst* user;
u32 operand;
};
class Inst : public boost::intrusive::list_base_hook<> { class Inst : public boost::intrusive::list_base_hook<> {
public: public:
explicit Inst(IR::Opcode op_, u32 flags_) noexcept; explicit Inst(IR::Opcode op_, u32 flags_) noexcept;
@ -117,12 +124,12 @@ public:
/// Get the number of uses this instruction has. /// Get the number of uses this instruction has.
[[nodiscard]] int UseCount() const noexcept { [[nodiscard]] int UseCount() const noexcept {
return use_count; return uses.size();
} }
/// Determines whether this instruction has uses or not. /// Determines whether this instruction has uses or not.
[[nodiscard]] bool HasUses() const noexcept { [[nodiscard]] bool HasUses() const noexcept {
return use_count > 0; return uses.size() > 0;
} }
/// Get the opcode this microinstruction represents. /// Get the opcode this microinstruction represents.
@ -199,11 +206,10 @@ private:
NonTriviallyDummy() noexcept {} NonTriviallyDummy() noexcept {}
}; };
void Use(const Value& value); void Use(Inst* used, u32 operand);
void UndoUse(const Value& value); void UndoUse(Inst* used);
IR::Opcode op{}; IR::Opcode op{};
int use_count{};
u32 flags{}; u32 flags{};
u32 definition{}; u32 definition{};
union { union {
@ -211,8 +217,10 @@ private:
boost::container::small_vector<std::pair<Block*, Value>, 2> phi_args; boost::container::small_vector<std::pair<Block*, Value>, 2> phi_args;
std::array<Value, 6> args; std::array<Value, 6> args;
}; };
boost::container::list<IR::Use> uses;
}; };
static_assert(sizeof(Inst) <= 128, "Inst size unintentionally increased"); static_assert(sizeof(Inst) <= 152, "Inst size unintentionally increased");
using U1 = TypedValue<Type::U1>; using U1 = TypedValue<Type::U1>;
using U8 = TypedValue<Type::U8>; using U8 = TypedValue<Type::U8>;