Files
KytyPS5/src/graphics/shader/recompiler/frontend/cfg/ShaderCFG.h
T

129 lines
4.3 KiB
C++

#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SHADERCFG_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SHADERCFG_H_
#include "common/common.h"
#include "common/stringUtils.h"
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
#include <vector>
namespace Libs::Graphics::ShaderRecompiler::CFG {
enum class BranchCondition {
Always,
SccZero,
SccNonZero,
VccZero,
VccNonZero,
ExecZero,
ExecNonZero,
ScalarInstruction,
Expression,
Unknown
};
struct ConditionExpression {
enum class Op { Constant, Variable, Native, Not, Or };
Op op;
uint32_t lhs;
uint32_t rhs = UINT32_MAX;
};
enum class TerminatorKind { Branch, ConditionalBranch, IndirectBranch, Return, Unsupported };
enum class FailureKind {
None,
InvalidInput,
UnsupportedInstruction,
InvalidBranchTarget,
MissingFallthrough,
InvalidLabel,
IrreducibleControlFlow,
StructuredControlFlow
};
struct Terminator {
TerminatorKind kind = TerminatorKind::Return;
BranchCondition condition = BranchCondition::Always;
uint32_t true_block = UINT32_MAX;
uint32_t false_block = UINT32_MAX;
uint32_t merge_block = UINT32_MAX;
uint32_t continue_block = UINT32_MAX;
uint32_t indirect_pc_sgpr = UINT32_MAX;
uint32_t indirect_selector_code = UINT32_MAX;
std::vector<uint32_t> indirect_target_pcs;
std::vector<uint32_t> indirect_targets;
std::vector<uint32_t> indirect_selector_values;
std::vector<uint32_t> indirect_selector_targets;
uint32_t expression = UINT32_MAX;
bool loop_header = false;
};
struct BasicBlock {
uint32_t id = 0;
uint32_t start_pc = 0;
uint32_t end_pc = 0;
uint32_t inst_begin = 0;
uint32_t inst_end = 0;
struct Assignment { uint32_t variable; uint32_t expression; };
std::vector<Assignment> assignments;
std::vector<uint32_t> predecessors;
std::vector<uint32_t> successors;
std::vector<uint32_t> dominators;
Terminator terminator;
};
struct BackEdge {
uint32_t from = UINT32_MAX;
uint32_t to = UINT32_MAX;
bool natural = false;
};
struct NaturalLoop {
uint32_t header = UINT32_MAX;
uint32_t latch = UINT32_MAX;
std::vector<uint32_t> body_blocks;
};
struct StronglyConnectedComponent {
std::vector<uint32_t> blocks;
std::vector<uint32_t> entry_blocks;
bool irreducible = false;
};
struct Graph {
std::vector<BasicBlock> blocks;
std::vector<ConditionExpression> expressions;
std::vector<BackEdge> back_edges;
std::vector<NaturalLoop> natural_loops;
std::vector<StronglyConnectedComponent> components;
std::vector<uint32_t> code_table_load_pcs;
uint32_t entry_block = UINT32_MAX;
bool irreducible = false;
bool unsupported = false;
FailureKind failure_kind = FailureKind::None;
uint32_t failure_block = UINT32_MAX;
std::string unsupported_reason;
const BasicBlock* FindBlock(uint32_t id) const;
BasicBlock* FindBlock(uint32_t id);
const BasicBlock* FindBlockByPc(uint32_t pc) const;
BasicBlock* FindBlockByPc(uint32_t pc);
bool Dominates(uint32_t dominator, uint32_t block) const;
};
Graph BuildGraph(const Decoder::Program& program);
bool MayWriteScalarRegister(const Decoder::Instruction& inst, uint32_t code);
uint32_t FindScalarDefinition(const Decoder::Program& program, const Graph& graph,
uint32_t before, uint32_t code, std::vector<uint32_t>& crossed_calls);
// Returns structured control flow or failure diagnostics without changing the native graph.
// On failure, failure_block is an original block ID or UINT32_MAX.
Graph Structurize(const Graph& graph);
std::string BranchConditionToString(BranchCondition condition);
std::string FailureKindToString(FailureKind kind);
std::string GraphToString(const Graph& graph);
} // namespace Libs::Graphics::ShaderRecompiler::CFG
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SHADERCFG_H_ */