From 92209f905fff33eaf4812c3d4a153ff9fffb1ed0 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 7 Jun 2018 00:58:12 -0400
Subject: [PATCH] gl_shader_decompiler: Implement BFE_IMM instruction.

---
 src/video_core/engines/shader_bytecode.h      | 18 ++++++++--
 .../renderer_opengl/gl_shader_decompiler.cpp  | 33 ++++++++++++++++---
 2 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 2cda1e63ef..32800392b9 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -265,6 +265,17 @@ union Instruction {
         BitField<49, 1, u64> negate_a;
     } iscadd;
 
+    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);
+        }
+    } bfe;
+
     union {
         BitField<48, 1, u64> negate_b;
         BitField<49, 1, u64> negate_c;
@@ -478,6 +489,7 @@ public:
     enum class Type {
         Trivial,
         Arithmetic,
+        Bfe,
         Logic,
         Shift,
         ScaledAdd,
@@ -584,9 +596,6 @@ private:
         std::vector<Matcher> table = {
 #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
             INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
-            INST("0100110000000---", Id::BFE_C, Type::Flow, "BFE_C"),
-            INST("0101110000000---", Id::BFE_R, Type::Flow, "BFE_R"),
-            INST("0011100-00000---", Id::BFE_IMM, Type::Flow, "BFE_IMM"),
             INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
             INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
             INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"),
@@ -631,6 +640,9 @@ private:
             INST("0100110000100---", Id::IMNMX_C, Type::Arithmetic, "FMNMX_IMM"),
             INST("0101110000100---", Id::IMNMX_R, Type::Arithmetic, "FMNMX_IMM"),
             INST("0011100-00100---", Id::IMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"),
+            INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"),
+            INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"),
+            INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"),
             INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"),
             INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"),
             INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8e249584fd..94c6bc4b25 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -888,8 +888,33 @@ private:
             }
             break;
         }
+        case OpCode::Type::Bfe: {
+            ASSERT_MSG(!instr.bfe.negate_b, "Unimplemented");
+
+            std::string op_a = instr.bfe.negate_a ? "-" : "";
+            op_a += regs.GetRegisterAsInteger(instr.gpr8);
+
+            switch (opcode->GetId()) {
+            case OpCode::Id::BFE_IMM: {
+                std::string inner_shift =
+                    '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
+                std::string outer_shift =
+                    '(' + inner_shift + " >> " +
+                    std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
+
+                regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
+                break;
+            }
+            default: {
+                NGLOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->GetName());
+                UNREACHABLE();
+            }
+            }
+
+            break;
+        }
         case OpCode::Type::Logic: {
-            std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, false);
+            std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true);
 
             if (instr.alu.lop.invert_a)
                 op_a = "~(" + op_a + ')';
@@ -903,17 +928,17 @@ private:
 
                 switch (instr.alu.lop.operation) {
                 case Tegra::Shader::LogicOperation::And: {
-                    regs.SetRegisterToInteger(instr.gpr0, false, 0,
+                    regs.SetRegisterToInteger(instr.gpr0, true, 0,
                                               '(' + op_a + " & " + std::to_string(imm) + ')', 1, 1);
                     break;
                 }
                 case Tegra::Shader::LogicOperation::Or: {
-                    regs.SetRegisterToInteger(instr.gpr0, false, 0,
+                    regs.SetRegisterToInteger(instr.gpr0, true, 0,
                                               '(' + op_a + " | " + std::to_string(imm) + ')', 1, 1);
                     break;
                 }
                 case Tegra::Shader::LogicOperation::Xor: {
-                    regs.SetRegisterToInteger(instr.gpr0, false, 0,
+                    regs.SetRegisterToInteger(instr.gpr0, true, 0,
                                               '(' + op_a + " ^ " + std::to_string(imm) + ')', 1, 1);
                     break;
                 }