summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-02-01 02:57:01 -0300
committerGravatar ReinUsesLisp2020-02-01 21:19:44 -0300
commit017474c3f89e5afcb3ffdb9fac3e412c40986092 (patch)
tree4164fe82d9d5ee8abb9ac3ae7d7875d163195c9b /src
parentMerge pull request #3350 from ReinUsesLisp/atom (diff)
downloadyuzu-017474c3f89e5afcb3ffdb9fac3e412c40986092.tar.gz
yuzu-017474c3f89e5afcb3ffdb9fac3e412c40986092.tar.xz
yuzu-017474c3f89e5afcb3ffdb9fac3e412c40986092.zip
shader/shift: Implement SHF_LEFT_{IMM,R}
Shifts a pair of registers to the left and returns the high register.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h20
-rw-r--r--src/video_core/shader/decode/shift.cpp79
2 files changed, 89 insertions, 10 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index f443ec0fe..901adb97b 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -624,6 +624,19 @@ enum class ShuffleOperation : u64 {
624 Bfly = 3, // shuffleXorNV 624 Bfly = 3, // shuffleXorNV
625}; 625};
626 626
627enum class ShfType : u64 {
628 Bits32 = 0,
629 U64 = 2,
630 S64 = 3,
631};
632
633enum class ShfXmode : u64 {
634 None = 0,
635 HI = 1,
636 X = 2,
637 XHI = 3,
638};
639
627union Instruction { 640union Instruction {
628 constexpr Instruction& operator=(const Instruction& instr) { 641 constexpr Instruction& operator=(const Instruction& instr) {
629 value = instr.value; 642 value = instr.value;
@@ -776,6 +789,13 @@ union Instruction {
776 } shr; 789 } shr;
777 790
778 union { 791 union {
792 BitField<37, 2, ShfType> type;
793 BitField<48, 2, ShfXmode> xmode;
794 BitField<50, 1, u64> wrap;
795 BitField<20, 6, u64> immediate;
796 } shf;
797
798 union {
779 BitField<39, 5, u64> shift_amount; 799 BitField<39, 5, u64> shift_amount;
780 BitField<48, 1, u64> negate_b; 800 BitField<48, 1, u64> negate_b;
781 BitField<49, 1, u64> negate_a; 801 BitField<49, 1, u64> negate_a;
diff --git a/src/video_core/shader/decode/shift.cpp b/src/video_core/shader/decode/shift.cpp
index d419e9c45..98e71b5f2 100644
--- a/src/video_core/shader/decode/shift.cpp
+++ b/src/video_core/shader/decode/shift.cpp
@@ -10,8 +10,30 @@
10 10
11namespace VideoCommon::Shader { 11namespace VideoCommon::Shader {
12 12
13using std::move;
13using Tegra::Shader::Instruction; 14using Tegra::Shader::Instruction;
14using Tegra::Shader::OpCode; 15using Tegra::Shader::OpCode;
16using Tegra::Shader::ShfType;
17using Tegra::Shader::ShfXmode;
18
19namespace {
20
21Node Shift(OperationCode opcode, Node value, Node shift) {
22 Node is_full = Operation(OperationCode::LogicalIEqual, shift, Immediate(32));
23 Node shifted = Operation(opcode, move(value), move(shift));
24 return Operation(OperationCode::Select, move(is_full), Immediate(0), move(shifted));
25}
26
27Node ClampShift(Node shift, s32 size = 32) {
28 shift = Operation(OperationCode::IMax, move(shift), Immediate(0));
29 return Operation(OperationCode::IMin, move(shift), Immediate(size));
30}
31
32Node WrapShift(Node shift, s32 size = 32) {
33 return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1));
34}
35
36} // Anonymous namespace
15 37
16u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { 38u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
17 const Instruction instr = {program_code[pc]}; 39 const Instruction instr = {program_code[pc]};
@@ -32,25 +54,62 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
32 case OpCode::Id::SHR_C: 54 case OpCode::Id::SHR_C:
33 case OpCode::Id::SHR_R: 55 case OpCode::Id::SHR_R:
34 case OpCode::Id::SHR_IMM: { 56 case OpCode::Id::SHR_IMM: {
35 if (instr.shr.wrap) { 57 op_b = instr.shr.wrap ? WrapShift(move(op_b)) : ClampShift(move(op_b));
36 op_b = Operation(OperationCode::UBitwiseAnd, std::move(op_b), Immediate(0x1f));
37 } else {
38 op_b = Operation(OperationCode::IMax, std::move(op_b), Immediate(0));
39 op_b = Operation(OperationCode::IMin, std::move(op_b), Immediate(31));
40 }
41 58
42 Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed, 59 Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed,
43 std::move(op_a), std::move(op_b)); 60 move(op_a), move(op_b));
44 SetInternalFlagsFromInteger(bb, value, instr.generates_cc); 61 SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
45 SetRegister(bb, instr.gpr0, std::move(value)); 62 SetRegister(bb, instr.gpr0, move(value));
46 break; 63 break;
47 } 64 }
48 case OpCode::Id::SHL_C: 65 case OpCode::Id::SHL_C:
49 case OpCode::Id::SHL_R: 66 case OpCode::Id::SHL_R:
50 case OpCode::Id::SHL_IMM: { 67 case OpCode::Id::SHL_IMM: {
51 const Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b); 68 Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
52 SetInternalFlagsFromInteger(bb, value, instr.generates_cc); 69 SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
53 SetRegister(bb, instr.gpr0, value); 70 SetRegister(bb, instr.gpr0, move(value));
71 break;
72 }
73 case OpCode::Id::SHF_LEFT_R:
74 case OpCode::Id::SHF_LEFT_IMM: {
75 UNIMPLEMENTED_IF(instr.generates_cc);
76 UNIMPLEMENTED_IF_MSG(instr.shf.xmode != ShfXmode::None, "xmode={}",
77 static_cast<int>(instr.shf.xmode.Value()));
78
79 if (instr.is_b_imm) {
80 op_b = Immediate(static_cast<u32>(instr.shf.immediate));
81 }
82 const s32 size = instr.shf.type == ShfType::Bits32 ? 32 : 64;
83 Node shift = instr.shf.wrap ? WrapShift(move(op_b), size) : ClampShift(move(op_b), size);
84
85 Node negated_shift = Operation(OperationCode::INegate, shift);
86 Node low_shift = Operation(OperationCode::IAdd, move(negated_shift), Immediate(32));
87
88 Node low = move(op_a);
89 Node high = GetRegister(instr.gpr39);
90 Node value;
91 if (instr.shf.type == ShfType::Bits32) {
92 high = Shift(OperationCode::ILogicalShiftLeft, move(high), move(shift));
93 low = Shift(OperationCode::ILogicalShiftRight, move(op_a), move(low_shift));
94 value = Operation(OperationCode::IBitwiseOr, move(high), move(low));
95 } else {
96 // These values are used when the shift value is less than 32
97 Node less_low = Operation(OperationCode::ILogicalShiftRight, low, low_shift);
98 Node less_high = Operation(OperationCode::ILogicalShiftLeft, high, shift);
99 Node less = Operation(OperationCode::IBitwiseOr, move(less_low), move(less_high));
100
101 // And these when it's larger than or 32
102 Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32));
103 Node greater = Shift(OperationCode::ILogicalShiftLeft, move(low), move(reduced));
104
105 Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32));
106 Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0));
107
108 value = Operation(OperationCode::Select, move(is_less), move(less), move(greater));
109 value = Operation(OperationCode::Select, move(is_zero), move(high), move(value));
110 }
111
112 SetRegister(bb, instr.gpr0, move(value));
54 break; 113 break;
55 } 114 }
56 default: 115 default: