mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-25 11:34:55 +00:00
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / linux-sdl-gcc (push) Blocked by required conditions
Build and Release / linux-qt-gcc (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions
* control_flow_graph: Improve divergence handling * recompiler: Simplify optimization passes Removes a redudant constant propagation and cleans up the passes a little * ir_passes: Add new readlane elimination pass The algorithm has grown complex enough where it deserves its own pass. The old implementation could only handle a single phi level properly, however this one should be able to eliminate vast majority of lane cases remaining. It first performs a traversal of the phi tree to ensure that all phi sources can be rewritten into an expected value and then performs elimintation by recursively duplicating the phi nodes at each step, in order to preserve control flow. * clang format * control_flow_graph: Remove debug code
89 lines
2.3 KiB
C++
89 lines
2.3 KiB
C++
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <span>
|
|
#include <string>
|
|
#include <boost/container/small_vector.hpp>
|
|
#include <boost/intrusive/set.hpp>
|
|
|
|
#include "common/assert.h"
|
|
#include "common/object_pool.h"
|
|
#include "common/types.h"
|
|
#include "shader_recompiler/frontend/instruction.h"
|
|
#include "shader_recompiler/ir/condition.h"
|
|
|
|
namespace Shader::Gcn {
|
|
|
|
using Hook =
|
|
boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>;
|
|
|
|
enum class EndClass {
|
|
Branch, ///< Block ends with a (un)conditional branch.
|
|
Exit, ///< Block ends with an exit instruction.
|
|
Kill, ///< Block ends with a discard instruction.
|
|
};
|
|
|
|
/// A block represents a linear range of instructions.
|
|
struct Block : Hook {
|
|
[[nodiscard]] bool Contains(u32 pc) const noexcept;
|
|
|
|
bool operator<(const Block& rhs) const noexcept {
|
|
return begin < rhs.begin;
|
|
}
|
|
|
|
u32 begin;
|
|
u32 end;
|
|
u32 begin_index;
|
|
u32 end_index;
|
|
u32 num_predecessors{};
|
|
IR::Condition cond{};
|
|
GcnInst end_inst{};
|
|
EndClass end_class{};
|
|
Block* branch_true{};
|
|
Block* branch_false{};
|
|
bool is_dummy{};
|
|
};
|
|
|
|
class CFG {
|
|
using Label = u32;
|
|
|
|
public:
|
|
explicit CFG(Common::ObjectPool<Block>& block_pool, std::span<const GcnInst> inst_list);
|
|
|
|
[[nodiscard]] std::string Dot() const;
|
|
|
|
private:
|
|
void EmitLabels();
|
|
void EmitBlocks();
|
|
void LinkBlocks();
|
|
void SplitDivergenceScopes();
|
|
|
|
void AddLabel(Label address) {
|
|
const auto it = std::ranges::find(labels, address);
|
|
if (it == labels.end()) {
|
|
labels.push_back(address);
|
|
}
|
|
};
|
|
|
|
size_t GetIndex(Label label) {
|
|
if (label == 0) {
|
|
return 0ULL;
|
|
}
|
|
const auto it_index = std::ranges::lower_bound(index_to_pc, label);
|
|
ASSERT(it_index != index_to_pc.end() || label > index_to_pc.back());
|
|
return std::distance(index_to_pc.begin(), it_index);
|
|
};
|
|
|
|
public:
|
|
Common::ObjectPool<Block>& block_pool;
|
|
std::span<const GcnInst> inst_list;
|
|
std::vector<u32> index_to_pc;
|
|
boost::container::small_vector<Label, 16> labels;
|
|
boost::intrusive::set<Block> blocks;
|
|
};
|
|
|
|
} // namespace Shader::Gcn
|