diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8fa9e6534..2955c6abf 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -20,6 +20,7 @@
 #include "video_core/renderer_opengl/gl_rasterizer.h"
 #include "video_core/renderer_opengl/gl_shader_decompiler.h"
 #include "video_core/shader/node.h"
+#include "video_core/shader/ast.h"
 #include "video_core/shader/shader_ir.h"
 
 namespace OpenGL::GLShader {
@@ -334,43 +335,26 @@ constexpr bool IsVertexShader(ProgramType stage) {
     return stage == ProgramType::VertexA || stage == ProgramType::VertexB;
 }
 
+class ASTDecompiler;
+class ExprDecompiler;
+
 class GLSLDecompiler final {
 public:
     explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ProgramType stage,
                             std::string suffix)
         : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {}
 
-    void Decompile() {
-        DeclareVertex();
-        DeclareGeometry();
-        DeclareRegisters();
-        DeclarePredicates();
-        DeclareLocalMemory();
-        DeclareSharedMemory();
-        DeclareInternalFlags();
-        DeclareInputAttributes();
-        DeclareOutputAttributes();
-        DeclareConstantBuffers();
-        DeclareGlobalMemory();
-        DeclareSamplers();
-        DeclarePhysicalAttributeReader();
-        DeclareImages();
-
-        code.AddLine("void execute_{}() {{", suffix);
-        ++code.scope;
-
+    void DecompileBranchMode() {
         // VM's program counter
         const auto first_address = ir.GetBasicBlocks().begin()->first;
         code.AddLine("uint jmp_to = {}U;", first_address);
 
         // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
         // unlikely that shaders will use 20 nested SSYs and PBKs.
-        if (!ir.IsFlowStackDisabled()) {
-            constexpr u32 FLOW_STACK_SIZE = 20;
-            for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) {
-                code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE);
-                code.AddLine("uint {} = 0U;", FlowStackTopName(stack));
-            }
+        constexpr u32 FLOW_STACK_SIZE = 20;
+        for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) {
+            code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE);
+            code.AddLine("uint {} = 0u;", FlowStackTopName(stack));
         }
 
         code.AddLine("while (true) {{");
@@ -392,10 +376,37 @@ public:
         code.AddLine("default: return;");
         code.AddLine("}}");
 
-        for (std::size_t i = 0; i < 2; ++i) {
-            --code.scope;
-            code.AddLine("}}");
+        --code.scope;
+        code.AddLine("}}");
+    }
+
+    void DecompileAST();
+
+    void Decompile() {
+        DeclareVertex();
+        DeclareGeometry();
+        DeclareRegisters();
+        DeclarePredicates();
+        DeclareLocalMemory();
+        DeclareInternalFlags();
+        DeclareInputAttributes();
+        DeclareOutputAttributes();
+        DeclareConstantBuffers();
+        DeclareGlobalMemory();
+        DeclareSamplers();
+        DeclarePhysicalAttributeReader();
+
+        code.AddLine("void execute_{}() {{", suffix);
+        ++code.scope;
+
+        if (ir.IsDecompiled()) {
+            DecompileAST();
+        } else {
+            DecompileBranchMode();
         }
+
+        --code.scope;
+        code.AddLine("}}");
     }
 
     std::string GetResult() {
@@ -424,6 +435,9 @@ public:
     }
 
 private:
+    friend class ASTDecompiler;
+    friend class ExprDecompiler;
+
     void DeclareVertex() {
         if (!IsVertexShader(stage))
             return;
@@ -1821,7 +1835,7 @@ private:
         return {};
     }
 
-    Expression Exit(Operation operation) {
+    Expression WriteExit() {
         if (stage != ProgramType::Fragment) {
             code.AddLine("return;");
             return {};
@@ -1861,6 +1875,10 @@ private:
         return {};
     }
 
+    Expression Exit(Operation operation) {
+        return WriteExit();
+    }
+
     Expression Discard(Operation operation) {
         // Enclose "discard" in a conditional, so that GLSL compilation does not complain
         // about unexecuted instructions that may follow this.
@@ -2253,6 +2271,201 @@ private:
     ShaderWriter code;
 };
 
+const std::string flow_var = "flow_var_";
+
+class ExprDecompiler {
+public:
+    ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {}
+
+    void operator()(VideoCommon::Shader::ExprAnd& expr) {
+        inner += "( ";
+        std::visit(*this, *expr.operand1);
+        inner += " && ";
+        std::visit(*this, *expr.operand2);
+        inner += ')';
+    }
+
+    void operator()(VideoCommon::Shader::ExprOr& expr) {
+        inner += "( ";
+        std::visit(*this, *expr.operand1);
+        inner += " || ";
+        std::visit(*this, *expr.operand2);
+        inner += ')';
+    }
+
+    void operator()(VideoCommon::Shader::ExprNot& expr) {
+        inner += '!';
+        std::visit(*this, *expr.operand1);
+    }
+
+    void operator()(VideoCommon::Shader::ExprPredicate& expr) {
+        auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate);
+        inner += decomp.GetPredicate(pred);
+    }
+
+    void operator()(VideoCommon::Shader::ExprCondCode& expr) {
+        Node cc = decomp.ir.GetConditionCode(expr.cc);
+        std::string target;
+
+        if (const auto pred = std::get_if<PredicateNode>(&*cc)) {
+            const auto index = pred->GetIndex();
+            switch (index) {
+            case Tegra::Shader::Pred::NeverExecute:
+                target = "false";
+            case Tegra::Shader::Pred::UnusedIndex:
+                target = "true";
+            default:
+                target = decomp.GetPredicate(index);
+            }
+        } else if (const auto flag = std::get_if<InternalFlagNode>(&*cc)) {
+            target = decomp.GetInternalFlag(flag->GetFlag());
+        }
+        inner += target;
+    }
+
+    void operator()(VideoCommon::Shader::ExprVar& expr) {
+        inner += flow_var + std::to_string(expr.var_index);
+    }
+
+    void operator()(VideoCommon::Shader::ExprBoolean& expr) {
+        inner += expr.value ? "true" : "false";
+    }
+
+    std::string& GetResult() {
+        return inner;
+    }
+
+private:
+    std::string inner{};
+    GLSLDecompiler& decomp;
+};
+
+class ASTDecompiler {
+public:
+    ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {}
+
+    void operator()(VideoCommon::Shader::ASTProgram& ast) {
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+    }
+
+    void operator()(VideoCommon::Shader::ASTIfThen& ast) {
+        ExprDecompiler expr_parser{decomp};
+        std::visit(expr_parser, *ast.condition);
+        decomp.code.AddLine("if ({}) {{", expr_parser.GetResult());
+        decomp.code.scope++;
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+        decomp.code.scope--;
+        decomp.code.AddLine("}}");
+    }
+
+    void operator()(VideoCommon::Shader::ASTIfElse& ast) {
+        decomp.code.AddLine("else {{");
+        decomp.code.scope++;
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+        decomp.code.scope--;
+        decomp.code.AddLine("}}");
+    }
+
+    void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) {
+        UNREACHABLE();
+    }
+
+    void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) {
+        decomp.VisitBlock(ast.nodes);
+    }
+
+    void operator()(VideoCommon::Shader::ASTVarSet& ast) {
+        ExprDecompiler expr_parser{decomp};
+        std::visit(expr_parser, *ast.condition);
+        decomp.code.AddLine("{}{} = {};", flow_var, ast.index, expr_parser.GetResult());
+    }
+
+    void operator()(VideoCommon::Shader::ASTLabel& ast) {
+        decomp.code.AddLine("// Label_{}:", ast.index);
+    }
+
+    void operator()(VideoCommon::Shader::ASTGoto& ast) {
+        UNREACHABLE();
+    }
+
+    void operator()(VideoCommon::Shader::ASTDoWhile& ast) {
+        ExprDecompiler expr_parser{decomp};
+        std::visit(expr_parser, *ast.condition);
+        decomp.code.AddLine("do {{");
+        decomp.code.scope++;
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+        decomp.code.scope--;
+        decomp.code.AddLine("}} while({});", expr_parser.GetResult());
+    }
+
+    void operator()(VideoCommon::Shader::ASTReturn& ast) {
+        bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition);
+        if (!is_true) {
+            ExprDecompiler expr_parser{decomp};
+            std::visit(expr_parser, *ast.condition);
+            decomp.code.AddLine("if ({}) {{", expr_parser.GetResult());
+            decomp.code.scope++;
+        }
+        if (ast.kills) {
+            decomp.code.AddLine("discard;");
+        } else {
+            decomp.WriteExit();
+        }
+        if (!is_true) {
+            decomp.code.scope--;
+            decomp.code.AddLine("}}");
+        }
+    }
+
+    void operator()(VideoCommon::Shader::ASTBreak& ast) {
+        bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition);
+        if (!is_true) {
+            ExprDecompiler expr_parser{decomp};
+            std::visit(expr_parser, *ast.condition);
+            decomp.code.AddLine("if ({}) {{", expr_parser.GetResult());
+            decomp.code.scope++;
+        }
+        decomp.code.AddLine("break;");
+        if (!is_true) {
+            decomp.code.scope--;
+            decomp.code.AddLine("}}");
+        }
+    }
+
+    void Visit(VideoCommon::Shader::ASTNode& node) {
+        std::visit(*this, *node->GetInnerData());
+    }
+
+private:
+    GLSLDecompiler& decomp;
+};
+
+void GLSLDecompiler::DecompileAST() {
+    u32 num_flow_variables = ir.GetASTNumVariables();
+    for (u32 i = 0; i < num_flow_variables; i++) {
+        code.AddLine("bool {}{} = false;", flow_var, i);
+    }
+    ASTDecompiler decompiler{*this};
+    VideoCommon::Shader::ASTNode program = ir.GetASTProgram();
+    decompiler.Visit(program);
+}
+
 } // Anonymous namespace
 
 std::string GetCommonDeclarations() {
diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp
index 0bf289f98..68a96cc79 100644
--- a/src/video_core/shader/ast.cpp
+++ b/src/video_core/shader/ast.cpp
@@ -372,13 +372,13 @@ ASTManager::~ASTManager() {
 void ASTManager::Init() {
     main_node = ASTBase::Make<ASTProgram>(ASTNode{});
     program = std::get_if<ASTProgram>(main_node->GetInnerData());
-    true_condition = MakeExpr<ExprBoolean>(true);
+    false_condition = MakeExpr<ExprBoolean>(false);
 }
 
 ASTManager::ASTManager(ASTManager&& other)
     : labels_map(std::move(other.labels_map)), labels_count{other.labels_count},
       gotos(std::move(other.gotos)), labels(std::move(other.labels)), variables{other.variables},
-      program{other.program}, main_node{other.main_node}, true_condition{other.true_condition} {
+      program{other.program}, main_node{other.main_node}, false_condition{other.false_condition} {
     other.main_node.reset();
 }
 
@@ -390,7 +390,7 @@ ASTManager& ASTManager::operator=(ASTManager&& other) {
     variables = other.variables;
     program = other.program;
     main_node = other.main_node;
-    true_condition = other.true_condition;
+    false_condition = other.false_condition;
 
     other.main_node.reset();
     return *this;
@@ -594,7 +594,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) {
         u32 var_index = NewVariable();
         Expr var_condition = MakeExpr<ExprVar>(var_index);
         ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
-        ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition);
+        ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition);
         zipper2.InsertBefore(var_node_init, parent);
         zipper.InsertAfter(var_node, prev);
         goto_node->SetGotoCondition(var_condition);
@@ -605,7 +605,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) {
             u32 var_index = NewVariable();
             Expr var_condition = MakeExpr<ExprVar>(var_index);
             ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
-            ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition);
+            ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition);
             if (is_if) {
                 zipper2.InsertBefore(var_node_init, parent);
             } else {
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h
index 958989bcd..06ab20cc5 100644
--- a/src/video_core/shader/ast.h
+++ b/src/video_core/shader/ast.h
@@ -141,8 +141,6 @@ public:
     Expr condition;
 };
 
-using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>;
-
 class ASTBase {
 public:
     explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {}
@@ -233,11 +231,7 @@ public:
         return std::holds_alternative<ASTBlockEncoded>(data);
     }
 
-    void TransformBlockEncoded(TransformCallback& callback) {
-        auto block = std::get_if<ASTBlockEncoded>(&data);
-        const u32 start = block->start;
-        const u32 end = block->end;
-        NodeBlock nodes = callback(start, end);
+    void TransformBlockEncoded(NodeBlock& nodes) {
         data = ASTBlockDecoded(nodes);
     }
 
@@ -309,16 +303,20 @@ public:
 
     void SanityCheck();
 
-    bool IsFullyDecompiled() {
+    bool IsFullyDecompiled() const {
         return gotos.size() == 0;
     }
 
-    ASTNode GetProgram() {
+    ASTNode GetProgram() const {
         return main_node;
     }
 
     void Clear();
 
+    u32 GetVariables() const {
+        return variables;
+    }
+
 private:
     bool IndirectlyRelated(ASTNode first, ASTNode second);
 
@@ -343,7 +341,7 @@ private:
     u32 variables{};
     ASTProgram* program{};
     ASTNode main_node{};
-    Expr true_condition{};
+    Expr false_condition{};
 };
 
 } // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index deb3d3ebd..a29922815 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -425,7 +425,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) {
         }
         if (cond.predicate != Pred::UnusedIndex) {
             u32 pred = static_cast<u32>(cond.predicate);
-            bool negate;
+            bool negate = false;
             if (pred > 7) {
                 negate = true;
                 pred -= 8;
diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h
index 2805d975c..347a35dcf 100644
--- a/src/video_core/shader/control_flow.h
+++ b/src/video_core/shader/control_flow.h
@@ -74,6 +74,6 @@ struct ShaderCharacteristics {
 };
 
 std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size,
-                                              u32 start_address, ASTManager& manager);
+                                                u32 start_address, ASTManager& manager);
 
 } // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index 381e87415..e7e0903f6 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -35,10 +35,73 @@ constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
 
 } // namespace
 
+class ASTDecoder {
+public:
+    ASTDecoder(ShaderIR& ir) : ir(ir) {}
+
+    void operator()(ASTProgram& ast) {
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+    }
+
+    void operator()(ASTIfThen& ast) {
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+    }
+
+    void operator()(ASTIfElse& ast) {
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+    }
+
+    void operator()(ASTBlockEncoded& ast) {}
+
+    void operator()(ASTBlockDecoded& ast) {}
+
+    void operator()(ASTVarSet& ast) {}
+
+    void operator()(ASTLabel& ast) {}
+
+    void operator()(ASTGoto& ast) {}
+
+    void operator()(ASTDoWhile& ast) {
+        ASTNode current = ast.nodes.GetFirst();
+        while (current) {
+            Visit(current);
+            current = current->GetNext();
+        }
+    }
+
+    void operator()(ASTReturn& ast) {}
+
+    void operator()(ASTBreak& ast) {}
+
+    void Visit(ASTNode& node) {
+        std::visit(*this, *node->GetInnerData());
+        if (node->IsBlockEncoded()) {
+            auto block = std::get_if<ASTBlockEncoded>(node->GetInnerData());
+            NodeBlock bb = ir.DecodeRange(block->start, block->end);
+            node->TransformBlockEncoded(bb);
+        }
+    }
+
+private:
+    ShaderIR& ir;
+};
+
 void ShaderIR::Decode() {
     std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
 
-    disable_flow_stack = false;
+    decompiled = false;
     const auto info =
         ScanFlow(program_code, program_size, main_offset, program_manager);
     if (info) {
@@ -46,7 +109,10 @@ void ShaderIR::Decode() {
         coverage_begin = shader_info.start;
         coverage_end = shader_info.end;
         if (shader_info.decompiled) {
-            disable_flow_stack = true;
+            decompiled = true;
+            ASTDecoder decoder{*this};
+            ASTNode program = GetASTProgram();
+            decoder.Visit(program);
             return;
         }
         LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method");
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp
index d46e0f823..6f678003c 100644
--- a/src/video_core/shader/decode/other.cpp
+++ b/src/video_core/shader/decode/other.cpp
@@ -157,7 +157,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
         UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
                              "Constant buffer flow is not supported");
 
-        if (disable_flow_stack) {
+        if (decompiled) {
             break;
         }
 
@@ -171,7 +171,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
         UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
                              "Constant buffer PBK is not supported");
 
-        if (disable_flow_stack) {
+        if (decompiled) {
             break;
         }
 
@@ -186,7 +186,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
         UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}",
                              static_cast<u32>(cc));
 
-        if (disable_flow_stack) {
+        if (decompiled) {
             break;
         }
 
@@ -198,7 +198,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
         const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
         UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}",
                              static_cast<u32>(cc));
-        if (disable_flow_stack) {
+        if (decompiled) {
             break;
         }
 
diff --git a/src/video_core/shader/expr.cpp b/src/video_core/shader/expr.cpp
index ebce6339b..ca633ffb1 100644
--- a/src/video_core/shader/expr.cpp
+++ b/src/video_core/shader/expr.cpp
@@ -72,4 +72,11 @@ bool ExprAreOpposite(Expr first, Expr second) {
     return false;
 }
 
+bool ExprIsTrue(Expr first) {
+    if (ExprIsBoolean(first)) {
+        return ExprBooleanGet(first);
+    }
+    return false;
+}
+
 } // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/expr.h b/src/video_core/shader/expr.h
index f012f6fcf..b954cffb0 100644
--- a/src/video_core/shader/expr.h
+++ b/src/video_core/shader/expr.h
@@ -115,4 +115,6 @@ Expr MakeExprAnd(Expr first, Expr second);
 
 Expr MakeExprOr(Expr first, Expr second);
 
+bool ExprIsTrue(Expr first);
+
 } // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index c79f80e04..004b1e16f 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -137,7 +137,7 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
     return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
 }
 
-Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) {
+Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const {
     const Node node = MakeNode<InternalFlagNode>(flag);
     if (negated) {
         return Operation(OperationCode::LogicalNegate, node);
@@ -367,13 +367,13 @@ OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
     return op->second;
 }
 
-Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) {
+Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const {
     switch (cc) {
     case Tegra::Shader::ConditionCode::NEU:
         return GetInternalFlag(InternalFlag::Zero, true);
     default:
         UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
-        return GetPredicate(static_cast<u64>(Pred::NeverExecute));
+        return MakeNode<PredicateNode>(Pred::NeverExecute, false);
     }
 }
 
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index a91cd7d67..48c7b722e 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -15,8 +15,8 @@
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/engines/shader_bytecode.h"
 #include "video_core/engines/shader_header.h"
-#include "video_core/shader/node.h"
 #include "video_core/shader/ast.h"
+#include "video_core/shader/node.h"
 
 namespace VideoCommon::Shader {
 
@@ -141,15 +141,27 @@ public:
         return header;
     }
 
-    bool IsFlowStackDisabled() const {
-        return disable_flow_stack;
+    bool IsDecompiled() const {
+        return decompiled;
+    }
+
+    ASTNode GetASTProgram() const {
+        return program_manager.GetProgram();
+    }
+
+    u32 GetASTNumVariables() const {
+        return program_manager.GetVariables();
     }
 
     u32 ConvertAddressToNvidiaSpace(const u32 address) const {
         return (address - main_offset) * sizeof(Tegra::Shader::Instruction);
     }
 
+    /// Returns a condition code evaluated from internal flags
+    Node GetConditionCode(Tegra::Shader::ConditionCode cc) const;
+
 private:
+    friend class ASTDecoder;
     void Decode();
 
     NodeBlock DecodeRange(u32 begin, u32 end);
@@ -214,7 +226,7 @@ private:
     /// Generates a node representing an output attribute. Keeps track of used attributes.
     Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer);
     /// Generates a node representing an internal flag
-    Node GetInternalFlag(InternalFlag flag, bool negated = false);
+    Node GetInternalFlag(InternalFlag flag, bool negated = false) const;
     /// Generates a node representing a local memory address
     Node GetLocalMemory(Node address);
     /// Generates a node representing a shared memory address
@@ -272,9 +284,6 @@ private:
     /// Returns a predicate combiner operation
     OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation);
 
-    /// Returns a condition code evaluated from internal flags
-    Node GetConditionCode(Tegra::Shader::ConditionCode cc);
-
     /// Accesses a texture sampler
     const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler,
                               Tegra::Shader::TextureType type, bool is_array, bool is_shadow);
@@ -358,7 +367,7 @@ private:
     const ProgramCode& program_code;
     const u32 main_offset;
     const std::size_t program_size;
-    bool disable_flow_stack{};
+    bool decompiled{};
 
     u32 coverage_begin{};
     u32 coverage_end{};