early-access version 1591

This commit is contained in:
pineappleEA
2021-04-13 00:32:26 +02:00
parent 2f619137d1
commit e839de5014
67 changed files with 777 additions and 5583 deletions

View File

@@ -7,7 +7,6 @@
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "common/assert.h"
@@ -27,29 +26,17 @@ using Tegra::Shader::OpCode;
constexpr s32 unassigned_branch = -2;
enum class JumpLabel : u32 {
SSYClass = 0,
PBKClass = 1,
};
struct JumpItem {
JumpLabel type;
u32 address;
bool operator==(const JumpItem& other) const {
return std::tie(type, address) == std::tie(other.type, other.address);
}
};
struct Query {
u32 address{};
std::stack<JumpItem> stack{};
std::stack<u32> ssy_stack{};
std::stack<u32> pbk_stack{};
};
struct BlockStack {
BlockStack() = default;
explicit BlockStack(const Query& q) : stack{q.stack} {}
std::stack<JumpItem> stack{};
explicit BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {}
std::stack<u32> ssy_stack{};
std::stack<u32> pbk_stack{};
};
template <typename T, typename... Args>
@@ -78,36 +65,20 @@ struct BlockInfo {
}
};
struct ProgramControl {
std::unordered_set<u32> found_functions{};
std::list<u32> pending_functions{};
void RegisterFunction(u32 address) {
if (found_functions.count(address) != 0) {
return;
}
found_functions.insert(address);
pending_functions.emplace_back(address);
}
};
struct CFGRebuildState {
explicit CFGRebuildState(ProgramControl& control_, const ProgramCode& program_code_, u32 start_,
u32 base_start_, Registry& registry_)
: control{control_}, program_code{program_code_}, registry{registry_}, start{start_},
base_start{base_start_} {}
explicit CFGRebuildState(const ProgramCode& program_code_, u32 start_, Registry& registry_)
: program_code{program_code_}, registry{registry_}, start{start_} {}
ProgramControl& control;
const ProgramCode& program_code;
Registry& registry;
u32 start{};
u32 base_start{};
std::vector<BlockInfo> block_info;
std::list<u32> inspect_queries;
std::list<Query> queries;
std::unordered_map<u32, u32> registered;
std::set<u32> labels;
std::map<u32, JumpItem> jump_labels;
std::map<u32, u32> ssy_labels;
std::map<u32, u32> pbk_labels;
std::unordered_map<u32, BlockStack> stacks;
ASTManager* manager{};
};
@@ -182,7 +153,7 @@ template <typename Result, typename TestCallable, typename PackCallable>
std::optional<Result> TrackInstruction(const CFGRebuildState& state, u32& pos, TestCallable test,
PackCallable pack) {
for (; pos >= state.start; --pos) {
if (IsSchedInstruction(pos, state.base_start)) {
if (IsSchedInstruction(pos, state.start)) {
continue;
}
const Instruction instr = state.program_code[pos];
@@ -291,7 +262,7 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
single_branch.ignore = true;
break;
}
if (IsSchedInstruction(offset, state.base_start)) {
if (IsSchedInstruction(offset, state.start)) {
offset++;
continue;
}
@@ -303,7 +274,6 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
}
switch (opcode->get().GetId()) {
case OpCode::Id::RET:
case OpCode::Id::EXIT: {
const auto pred_index = static_cast<u32>(instr.pred.pred_index);
single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
@@ -441,20 +411,13 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
case OpCode::Id::SSY: {
const u32 target = offset + instr.bra.GetBranchTarget();
insert_label(state, target);
JumpItem it = {JumpLabel::SSYClass, target};
state.jump_labels.emplace(offset, it);
state.ssy_labels.emplace(offset, target);
break;
}
case OpCode::Id::PBK: {
const u32 target = offset + instr.bra.GetBranchTarget();
insert_label(state, target);
JumpItem it = {JumpLabel::PBKClass, target};
state.jump_labels.emplace(offset, it);
break;
}
case OpCode::Id::CAL: {
const u32 target = offset + instr.bra.GetBranchTarget();
state.control.RegisterFunction(target);
state.pbk_labels.emplace(offset, target);
break;
}
case OpCode::Id::BRX: {
@@ -550,7 +513,7 @@ bool TryInspectAddress(CFGRebuildState& state) {
}
bool TryQuery(CFGRebuildState& state) {
const auto gather_labels = [](std::stack<JumpItem>& cc, std::map<u32, JumpItem>& labels,
const auto gather_labels = [](std::stack<u32>& cc, std::map<u32, u32>& labels,
BlockInfo& block) {
auto gather_start = labels.lower_bound(block.start);
const auto gather_end = labels.upper_bound(block.end);
@@ -559,19 +522,6 @@ bool TryQuery(CFGRebuildState& state) {
++gather_start;
}
};
const auto pop_labels = [](JumpLabel type, SingleBranch* branch, Query& query) -> bool {
while (!query.stack.empty() && query.stack.top().type != type) {
query.stack.pop();
}
if (query.stack.empty()) {
return false;
}
if (branch->address == unassigned_branch) {
branch->address = query.stack.top().address;
}
query.stack.pop();
return true;
};
if (state.queries.empty()) {
return false;
}
@@ -584,7 +534,8 @@ bool TryQuery(CFGRebuildState& state) {
// consumes a label. Schedule new queries accordingly
if (block.visited) {
BlockStack& stack = state.stacks[q.address];
const bool all_okay = (stack.stack.empty() || q.stack == stack.stack);
const bool all_okay = (stack.ssy_stack.empty() || q.ssy_stack == stack.ssy_stack) &&
(stack.pbk_stack.empty() || q.pbk_stack == stack.pbk_stack);
state.queries.pop_front();
return all_okay;
}
@@ -593,7 +544,8 @@ bool TryQuery(CFGRebuildState& state) {
Query q2(q);
state.queries.pop_front();
gather_labels(q2.stack, state.jump_labels, block);
gather_labels(q2.ssy_stack, state.ssy_labels, block);
gather_labels(q2.pbk_stack, state.pbk_labels, block);
if (std::holds_alternative<SingleBranch>(*block.branch)) {
auto* branch = std::get_if<SingleBranch>(block.branch.get());
if (!branch->condition.IsUnconditional()) {
@@ -603,10 +555,16 @@ bool TryQuery(CFGRebuildState& state) {
auto& conditional_query = state.queries.emplace_back(q2);
if (branch->is_sync) {
pop_labels(JumpLabel::SSYClass, branch, conditional_query);
if (branch->address == unassigned_branch) {
branch->address = conditional_query.ssy_stack.top();
}
conditional_query.ssy_stack.pop();
}
if (branch->is_brk) {
pop_labels(JumpLabel::PBKClass, branch, conditional_query);
if (branch->address == unassigned_branch) {
branch->address = conditional_query.pbk_stack.top();
}
conditional_query.pbk_stack.pop();
}
conditional_query.address = branch->address;
return true;
@@ -688,23 +646,25 @@ void DecompileShader(CFGRebuildState& state) {
state.manager->Decompile();
}
ShaderFunction ScanFunction(ProgramControl& control, const ProgramCode& program_code,
u32 start_address, u32 base_start, const CompilerSettings& settings,
Registry& registry) {
ShaderFunction result_out{};
} // Anonymous namespace
std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings,
Registry& registry) {
auto result_out = std::make_unique<ShaderCharacteristics>();
if (settings.depth == CompileDepth::BruteForce) {
result_out.settings.depth = CompileDepth::BruteForce;
result_out->settings.depth = CompileDepth::BruteForce;
return result_out;
}
CFGRebuildState state{control, program_code, start_address, base_start, registry};
CFGRebuildState state{program_code, start_address, registry};
// Inspect Code and generate blocks
state.labels.clear();
state.labels.emplace(start_address);
state.inspect_queries.push_back(state.start);
while (!state.inspect_queries.empty()) {
if (!TryInspectAddress(state)) {
result_out.settings.depth = CompileDepth::BruteForce;
result_out->settings.depth = CompileDepth::BruteForce;
return result_out;
}
}
@@ -715,7 +675,7 @@ ShaderFunction ScanFunction(ProgramControl& control, const ProgramCode& program_
if (settings.depth != CompileDepth::FlowStack) {
// Decompile Stacks
state.queries.push_back(Query{state.start, {}});
state.queries.push_back(Query{state.start, {}, {}});
decompiled = true;
while (!state.queries.empty()) {
if (!TryQuery(state)) {
@@ -745,18 +705,19 @@ ShaderFunction ScanFunction(ProgramControl& control, const ProgramCode& program_
state.manager->ShowCurrentState("Of Shader");
state.manager->Clear();
} else {
result_out.start = start_address;
result_out.settings.depth = settings.depth;
result_out.manager = std::move(manager);
result_out.end = state.block_info.back().end + 1;
return result_out;
auto characteristics = std::make_unique<ShaderCharacteristics>();
characteristics->start = start_address;
characteristics->settings.depth = settings.depth;
characteristics->manager = std::move(manager);
characteristics->end = state.block_info.back().end + 1;
return characteristics;
}
}
result_out.start = start_address;
result_out.settings.depth =
result_out->start = start_address;
result_out->settings.depth =
use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack;
result_out.blocks.clear();
result_out->blocks.clear();
for (auto& block : state.block_info) {
ShaderBlock new_block{};
new_block.start = block.start;
@@ -765,20 +726,20 @@ ShaderFunction ScanFunction(ProgramControl& control, const ProgramCode& program_
if (!new_block.ignore_branch) {
new_block.branch = block.branch;
}
result_out.end = std::max(result_out.end, block.end);
result_out.blocks.push_back(new_block);
result_out->end = std::max(result_out->end, block.end);
result_out->blocks.push_back(new_block);
}
if (!use_flow_stack) {
result_out.labels = std::move(state.labels);
result_out->labels = std::move(state.labels);
return result_out;
}
auto back = result_out.blocks.begin();
auto back = result_out->blocks.begin();
auto next = std::next(back);
while (next != result_out.blocks.end()) {
while (next != result_out->blocks.end()) {
if (!state.labels.contains(next->start) && next->start == back->end + 1) {
back->end = next->end;
next = result_out.blocks.erase(next);
next = result_out->blocks.erase(next);
continue;
}
back = next;
@@ -787,22 +748,4 @@ ShaderFunction ScanFunction(ProgramControl& control, const ProgramCode& program_
return result_out;
}
} // Anonymous namespace
std::unique_ptr<ShaderProgram> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings, Registry& registry) {
ProgramControl control{};
auto result_out = std::make_unique<ShaderProgram>();
result_out->main =
ScanFunction(control, program_code, start_address, start_address, settings, registry);
while (!control.pending_functions.empty()) {
u32 address = control.pending_functions.front();
auto fun = ScanFunction(control, program_code, address, start_address, settings, registry);
result_out->subfunctions.emplace(address, std::move(fun));
control.pending_functions.pop_front();
}
return result_out;
}
} // namespace VideoCommon::Shader

View File

@@ -5,7 +5,6 @@
#pragma once
#include <list>
#include <map>
#include <optional>
#include <set>
#include <variant>
@@ -102,7 +101,7 @@ struct ShaderBlock {
}
};
struct ShaderFunction {
struct ShaderCharacteristics {
std::list<ShaderBlock> blocks{};
std::set<u32> labels{};
u32 start{};
@@ -111,12 +110,8 @@ struct ShaderFunction {
CompilerSettings settings{};
};
struct ShaderProgram {
ShaderFunction main;
std::map<u32, ShaderFunction> subfunctions;
};
std::unique_ptr<ShaderProgram> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings, Registry& registry);
std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings,
Registry& registry);
} // namespace VideoCommon::Shader

View File

@@ -64,52 +64,9 @@ std::optional<u32> TryDeduceSamplerSize(const SamplerEntry& sampler_to_deduce,
} // Anonymous namespace
class ExprDecoder {
public:
explicit ExprDecoder(ShaderIR& ir_) : ir(ir_) {}
void operator()(const ExprAnd& expr) {
Visit(expr.operand1);
Visit(expr.operand2);
}
void operator()(const ExprOr& expr) {
Visit(expr.operand1);
Visit(expr.operand2);
}
void operator()(const ExprNot& expr) {
Visit(expr.operand1);
}
void operator()(const ExprPredicate& expr) {
const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate);
if (pred != Pred::UnusedIndex && pred != Pred::NeverExecute) {
ir.used_predicates.insert(pred);
}
}
void operator()(const ExprCondCode& expr) {}
void operator()(const ExprVar& expr) {}
void operator()(const ExprBoolean& expr) {}
void operator()(const ExprGprEqual& expr) {
ir.used_registers.insert(expr.gpr);
}
void Visit(const Expr& node) {
return std::visit(*this, *node);
}
private:
ShaderIR& ir;
};
class ASTDecoder {
public:
explicit ASTDecoder(ShaderIR& ir_) : ir(ir_), decoder(ir_) {}
explicit ASTDecoder(ShaderIR& ir_) : ir(ir_) {}
void operator()(ASTProgram& ast) {
ASTNode current = ast.nodes.GetFirst();
@@ -120,7 +77,6 @@ public:
}
void operator()(ASTIfThen& ast) {
decoder.Visit(ast.condition);
ASTNode current = ast.nodes.GetFirst();
while (current) {
Visit(current);
@@ -140,18 +96,13 @@ public:
void operator()(ASTBlockDecoded& ast) {}
void operator()(ASTVarSet& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTVarSet& ast) {}
void operator()(ASTLabel& ast) {}
void operator()(ASTGoto& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTGoto& ast) {}
void operator()(ASTDoWhile& ast) {
decoder.Visit(ast.condition);
ASTNode current = ast.nodes.GetFirst();
while (current) {
Visit(current);
@@ -159,13 +110,9 @@ public:
}
}
void operator()(ASTReturn& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTReturn& ast) {}
void operator()(ASTBreak& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTBreak& ast) {}
void Visit(ASTNode& node) {
std::visit(*this, *node->GetInnerData());
@@ -178,113 +125,77 @@ public:
private:
ShaderIR& ir;
ExprDecoder decoder;
};
void ShaderIR::Decode() {
const auto decode_function = ([this](ShaderFunction& shader_info) {
coverage_end = std::max<u32>(0, shader_info.end);
switch (shader_info.settings.depth) {
case CompileDepth::FlowStack: {
for (const auto& block : shader_info.blocks) {
basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
}
break;
}
case CompileDepth::NoFlowStack: {
disable_flow_stack = true;
const auto insert_block = [this](NodeBlock& nodes, u32 label) {
if (label == static_cast<u32>(exit_branch)) {
return;
}
basic_blocks.insert({label, nodes});
};
const auto& blocks = shader_info.blocks;
NodeBlock current_block;
u32 current_label = static_cast<u32>(exit_branch);
for (const auto& block : blocks) {
if (shader_info.labels.contains(block.start)) {
insert_block(current_block, current_label);
current_block.clear();
current_label = block.start;
}
if (!block.ignore_branch) {
DecodeRangeInner(current_block, block.start, block.end);
InsertControlFlow(current_block, block);
} else {
DecodeRangeInner(current_block, block.start, block.end + 1);
}
}
insert_block(current_block, current_label);
break;
}
case CompileDepth::DecompileBackwards:
case CompileDepth::FullDecompile: {
program_manager = std::move(shader_info.manager);
disable_flow_stack = true;
decompiled = true;
ASTDecoder decoder{*this};
ASTNode program = program_manager.GetProgram();
decoder.Visit(program);
break;
}
default:
LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
[[fallthrough]];
case CompileDepth::BruteForce: {
const auto shader_end = static_cast<u32>(program_code.size());
coverage_begin = main_offset;
coverage_end = shader_end;
for (u32 label = main_offset; label < shader_end; ++label) {
basic_blocks.insert({label, DecodeRange(label, label + 1)});
}
break;
}
}
if (settings.depth != shader_info.settings.depth) {
LOG_WARNING(
HW_GPU,
"Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"",
CompileDepthAsString(settings.depth),
CompileDepthAsString(shader_info.settings.depth));
}
});
const auto gen_function =
([this](ShaderFunction& shader_info, u32 id) -> std::shared_ptr<ShaderFunctionIR> {
std::shared_ptr<ShaderFunctionIR> result;
if (decompiled) {
result = std::make_shared<ShaderFunctionIR>(std::move(program_manager), id,
shader_info.start, shader_info.end);
} else {
result =
std::make_shared<ShaderFunctionIR>(std::move(basic_blocks), disable_flow_stack,
id, shader_info.start, shader_info.end);
}
decompiled = false;
disable_flow_stack = false;
basic_blocks.clear();
program_manager.Clear();
return result;
});
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
decompiled = false;
auto info = ScanFlow(program_code, main_offset, settings, registry);
u32 id_start = 1;
for (auto& pair : info->subfunctions) {
func_map.emplace(pair.first, id_start);
id_start++;
auto& shader_info = *info;
coverage_begin = shader_info.start;
coverage_end = shader_info.end;
switch (shader_info.settings.depth) {
case CompileDepth::FlowStack: {
for (const auto& block : shader_info.blocks) {
basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
}
break;
}
coverage_begin = info->main.start;
coverage_end = 0;
decode_function(info->main);
main_function = gen_function(info->main, 0);
subfunctions.resize(info->subfunctions.size());
for (auto& pair : info->subfunctions) {
auto& func_info = pair.second;
decode_function(func_info);
u32 id = func_map[pair.first];
subfunctions[id - 1] = gen_function(func_info, id);
case CompileDepth::NoFlowStack: {
disable_flow_stack = true;
const auto insert_block = [this](NodeBlock& nodes, u32 label) {
if (label == static_cast<u32>(exit_branch)) {
return;
}
basic_blocks.insert({label, nodes});
};
const auto& blocks = shader_info.blocks;
NodeBlock current_block;
u32 current_label = static_cast<u32>(exit_branch);
for (const auto& block : blocks) {
if (shader_info.labels.contains(block.start)) {
insert_block(current_block, current_label);
current_block.clear();
current_label = block.start;
}
if (!block.ignore_branch) {
DecodeRangeInner(current_block, block.start, block.end);
InsertControlFlow(current_block, block);
} else {
DecodeRangeInner(current_block, block.start, block.end + 1);
}
}
insert_block(current_block, current_label);
break;
}
case CompileDepth::DecompileBackwards:
case CompileDepth::FullDecompile: {
program_manager = std::move(shader_info.manager);
disable_flow_stack = true;
decompiled = true;
ASTDecoder decoder{*this};
ASTNode program = GetASTProgram();
decoder.Visit(program);
break;
}
default:
LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
[[fallthrough]];
case CompileDepth::BruteForce: {
const auto shader_end = static_cast<u32>(program_code.size());
coverage_begin = main_offset;
coverage_end = shader_end;
for (u32 label = main_offset; label < shader_end; ++label) {
basic_blocks.insert({label, DecodeRange(label, label + 1)});
}
break;
}
}
if (settings.depth != shader_info.settings.depth) {
LOG_WARNING(
HW_GPU, "Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"",
CompileDepthAsString(settings.depth), CompileDepthAsString(shader_info.settings.depth));
}
}

View File

@@ -33,7 +33,6 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
// With the previous preconditions, this instruction is a no-operation.
break;
}
case OpCode::Id::RET:
case OpCode::Id::EXIT: {
const ConditionCode cc = instr.flow_condition_code;
UNIMPLEMENTED_IF_MSG(cc != ConditionCode::T, "EXIT condition code used: {}", cc);
@@ -313,16 +312,6 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
LOG_DEBUG(HW_GPU, "DEPBAR instruction is stubbed");
break;
}
case OpCode::Id::CAL: {
const u32 target = pc + instr.bra.GetBranchTarget();
const auto it = func_map.find(target);
if (it == func_map.end()) {
UNREACHABLE();
break;
}
bb.push_back(FunctionCall(it->second));
break;
}
default:
UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName());
}

View File

@@ -339,6 +339,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
const TextureType texture_type{instr.tlds.GetTextureType()};
const bool is_array{instr.tlds.IsArrayTexture()};
UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(TextureMiscMode::AOFFI),
"AOFFI is not implemented");
UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(TextureMiscMode::MZ), "MZ is not implemented");
const Node4 components = GetTldsCode(instr, texture_type, is_array);
@@ -820,7 +822,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
for (std::size_t i = 0; i < type_coord_count; ++i) {
const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1);
coords.push_back(
GetRegister(last && !aoffi_enabled ? last_coord_register : (coord_register + i)));
GetRegister(last && !aoffi_enabled ? last_coord_register : coord_register + i));
}
const Node array = is_array ? GetRegister(array_register) : nullptr;

View File

@@ -267,11 +267,10 @@ class PatchNode;
class SmemNode;
class GmemNode;
class CommentNode;
class FunctionCallNode;
using NodeData = std::variant<OperationNode, ConditionalNode, GprNode, CustomVarNode, ImmediateNode,
InternalFlagNode, PredicateNode, AbufNode, PatchNode, CbufNode,
LmemNode, SmemNode, GmemNode, FunctionCallNode, CommentNode>;
LmemNode, SmemNode, GmemNode, CommentNode>;
using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
@@ -495,18 +494,6 @@ private:
std::vector<Node> code; ///< Code to execute
};
class FunctionCallNode final : public AmendNode {
public:
explicit FunctionCallNode(u32 func_id_) : func_id{func_id_} {}
[[nodiscard]] u32 GetFuncId() const {
return func_id;
}
private:
u32 func_id; ///< Id of the function to call
};
/// A general purpose register
class GprNode final {
public:

View File

@@ -19,11 +19,6 @@ Node Comment(std::string text) {
return MakeNode<CommentNode>(std::move(text));
}
/// Creates a function call
Node FunctionCall(u32 func_id) {
return MakeNode<FunctionCallNode>(func_id);
}
Node Immediate(u32 value) {
return MakeNode<ImmediateNode>(value);
}

View File

@@ -27,9 +27,6 @@ Node Conditional(Node condition, std::vector<Node> code);
/// Creates a commentary node
Node Comment(std::string text);
/// Creates a function call
Node FunctionCall(u32 func_id);
/// Creates an u32 immediate
Node Immediate(u32 value);

View File

@@ -26,7 +26,7 @@ namespace VideoCommon::Shader {
struct ShaderBlock;
constexpr u32 MAX_PROGRAM_LENGTH = 0x2000;
constexpr u32 MAX_PROGRAM_LENGTH = 0x1000;
struct ConstBuffer {
constexpr explicit ConstBuffer(u32 max_offset_, bool is_indirect_)
@@ -64,68 +64,16 @@ struct GlobalMemoryUsage {
bool is_written{};
};
class ShaderFunctionIR final {
public:
explicit ShaderFunctionIR(std::map<u32, NodeBlock>&& basic_blocks_, bool disable_flow_stack_,
u32 id_, u32 coverage_begin_, u32 coverage_end_)
: basic_blocks{std::move(basic_blocks_)}, decompiled{false},
disable_flow_stack{disable_flow_stack_}, id{id_}, coverage_begin{coverage_begin_},
coverage_end{coverage_end_} {}
explicit ShaderFunctionIR(ASTManager&& program_manager_, u32 id_, u32 coverage_begin_,
u32 coverage_end_)
: program_manager{std::move(program_manager_)}, decompiled{true}, disable_flow_stack{true},
id{id_}, coverage_begin{coverage_begin_}, coverage_end{coverage_end_} {}
const std::map<u32, NodeBlock>& GetBasicBlocks() const {
return basic_blocks;
}
[[nodiscard]] bool IsFlowStackDisabled() const {
return disable_flow_stack;
}
[[nodiscard]] bool IsDecompiled() const {
return decompiled;
}
const ASTManager& GetASTManager() const {
return program_manager;
}
[[nodiscard]] ASTNode GetASTProgram() const {
return program_manager.GetProgram();
}
[[nodiscard]] u32 GetASTNumVariables() const {
return program_manager.GetVariables();
}
[[nodiscard]] bool IsMain() const {
return id == 0;
}
[[nodiscard]] u32 GetId() const {
return id;
}
private:
std::map<u32, NodeBlock> basic_blocks;
ASTManager program_manager{true, true};
bool decompiled{};
bool disable_flow_stack{};
u32 id{};
u32 coverage_begin{};
u32 coverage_end{};
};
class ShaderIR final {
public:
explicit ShaderIR(const ProgramCode& program_code_, u32 main_offset_,
CompilerSettings settings_, Registry& registry_);
~ShaderIR();
const std::map<u32, NodeBlock>& GetBasicBlocks() const {
return basic_blocks;
}
const std::set<u32>& GetRegisters() const {
return used_registers;
}
@@ -207,6 +155,26 @@ public:
return header;
}
bool IsFlowStackDisabled() const {
return disable_flow_stack;
}
bool IsDecompiled() const {
return decompiled;
}
const ASTManager& GetASTManager() const {
return program_manager;
}
ASTNode GetASTProgram() const {
return program_manager.GetProgram();
}
u32 GetASTNumVariables() const {
return program_manager.GetVariables();
}
u32 ConvertAddressToNvidiaSpace(u32 address) const {
return (address - main_offset) * static_cast<u32>(sizeof(Tegra::Shader::Instruction));
}
@@ -222,16 +190,7 @@ public:
return num_custom_variables;
}
std::shared_ptr<ShaderFunctionIR> GetMainFunction() const {
return main_function;
}
const std::vector<std::shared_ptr<ShaderFunctionIR>>& GetSubFunctions() const {
return subfunctions;
}
private:
friend class ExprDecoder;
friend class ASTDecoder;
struct SamplerInfo {
@@ -494,10 +453,6 @@ private:
std::vector<Node> amend_code;
u32 num_custom_variables{};
std::shared_ptr<ShaderFunctionIR> main_function;
std::vector<std::shared_ptr<ShaderFunctionIR>> subfunctions;
std::unordered_map<u32, u32> func_map;
std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates;
std::set<Tegra::Shader::Attribute::Index> used_input_attributes;