From 465ba30d08fd294a6ccc05f9257894241a5240fc Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Fri, 13 Mar 2020 12:48:01 +0700
Subject: [PATCH 1/9] shader_decode: Reimplement BFE instructions

---
 src/video_core/shader/decode/bfe.cpp | 44 +++++++++++++++-------------
 1 file changed, 23 insertions(+), 21 deletions(-)

diff --git a/src/video_core/shader/decode/bfe.cpp b/src/video_core/shader/decode/bfe.cpp
index e02bcd0972..c3ef883737 100644
--- a/src/video_core/shader/decode/bfe.cpp
+++ b/src/video_core/shader/decode/bfe.cpp
@@ -17,32 +17,34 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
     const Instruction instr = {program_code[pc]};
     const auto opcode = OpCode::Decode(instr);
 
-    UNIMPLEMENTED_IF(instr.bfe.negate_b);
-
     Node op_a = GetRegister(instr.gpr8);
-    op_a = GetOperandAbsNegInteger(op_a, false, instr.bfe.negate_a, false);
+    Node op_b = [&] {
+        switch (opcode->get().GetId()) {
+        case OpCode::Id::BFE_R:
+            return GetRegister(instr.gpr20);
+        case OpCode::Id::BFE_C:
+            return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
+        case OpCode::Id::BFE_IMM:
+            return Immediate(instr.alu.GetSignedImm20_20());
+        default:
+            UNREACHABLE();
+            return Immediate(0);
+        }
+    }();
 
-    switch (opcode->get().GetId()) {
-    case OpCode::Id::BFE_IMM: {
-        UNIMPLEMENTED_IF_MSG(instr.generates_cc,
-                             "Condition codes generation in BFE is not implemented");
+    UNIMPLEMENTED_IF_MSG(instr.bfe.rd_cc, "Condition codes in BFE is not implemented");
+    UNIMPLEMENTED_IF_MSG(instr.bfe.brev, "BREV in BFE is not implemented");
 
-        const Node inner_shift_imm = Immediate(static_cast<u32>(instr.bfe.GetLeftShiftValue()));
-        const Node outer_shift_imm =
-            Immediate(static_cast<u32>(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position));
+    const bool is_signed = instr.bfe.is_signed;
 
-        const Node inner_shift =
-            Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, op_a, inner_shift_imm);
-        const Node outer_shift =
-            Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, inner_shift, outer_shift_imm);
+    const auto start_position = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_b,
+                                                Immediate(0), Immediate(8));
+    const auto bits = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_b,
+                                      Immediate(8), Immediate(8));
 
-        SetInternalFlagsFromInteger(bb, outer_shift, instr.generates_cc);
-        SetRegister(bb, instr.gpr0, outer_shift);
-        break;
-    }
-    default:
-        UNIMPLEMENTED_MSG("Unhandled BFE instruction: {}", opcode->get().GetName());
-    }
+    auto result =
+        SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_a, start_position, bits);
+    SetRegister(bb, instr.gpr0, result);
 
     return pc;
 }

From 911c56ccef5ea9ce2cad6f92adff0b575b2a9bc6 Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Fri, 13 Mar 2020 12:50:32 +0700
Subject: [PATCH 2/9] node_helper: add IBitfieldExtract case

---
 src/video_core/shader/node_helper.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/video_core/shader/node_helper.cpp b/src/video_core/shader/node_helper.cpp
index b3dcd291c1..76c56abb5a 100644
--- a/src/video_core/shader/node_helper.cpp
+++ b/src/video_core/shader/node_helper.cpp
@@ -68,6 +68,8 @@ OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed)
         return OperationCode::UBitwiseXor;
     case OperationCode::IBitwiseNot:
         return OperationCode::UBitwiseNot;
+    case OperationCode::IBitfieldExtract:
+        return OperationCode::UBitfieldExtract;
     case OperationCode::IBitfieldInsert:
         return OperationCode::UBitfieldInsert;
     case OperationCode::IBitCount:

From 93547cac68ac5433c1080b53abe9822045f07604 Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Fri, 13 Mar 2020 12:52:16 +0700
Subject: [PATCH 3/9] shader_bytecode: update BFE instructions struct.

---
 src/video_core/engines/shader_bytecode.h | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index c9bc83cd7d..eba42deb45 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -911,14 +911,9 @@ union Instruction {
     } fadd32i;
 
     union {
-        BitField<20, 8, u64> shift_position;
-        BitField<28, 8, u64> shift_length;
-        BitField<48, 1, u64> negate_b;
-        BitField<49, 1, u64> negate_a;
-
-        u64 GetLeftShiftValue() const {
-            return 32 - (shift_position + shift_length);
-        }
+        BitField<40, 1, u64> brev;
+        BitField<47, 1, u64> rd_cc;
+        BitField<48, 1, u64> is_signed;
     } bfe;
 
     union {

From 96a4abe12d69a3fa35dd39e359438da18056f6ad Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Fri, 13 Mar 2020 14:13:31 +0700
Subject: [PATCH 4/9] shader_decode: implement BREV on BFE

Implement reverse parallel follow: https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
---
 src/video_core/shader/decode/bfe.cpp | 31 ++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/src/video_core/shader/decode/bfe.cpp b/src/video_core/shader/decode/bfe.cpp
index c3ef883737..911d536570 100644
--- a/src/video_core/shader/decode/bfe.cpp
+++ b/src/video_core/shader/decode/bfe.cpp
@@ -33,17 +33,36 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
     }();
 
     UNIMPLEMENTED_IF_MSG(instr.bfe.rd_cc, "Condition codes in BFE is not implemented");
-    UNIMPLEMENTED_IF_MSG(instr.bfe.brev, "BREV in BFE is not implemented");
 
     const bool is_signed = instr.bfe.is_signed;
 
-    const auto start_position = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_b,
-                                                Immediate(0), Immediate(8));
+    if (instr.bfe.brev) {
+        const auto swap = [&](u32 s, u32 mask) {
+            Node v1 =
+                SignedOperation(OperationCode::ILogicalShiftRight, is_signed, op_a, Immediate(s));
+            if (mask != 0) {
+                v1 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, v1, Immediate(mask));
+            }
+            Node v2 = op_a;
+            if (mask != 0) {
+                v2 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, op_a, Immediate(mask));
+            }
+            v2 = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, v2, Immediate(s));
+            return SignedOperation(OperationCode::IBitwiseOr, is_signed, v1, v2);
+        };
+        op_a = swap(1, 0x55555555U);
+        op_a = swap(2, 0x33333333U);
+        op_a = swap(4, 0x0F0F0F0FU);
+        op_a = swap(8, 0x00FF00FFU);
+        op_a = swap(16, 0);
+    }
+
+    const auto offset = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_b,
+                                        Immediate(0), Immediate(8));
     const auto bits = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_b,
                                       Immediate(8), Immediate(8));
-
-    auto result =
-        SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_a, start_position, bits);
+    const auto result =
+        SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_a, offset, bits);
     SetRegister(bb, instr.gpr0, result);
 
     return pc;

From 70ff82f72d4dfd0b296e885b0f1517d0a46e64e1 Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Fri, 13 Mar 2020 14:20:18 +0700
Subject: [PATCH 5/9] shader_decode: BFE add ref of reverse parallel method.

---
 src/video_core/shader/decode/bfe.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/video_core/shader/decode/bfe.cpp b/src/video_core/shader/decode/bfe.cpp
index 911d536570..39587e0df9 100644
--- a/src/video_core/shader/decode/bfe.cpp
+++ b/src/video_core/shader/decode/bfe.cpp
@@ -36,6 +36,9 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
 
     const bool is_signed = instr.bfe.is_signed;
 
+    // using reverse parallel method in
+    // https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
+    // note for later if possible to implement faster method.
     if (instr.bfe.brev) {
         const auto swap = [&](u32 s, u32 mask) {
             Node v1 =

From 325977c0c6947597618afca51494df62bacefb76 Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Fri, 13 Mar 2020 15:35:15 +0700
Subject: [PATCH 6/9] Apply suggestions from code review

Co-Authored-By: Mat M. <mathew1800@gmail.com>
---
 src/video_core/shader/decode/bfe.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/video_core/shader/decode/bfe.cpp b/src/video_core/shader/decode/bfe.cpp
index 39587e0df9..7f2647973e 100644
--- a/src/video_core/shader/decode/bfe.cpp
+++ b/src/video_core/shader/decode/bfe.cpp
@@ -44,14 +44,14 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
             Node v1 =
                 SignedOperation(OperationCode::ILogicalShiftRight, is_signed, op_a, Immediate(s));
             if (mask != 0) {
-                v1 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, v1, Immediate(mask));
+                v1 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, std::move(v1), Immediate(mask));
             }
             Node v2 = op_a;
             if (mask != 0) {
-                v2 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, op_a, Immediate(mask));
+                v2 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, std::move(v2), Immediate(mask));
             }
-            v2 = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, v2, Immediate(s));
-            return SignedOperation(OperationCode::IBitwiseOr, is_signed, v1, v2);
+            v2 = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, std::move(v2), Immediate(s));
+            return SignedOperation(OperationCode::IBitwiseOr, is_signed, std::move(v1), std::move(v2));
         };
         op_a = swap(1, 0x55555555U);
         op_a = swap(2, 0x33333333U);
@@ -66,7 +66,7 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
                                       Immediate(8), Immediate(8));
     const auto result =
         SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_a, offset, bits);
-    SetRegister(bb, instr.gpr0, result);
+    SetRegister(bb, instr.gpr0, std::move(result));
 
     return pc;
 }

From 00607fe1e018e9b9144c2e1d8dac96150455bc0b Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Fri, 13 Mar 2020 15:38:57 +0700
Subject: [PATCH 7/9] clang-format

---
 src/video_core/shader/decode/bfe.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/video_core/shader/decode/bfe.cpp b/src/video_core/shader/decode/bfe.cpp
index 7f2647973e..80253aee3a 100644
--- a/src/video_core/shader/decode/bfe.cpp
+++ b/src/video_core/shader/decode/bfe.cpp
@@ -44,14 +44,18 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
             Node v1 =
                 SignedOperation(OperationCode::ILogicalShiftRight, is_signed, op_a, Immediate(s));
             if (mask != 0) {
-                v1 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, std::move(v1), Immediate(mask));
+                v1 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, std::move(v1),
+                                     Immediate(mask));
             }
             Node v2 = op_a;
             if (mask != 0) {
-                v2 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, std::move(v2), Immediate(mask));
+                v2 = SignedOperation(OperationCode::IBitwiseAnd, is_signed, std::move(v2),
+                                     Immediate(mask));
             }
-            v2 = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, std::move(v2), Immediate(s));
-            return SignedOperation(OperationCode::IBitwiseOr, is_signed, std::move(v1), std::move(v2));
+            v2 = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, std::move(v2),
+                                 Immediate(s));
+            return SignedOperation(OperationCode::IBitwiseOr, is_signed, std::move(v1),
+                                   std::move(v2));
         };
         op_a = swap(1, 0x55555555U);
         op_a = swap(2, 0x33333333U);

From 240d45830d16342cb357427894690ddde660e259 Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Sat, 14 Mar 2020 09:57:24 +0700
Subject: [PATCH 8/9] nit

---
 src/video_core/shader/decode/bfe.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/video_core/shader/decode/bfe.cpp b/src/video_core/shader/decode/bfe.cpp
index 80253aee3a..69ef9013d8 100644
--- a/src/video_core/shader/decode/bfe.cpp
+++ b/src/video_core/shader/decode/bfe.cpp
@@ -68,7 +68,7 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
                                         Immediate(0), Immediate(8));
     const auto bits = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_b,
                                       Immediate(8), Immediate(8));
-    const auto result =
+    auto result =
         SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_a, offset, bits);
     SetRegister(bb, instr.gpr0, std::move(result));
 

From 3287b1247d97682b443f8db050b4ee73dac1d05b Mon Sep 17 00:00:00 2001
From: Nguyen Dac Nam <nam.kazt.91@gmail.com>
Date: Sat, 14 Mar 2020 10:07:40 +0700
Subject: [PATCH 9/9] clang-format

---
 src/video_core/shader/decode/bfe.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/video_core/shader/decode/bfe.cpp b/src/video_core/shader/decode/bfe.cpp
index 69ef9013d8..8e3b46e8e0 100644
--- a/src/video_core/shader/decode/bfe.cpp
+++ b/src/video_core/shader/decode/bfe.cpp
@@ -68,8 +68,7 @@ u32 ShaderIR::DecodeBfe(NodeBlock& bb, u32 pc) {
                                         Immediate(0), Immediate(8));
     const auto bits = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_b,
                                       Immediate(8), Immediate(8));
-    auto result =
-        SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_a, offset, bits);
+    auto result = SignedOperation(OperationCode::IBitfieldExtract, is_signed, op_a, offset, bits);
     SetRegister(bb, instr.gpr0, std::move(result));
 
     return pc;