From 9170200a11715d131645d1ffb92e86e6ef0d7e88 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Thu, 11 Feb 2021 16:39:06 -0300
Subject: shader: Initial implementation of an AST

---
 src/shader_recompiler/frontend/ir/basic_block.cpp | 64 +++++++++++++++++------
 1 file changed, 47 insertions(+), 17 deletions(-)

(limited to 'src/shader_recompiler/frontend/ir/basic_block.cpp')

diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp
index da33ff6f10..b5616f3941 100644
--- a/src/shader_recompiler/frontend/ir/basic_block.cpp
+++ b/src/shader_recompiler/frontend/ir/basic_block.cpp
@@ -17,6 +17,8 @@ namespace Shader::IR {
 Block::Block(ObjectPool<Inst>& inst_pool_, u32 begin, u32 end)
     : inst_pool{&inst_pool_}, location_begin{begin}, location_end{end} {}
 
+Block::Block(ObjectPool<Inst>& inst_pool_) : Block{inst_pool_, 0, 0} {}
+
 Block::~Block() = default;
 
 void Block::AppendNewInst(Opcode op, std::initializer_list<Value> args) {
@@ -38,8 +40,25 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op,
     return result_it;
 }
 
-void Block::AddImmediatePredecessor(IR::Block* immediate_predecessor) {
-    imm_predecessors.push_back(immediate_predecessor);
+void Block::SetBranches(Condition cond, Block* branch_true_, Block* branch_false_) {
+    branch_cond = cond;
+    branch_true = branch_true_;
+    branch_false = branch_false_;
+}
+
+void Block::SetBranch(Block* branch) {
+    branch_cond = Condition{true};
+    branch_true = branch;
+}
+
+void Block::SetReturn() {
+    branch_cond = Condition{true};
+    branch_true = nullptr;
+    branch_false = nullptr;
+}
+
+bool Block::IsVirtual() const noexcept {
+    return location_begin == location_end;
 }
 
 u32 Block::LocationBegin() const noexcept {
@@ -58,6 +77,12 @@ const Block::InstructionList& Block::Instructions() const noexcept {
     return instructions;
 }
 
+void Block::AddImmediatePredecessor(Block* block) {
+    if (std::ranges::find(imm_predecessors, block) == imm_predecessors.end()) {
+        imm_predecessors.push_back(block);
+    }
+}
+
 std::span<IR::Block* const> Block::ImmediatePredecessors() const noexcept {
     return imm_predecessors;
 }
@@ -70,8 +95,17 @@ static std::string BlockToIndex(const std::map<const Block*, size_t>& block_to_i
     return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(block));
 }
 
+static size_t InstIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index,
+                        const Inst* inst) {
+    const auto [it, is_inserted]{inst_to_index.emplace(inst, inst_index + 1)};
+    if (is_inserted) {
+        ++inst_index;
+    }
+    return it->second;
+}
+
 static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index,
-                              const std::map<const Inst*, size_t>& inst_to_index,
+                              std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index,
                               const Value& arg) {
     if (arg.IsEmpty()) {
         return "<null>";
@@ -80,10 +114,7 @@ static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_ind
         return BlockToIndex(block_to_index, arg.Label());
     }
     if (!arg.IsImmediate()) {
-        if (const auto it{inst_to_index.find(arg.Inst())}; it != inst_to_index.end()) {
-            return fmt::format("%{}", it->second);
-        }
-        return fmt::format("%<unknown inst {:016x}>", reinterpret_cast<u64>(arg.Inst()));
+        return fmt::format("%{}", InstIndex(inst_to_index, inst_index, arg.Inst()));
     }
     switch (arg.Type()) {
     case Type::U1:
@@ -125,14 +156,14 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>&
         const Opcode op{inst.Opcode()};
         ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst));
         if (TypeOf(op) != Type::Void) {
-            ret += fmt::format("%{:<5} = {}", inst_index, op);
+            ret += fmt::format("%{:<5} = {}", InstIndex(inst_to_index, inst_index, &inst), op);
         } else {
             ret += fmt::format("         {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
         }
-        const size_t arg_count{NumArgsOf(op)};
+        const size_t arg_count{inst.NumArgs()};
         for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) {
             const Value arg{inst.Arg(arg_index)};
-            const std::string arg_str{ArgToIndex(block_to_index, inst_to_index, arg)};
+            const std::string arg_str{ArgToIndex(block_to_index, inst_to_index, inst_index, arg)};
             ret += arg_index != 0 ? ", " : " ";
             if (op == Opcode::Phi) {
                 ret += fmt::format("[ {}, {} ]", arg_index,
@@ -140,10 +171,12 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>&
             } else {
                 ret += arg_str;
             }
-            const Type actual_type{arg.Type()};
-            const Type expected_type{ArgTypeOf(op, arg_index)};
-            if (!AreTypesCompatible(actual_type, expected_type)) {
-                ret += fmt::format("<type error: {} != {}>", actual_type, expected_type);
+            if (op != Opcode::Phi) {
+                const Type actual_type{arg.Type()};
+                const Type expected_type{ArgTypeOf(op, arg_index)};
+                if (!AreTypesCompatible(actual_type, expected_type)) {
+                    ret += fmt::format("<type error: {} != {}>", actual_type, expected_type);
+                }
             }
         }
         if (TypeOf(op) != Type::Void) {
@@ -151,9 +184,6 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>&
         } else {
             ret += '\n';
         }
-
-        inst_to_index.emplace(&inst, inst_index);
-        ++inst_index;
     }
     return ret;
 }
-- 
cgit v1.2.3-70-g09d2