From 2d48a7b4d0666ad16d03a22d85712617a0849046 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sat, 9 Jan 2021 03:30:07 -0300
Subject: shader: Initial recompiler work

---
 .../frontend/maxwell/control_flow.h                | 137 +++++++++++++++++++++
 1 file changed, 137 insertions(+)
 create mode 100644 src/shader_recompiler/frontend/maxwell/control_flow.h

(limited to 'src/shader_recompiler/frontend/maxwell/control_flow.h')

diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.h b/src/shader_recompiler/frontend/maxwell/control_flow.h
new file mode 100644
index 0000000000..b2ab0cdc35
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.h
@@ -0,0 +1,137 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <compare>
+#include <optional>
+#include <span>
+#include <string>
+#include <vector>
+
+#include <boost/container/small_vector.hpp>
+
+#include "shader_recompiler/environment.h"
+#include "shader_recompiler/frontend/ir/condition.h"
+#include "shader_recompiler/frontend/maxwell/instruction.h"
+#include "shader_recompiler/frontend/maxwell/location.h"
+#include "shader_recompiler/frontend/maxwell/opcode.h"
+
+namespace Shader::Maxwell::Flow {
+
+using BlockId = u32;
+using FunctionId = size_t;
+
+constexpr BlockId UNREACHABLE_BLOCK_ID{static_cast<u32>(-1)};
+
+enum class EndClass {
+    Branch,
+    Exit,
+    Return,
+    Unreachable,
+};
+
+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 Block {
+    [[nodiscard]] bool Contains(Location pc) const noexcept;
+
+    Location begin;
+    Location end;
+    EndClass end_class;
+    BlockId id;
+    Stack stack;
+    IR::Condition cond;
+    BlockId branch_true;
+    BlockId branch_false;
+};
+
+struct Label {
+    Location address;
+    BlockId block_id;
+    Stack stack;
+};
+
+struct Function {
+    Function(Location start_address);
+
+    Location entrypoint;
+    BlockId current_block_id{0};
+    boost::container::small_vector<Label, 16> labels;
+    boost::container::small_vector<u32, 0x130> blocks;
+    boost::container::small_vector<Block, 0x130> blocks_data;
+};
+
+class CFG {
+    enum class AnalysisState {
+        Branch,
+        Continue,
+    };
+
+public:
+    explicit CFG(Environment& env, Location start_address);
+
+    [[nodiscard]] std::string Dot() const;
+
+    [[nodiscard]] std::span<const Function> Functions() const noexcept {
+        return std::span(functions.data(), functions.size());
+    }
+
+private:
+    void AnalyzeLabel(FunctionId function_id, Label& label);
+
+    /// Inspect already visited blocks.
+    /// Return true when the block has already been visited
+    [[nodiscard]] bool InspectVisitedBlocks(FunctionId function_id, const Label& label);
+
+    [[nodiscard]] AnalysisState AnalyzeInst(Block& block, FunctionId function_id, Location pc);
+
+    void AnalyzeCondInst(Block& block, FunctionId function_id, Location pc, EndClass insn_end_class,
+                         IR::Condition cond);
+
+    /// Return true when the branch instruction is confirmed to be a branch
+    [[nodiscard]] bool AnalyzeBranch(Block& block, FunctionId function_id, Location pc,
+                                     Instruction inst, Opcode opcode);
+
+    void AnalyzeBRA(Block& block, FunctionId function_id, Location pc, Instruction inst,
+                    bool is_absolute);
+    void AnalyzeBRX(Block& block, Location pc, Instruction inst, bool is_absolute);
+    void AnalyzeCAL(Location pc, Instruction inst, bool is_absolute);
+    AnalysisState AnalyzeEXIT(Block& block, FunctionId function_id, Location pc, Instruction inst);
+
+    /// Return the branch target block id
+    [[nodiscard]] BlockId AddLabel(const Block& block, Stack stack, Location pc,
+                                   FunctionId function_id);
+
+    Environment& env;
+    boost::container::small_vector<Function, 1> functions;
+    FunctionId current_function_id{0};
+};
+
+} // namespace Shader::Maxwell::Flow
-- 
cgit v1.2.3-70-g09d2