From fc93bc2abde0b54a0a495f9b28a76fd34b47f320 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 4 Apr 2021 03:04:48 -0300
Subject: shader: Implement BAR and fix memory barriers

---
 src/shader_recompiler/frontend/ir/ir_emitter.cpp   |  4 ++
 src/shader_recompiler/frontend/ir/ir_emitter.h     |  1 +
 .../frontend/ir/microinstruction.cpp               |  4 ++
 src/shader_recompiler/frontend/ir/opcodes.inc      |  1 +
 .../maxwell/translate/impl/barrier_operations.cpp  | 58 +++++++++++++++++++++-
 5 files changed, 66 insertions(+), 2 deletions(-)

(limited to 'src/shader_recompiler/frontend')

diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index dbd38a28b3..246c3b9ef1 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -82,6 +82,10 @@ void IREmitter::SelectionMerge(Block* merge_block) {
     Inst(Opcode::SelectionMerge, merge_block);
 }
 
+void IREmitter::Barrier() {
+    Inst(Opcode::Barrier);
+}
+
 void IREmitter::MemoryBarrier(MemoryScope scope) {
     switch (scope) {
     case MemoryScope::Workgroup:
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 81a57fefea..1b00c548d0 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -128,6 +128,7 @@ public:
     [[nodiscard]] Value Select(const U1& condition, const Value& true_value,
                                const Value& false_value);
 
+    [[nodiscard]] void Barrier();
     [[nodiscard]] void MemoryBarrier(MemoryScope scope);
 
     template <typename Dest, typename Source>
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index 074c71d533..481202d94b 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -57,6 +57,10 @@ bool Inst::MayHaveSideEffects() const noexcept {
     case Opcode::Return:
     case Opcode::Unreachable:
     case Opcode::DemoteToHelperInvocation:
+    case Opcode::Barrier:
+    case Opcode::MemoryBarrierWorkgroupLevel:
+    case Opcode::MemoryBarrierDeviceLevel:
+    case Opcode::MemoryBarrierSystemLevel:
     case Opcode::Prologue:
     case Opcode::Epilogue:
     case Opcode::SetAttribute:
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 734f5328be..dcd54bcf79 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -17,6 +17,7 @@ OPCODE(Unreachable,                                         Void,
 OPCODE(DemoteToHelperInvocation,                            Void,           Label,                                                                          )
 
 // Barriers
+OPCODE(Barrier,                                             Void,                                                                                           )
 OPCODE(MemoryBarrierWorkgroupLevel,                         Void,                                                                                           )
 OPCODE(MemoryBarrierDeviceLevel,                            Void,                                                                                           )
 OPCODE(MemoryBarrierSystemLevel,                            Void,                                                                                           )
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp
index 26d5e276bc..2a2a294dfa 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/barrier_operations.cpp
@@ -38,6 +38,7 @@ void TranslatorVisitor::MEMBAR(u64 inst) {
         u64 raw;
         BitField<8, 2, LocalScope> scope;
     } membar{inst};
+
     ir.MemoryBarrier(LocalScopeToMemoryScope(membar.scope));
 }
 
@@ -45,8 +46,61 @@ void TranslatorVisitor::DEPBAR() {
     // DEPBAR is a no-op
 }
 
-void TranslatorVisitor::BAR(u64) {
-    throw NotImplementedException("Instruction {} is not implemented", Opcode::BAR);
+void TranslatorVisitor::BAR(u64 insn) {
+    enum class Mode {
+        RedPopc,
+        Scan,
+        RedAnd,
+        RedOr,
+        Sync,
+        Arrive,
+    };
+    union {
+        u64 raw;
+        BitField<43, 1, u64> is_a_imm;
+        BitField<44, 1, u64> is_b_imm;
+        BitField<8, 8, u64> imm_a;
+        BitField<20, 12, u64> imm_b;
+        BitField<42, 1, u64> neg_pred;
+        BitField<39, 3, IR::Pred> pred;
+    } const bar{insn};
+
+    const Mode mode{[insn] {
+        switch (insn & 0x0000009B00000000ULL) {
+        case 0x0000000200000000ULL:
+            return Mode::RedPopc;
+        case 0x0000000300000000ULL:
+            return Mode::Scan;
+        case 0x0000000A00000000ULL:
+            return Mode::RedAnd;
+        case 0x0000001200000000ULL:
+            return Mode::RedOr;
+        case 0x0000008000000000ULL:
+            return Mode::Sync;
+        case 0x0000008100000000ULL:
+            return Mode::Arrive;
+        }
+        throw NotImplementedException("Invalid encoding");
+    }()};
+    if (mode != Mode::Sync) {
+        throw NotImplementedException("BAR mode {}", mode);
+    }
+    if (bar.is_a_imm == 0) {
+        throw NotImplementedException("Non-immediate input A");
+    }
+    if (bar.imm_a != 0) {
+        throw NotImplementedException("Non-zero input A");
+    }
+    if (bar.is_b_imm == 0) {
+        throw NotImplementedException("Non-immediate input B");
+    }
+    if (bar.imm_b != 0) {
+        throw NotImplementedException("Non-zero input B");
+    }
+    if (bar.pred != IR::Pred::PT && bar.neg_pred != 0) {
+        throw NotImplementedException("Non-true input predicate");
+    }
+    ir.Barrier();
 }
 
 } // namespace Shader::Maxwell
-- 
cgit v1.2.3-70-g09d2