From 027f443e699652fc30a849efaf8c12725a7b5729 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 23 Dec 2018 01:33:47 -0300
Subject: [PATCH] shader_decode: Implement POPC

---
 src/video_core/shader/decode/arithmetic_integer.cpp | 10 ++++++++++
 src/video_core/shader/glsl_decompiler.cpp           |  7 +++++++
 src/video_core/shader/shader_ir.cpp                 |  2 ++
 src/video_core/shader/shader_ir.h                   |  4 +++-
 4 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index b12dc5ba8..271ce205b 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -119,6 +119,16 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) {
         SetRegister(bb, instr.gpr0, value);
         break;
     }
+    case OpCode::Id::POPC_C:
+    case OpCode::Id::POPC_R:
+    case OpCode::Id::POPC_IMM: {
+        if (instr.popc.invert) {
+            op_b = Operation(OperationCode::IBitwiseNot, NO_PRECISE, op_b);
+        }
+        const Node value = Operation(OperationCode::IBitCount, PRECISE, op_b);
+        SetRegister(bb, instr.gpr0, value);
+        break;
+    }
     case OpCode::Id::SEL_C:
     case OpCode::Id::SEL_R:
     case OpCode::Id::SEL_IMM: {
diff --git a/src/video_core/shader/glsl_decompiler.cpp b/src/video_core/shader/glsl_decompiler.cpp
index b93ea9ec6..1aff62882 100644
--- a/src/video_core/shader/glsl_decompiler.cpp
+++ b/src/video_core/shader/glsl_decompiler.cpp
@@ -908,6 +908,11 @@ private:
                                   Type::Int);
     }
 
+    template <Type type>
+    std::string BitCount(Operation operation) {
+        return GenerateUnary(operation, "bitCount", type, type, false);
+    }
+
     std::string HNegate(Operation operation) {
         const auto GetNegate = [&](std::size_t index) -> std::string {
             if (const auto pred = std::get_if<PredicateNode>(operation[index])) {
@@ -1273,6 +1278,7 @@ private:
         &BitwiseXor<Type::Int>,
         &BitwiseNot<Type::Int>,
         &BitfieldInsert<Type::Int>,
+        &BitCount<Type::Int>,
 
         &Add<Type::Uint>,
         &Mul<Type::Uint>,
@@ -1289,6 +1295,7 @@ private:
         &BitwiseXor<Type::Uint>,
         &BitwiseNot<Type::Uint>,
         &BitfieldInsert<Type::Uint>,
+        &BitCount<Type::Uint>,
 
         &Add<Type::HalfFloat>,
         &Mul<Type::HalfFloat>,
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index 1f39dc6d0..1fc838d15 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -386,6 +386,8 @@ void ShaderIR::SetLocalMemory(BasicBlock& bb, Node address, Node value) {
         return OperationCode::UBitwiseNot;
     case OperationCode::IBitfieldInsert:
         return OperationCode::UBitfieldInsert;
+    case OperationCode::IBitCount:
+        return OperationCode::UBitCount;
     case OperationCode::LogicalILessThan:
         return OperationCode::LogicalULessThan;
     case OperationCode::LogicalIEqual:
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 231f58f6a..ccdf316ac 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -89,6 +89,7 @@ enum class OperationCode {
     IBitwiseXor,           /// (MetaArithmetic, int a, int b) -> int
     IBitwiseNot,           /// (MetaArithmetic, int a) -> int
     IBitfieldInsert,       /// (MetaArithmetic, int base, int insert, int offset, int bits) -> int
+    IBitCount,             /// (MetaArithmetic, int) -> int
 
     UAdd,                  /// (MetaArithmetic, uint a, uint b) -> uint
     UMul,                  /// (MetaArithmetic, uint a, uint b) -> uint
@@ -103,8 +104,9 @@ enum class OperationCode {
     UBitwiseAnd,           /// (MetaArithmetic, uint a, uint b) -> uint
     UBitwiseOr,            /// (MetaArithmetic, uint a, uint b) -> uint
     UBitwiseXor,           /// (MetaArithmetic, uint a, uint b) -> uint
-    UBitwiseNot,           /// (MetaArithmetic, uint a) -> int
+    UBitwiseNot,           /// (MetaArithmetic, uint a) -> uint
     UBitfieldInsert, /// (MetaArithmetic, uint base, uint insert, int offset, int bits) -> uint
+    UBitCount,       /// (MetaArithmetic, uint) -> uint
 
     HAdd,      /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
     HMul,      /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2