yuzu/src/shader_recompiler/frontend/maxwell/control_flow.h

170 lines
4.5 KiB
C++
Raw Normal View History

2021-01-09 06:30:07 +00:00
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <optional>
#include <span>
#include <string>
#include <vector>
#include <boost/container/small_vector.hpp>
#include <boost/intrusive/set.hpp>
2021-01-09 06:30:07 +00:00
#include "shader_recompiler/environment.h"
#include "shader_recompiler/frontend/ir/condition.h"
#include "shader_recompiler/frontend/ir/reg.h"
2021-01-09 06:30:07 +00:00
#include "shader_recompiler/frontend/maxwell/instruction.h"
#include "shader_recompiler/frontend/maxwell/location.h"
2021-02-06 02:11:23 +00:00
#include "shader_recompiler/frontend/maxwell/opcodes.h"
#include "shader_recompiler/object_pool.h"
2021-01-09 06:30:07 +00:00
namespace Shader::Maxwell::Flow {
struct Block;
2021-01-09 06:30:07 +00:00
using FunctionId = size_t;
enum class EndClass {
Branch,
2021-03-27 21:30:24 +00:00
IndirectBranch,
Call,
2021-01-09 06:30:07 +00:00
Exit,
Return,
Kill,
2021-01-09 06:30:07 +00:00
};
enum class Token {
SSY,
PBK,
PEXIT,
PRET,
PCNT,
PLONGJMP,
};
struct StackEntry {
auto operator<=>(const StackEntry&) const noexcept = default;
Token token;
Location target;
};
class Stack {
public:
void Push(Token token, Location target);
[[nodiscard]] std::pair<Location, Stack> Pop(Token token) const;
[[nodiscard]] std::optional<Location> Peek(Token token) const;
[[nodiscard]] Stack Remove(Token token) const;
private:
boost::container::small_vector<StackEntry, 3> entries;
};
struct IndirectBranch {
Block* block;
u32 address;
};
struct Block : boost::intrusive::set_base_hook<
// Normal link is ~2.5% faster compared to safe link
boost::intrusive::link_mode<boost::intrusive::normal_link>> {
2021-01-09 06:30:07 +00:00
[[nodiscard]] bool Contains(Location pc) const noexcept;
bool operator<(const Block& rhs) const noexcept {
return begin < rhs.begin;
}
2021-01-09 06:30:07 +00:00
Location begin;
Location end;
EndClass end_class{};
IR::Condition cond{};
Stack stack;
Block* branch_true{};
Block* branch_false{};
FunctionId function_call{};
Block* return_block{};
IR::Reg branch_reg{};
s32 branch_offset{};
std::vector<IndirectBranch> indirect_branches;
2021-01-09 06:30:07 +00:00
};
struct Label {
Location address;
Block* block;
2021-01-09 06:30:07 +00:00
Stack stack;
};
struct Function {
explicit Function(ObjectPool<Block>& block_pool, Location start_address);
2021-01-09 06:30:07 +00:00
Location entrypoint;
boost::container::small_vector<Label, 16> labels;
boost::intrusive::set<Block> blocks;
2021-01-09 06:30:07 +00:00
};
class CFG {
enum class AnalysisState {
Branch,
Continue,
};
public:
explicit CFG(Environment& env, ObjectPool<Block>& block_pool, Location start_address,
bool exits_to_dispatcher = false);
2021-01-09 06:30:07 +00:00
2021-02-03 00:07:00 +00:00
CFG& operator=(const CFG&) = delete;
CFG(const CFG&) = delete;
CFG& operator=(CFG&&) = delete;
CFG(CFG&&) = delete;
2021-01-09 06:30:07 +00:00
[[nodiscard]] std::string Dot() const;
[[nodiscard]] std::span<const Function> Functions() const noexcept {
return std::span(functions.data(), functions.size());
}
[[nodiscard]] std::span<Function> Functions() noexcept {
return std::span(functions.data(), functions.size());
}
2021-01-09 06:30:07 +00:00
[[nodiscard]] bool ExitsToDispatcher() const {
return exits_to_dispatcher;
}
2021-01-09 06:30:07 +00:00
private:
void AnalyzeLabel(FunctionId function_id, Label& label);
/// Inspect already visited blocks.
/// Return true when the block has already been visited
2021-02-03 00:07:00 +00:00
bool InspectVisitedBlocks(FunctionId function_id, const Label& label);
2021-01-09 06:30:07 +00:00
AnalysisState AnalyzeInst(Block* block, FunctionId function_id, Location pc);
2021-01-09 06:30:07 +00:00
void AnalyzeCondInst(Block* block, FunctionId function_id, Location pc, EndClass insn_end_class,
IR::Condition cond);
2021-01-09 06:30:07 +00:00
/// Return true when the branch instruction is confirmed to be a branch
bool AnalyzeBranch(Block* block, FunctionId function_id, Location pc, Instruction inst,
2021-02-03 00:07:00 +00:00
Opcode opcode);
2021-01-09 06:30:07 +00:00
void AnalyzeBRA(Block* block, FunctionId function_id, Location pc, Instruction inst,
2021-01-09 06:30:07 +00:00
bool is_absolute);
2021-03-27 21:30:24 +00:00
AnalysisState AnalyzeBRX(Block* block, Location pc, Instruction inst, bool is_absolute,
FunctionId function_id);
AnalysisState AnalyzeEXIT(Block* block, FunctionId function_id, Location pc, Instruction inst);
2021-01-09 06:30:07 +00:00
/// Return the branch target block id
Block* AddLabel(Block* block, Stack stack, Location pc, FunctionId function_id);
2021-01-09 06:30:07 +00:00
Environment& env;
ObjectPool<Block>& block_pool;
2021-01-09 06:30:07 +00:00
boost::container::small_vector<Function, 1> functions;
2021-04-06 00:01:01 +00:00
Location program_start;
bool exits_to_dispatcher{};
Block* dispatch_block{};
2021-01-09 06:30:07 +00:00
};
} // namespace Shader::Maxwell::Flow