summaryrefslogtreecommitdiffstats
path: root/src/video_core/shader/decode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader/decode.cpp')
-rw-r--r--src/video_core/shader/decode.cpp46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index 09f55bd21..1a74b70cb 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -44,6 +44,17 @@ void ShaderIR::Decode() {
coverage_begin = shader_info.start;
coverage_end = shader_info.end;
if (shader_info.decompilable) {
+ std::list<ShaderBlock>& blocks = shader_info.blocks;
+ for (auto& block : blocks) {
+ NodeBlock nodes;
+ if (!block.ignore_branch) {
+ nodes = DecodeRange(block.start, block.end);
+ InsertControlFlow(nodes, block);
+ } else {
+ nodes = DecodeRange(block.start, block.end + 1);
+ }
+ basic_blocks.insert({block.start, nodes});
+ }
return;
}
// we can't decompile it, fallback to standard method
@@ -73,6 +84,41 @@ NodeBlock ShaderIR::DecodeRange(u32 begin, u32 end) {
return basic_block;
}
+void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
+ auto apply_conditions = ([&](const Condition& cond, Node n) -> Node {
+ Node result = n;
+ if (cond.cc != ConditionCode::T) {
+ result = Conditional(GetConditionCode(cond.cc), {result});
+ }
+ if (cond.predicate != Pred::UnusedIndex) {
+ u32 pred = static_cast<u32>(cond.predicate);
+ bool is_neg = pred > 7;
+ if (is_neg)
+ pred -= 8;
+ result = Conditional(GetPredicate(pred, is_neg), {result});
+ }
+ return result;
+ });
+ if (block.branch.address < 0) {
+ if (block.branch.kills) {
+ Node n = Operation(OperationCode::Discard);
+ n = apply_conditions(block.branch.cond, n);
+ bb.push_back(n);
+ global_code.push_back(n);
+ return;
+ }
+ Node n = Operation(OperationCode::Exit);
+ n = apply_conditions(block.branch.cond, n);
+ bb.push_back(n);
+ global_code.push_back(n);
+ return;
+ }
+ Node n = Operation(OperationCode::Branch, Immediate(block.branch.address));
+ n = apply_conditions(block.branch.cond, n);
+ bb.push_back(n);
+ global_code.push_back(n);
+}
+
u32 ShaderIR::DecodeInstr(NodeBlock& bb, u32 pc) {
// Ignore sched instructions when generating code.
if (IsSchedInstruction(pc, main_offset)) {