diff options
| author | 2020-02-07 22:06:57 -0500 | |
|---|---|---|
| committer | 2020-02-07 22:06:57 -0500 | |
| commit | 90df4b8e2b07be217b8fc2d08b766577710b3945 (patch) | |
| tree | 72d14549e5b0ab0e8de836ece410667b278c2a2f /src | |
| parent | Merge pull request #3381 from bunnei/ipc-fix (diff) | |
| parent | shader/shift: Implement SHIFT_RIGHT_{IMM,R} (diff) | |
| download | yuzu-90df4b8e2b07be217b8fc2d08b766577710b3945.tar.gz yuzu-90df4b8e2b07be217b8fc2d08b766577710b3945.tar.xz yuzu-90df4b8e2b07be217b8fc2d08b766577710b3945.zip | |
Merge pull request #3369 from ReinUsesLisp/shf
shader/shift: Implement SHF
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 20 | ||||
| -rw-r--r-- | src/video_core/shader/decode/shift.cpp | 113 |
2 files changed, 122 insertions, 11 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 81b6d9eff..402869fde 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 | ||
| 627 | enum class ShfType : u64 { | ||
| 628 | Bits32 = 0, | ||
| 629 | U64 = 2, | ||
| 630 | S64 = 3, | ||
| 631 | }; | ||
| 632 | |||
| 633 | enum class ShfXmode : u64 { | ||
| 634 | None = 0, | ||
| 635 | HI = 1, | ||
| 636 | X = 2, | ||
| 637 | XHI = 3, | ||
| 638 | }; | ||
| 639 | |||
| 627 | union Instruction { | 640 | union 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..3b391d3e6 100644 --- a/src/video_core/shader/decode/shift.cpp +++ b/src/video_core/shader/decode/shift.cpp | |||
| @@ -10,8 +10,80 @@ | |||
| 10 | 10 | ||
| 11 | namespace VideoCommon::Shader { | 11 | namespace VideoCommon::Shader { |
| 12 | 12 | ||
| 13 | using std::move; | ||
| 13 | using Tegra::Shader::Instruction; | 14 | using Tegra::Shader::Instruction; |
| 14 | using Tegra::Shader::OpCode; | 15 | using Tegra::Shader::OpCode; |
| 16 | using Tegra::Shader::ShfType; | ||
| 17 | using Tegra::Shader::ShfXmode; | ||
| 18 | |||
| 19 | namespace { | ||
| 20 | |||
| 21 | Node IsFull(Node shift) { | ||
| 22 | return Operation(OperationCode::LogicalIEqual, move(shift), Immediate(32)); | ||
| 23 | } | ||
| 24 | |||
| 25 | Node Shift(OperationCode opcode, Node value, Node shift) { | ||
| 26 | Node is_full = Operation(OperationCode::LogicalIEqual, shift, Immediate(32)); | ||
| 27 | Node shifted = Operation(opcode, move(value), shift); | ||
| 28 | return Operation(OperationCode::Select, IsFull(move(shift)), Immediate(0), move(shifted)); | ||
| 29 | } | ||
| 30 | |||
| 31 | Node ClampShift(Node shift, s32 size = 32) { | ||
| 32 | shift = Operation(OperationCode::IMax, move(shift), Immediate(0)); | ||
| 33 | return Operation(OperationCode::IMin, move(shift), Immediate(size)); | ||
| 34 | } | ||
| 35 | |||
| 36 | Node WrapShift(Node shift, s32 size = 32) { | ||
| 37 | return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1)); | ||
| 38 | } | ||
| 39 | |||
| 40 | Node ShiftRight(Node low, Node high, Node shift, Node low_shift, ShfType type) { | ||
| 41 | // These values are used when the shift value is less than 32 | ||
| 42 | Node less_low = Shift(OperationCode::ILogicalShiftRight, low, shift); | ||
| 43 | Node less_high = Shift(OperationCode::ILogicalShiftLeft, high, low_shift); | ||
| 44 | Node less = Operation(OperationCode::IBitwiseOr, move(less_high), move(less_low)); | ||
| 45 | |||
| 46 | if (type == ShfType::Bits32) { | ||
| 47 | // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits | ||
| 48 | return Operation(OperationCode::Select, IsFull(move(shift)), move(high), move(less)); | ||
| 49 | } | ||
| 50 | |||
| 51 | // And these when it's larger than or 32 | ||
| 52 | const bool is_signed = type == ShfType::S64; | ||
| 53 | const auto opcode = SignedToUnsignedCode(OperationCode::IArithmeticShiftRight, is_signed); | ||
| 54 | Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32)); | ||
| 55 | Node greater = Shift(opcode, high, move(reduced)); | ||
| 56 | |||
| 57 | Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32)); | ||
| 58 | Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0)); | ||
| 59 | |||
| 60 | Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater)); | ||
| 61 | return Operation(OperationCode::Select, move(is_zero), move(high), move(value)); | ||
| 62 | } | ||
| 63 | |||
| 64 | Node ShiftLeft(Node low, Node high, Node shift, Node low_shift, ShfType type) { | ||
| 65 | // These values are used when the shift value is less than 32 | ||
| 66 | Node less_low = Operation(OperationCode::ILogicalShiftRight, low, low_shift); | ||
| 67 | Node less_high = Operation(OperationCode::ILogicalShiftLeft, high, shift); | ||
| 68 | Node less = Operation(OperationCode::IBitwiseOr, move(less_low), move(less_high)); | ||
| 69 | |||
| 70 | if (type == ShfType::Bits32) { | ||
| 71 | // On 32 bit shifts we are either full (shifting 32) or shifting less than 32 bits | ||
| 72 | return Operation(OperationCode::Select, IsFull(move(shift)), move(low), move(less)); | ||
| 73 | } | ||
| 74 | |||
| 75 | // And these when it's larger than or 32 | ||
| 76 | Node reduced = Operation(OperationCode::IAdd, shift, Immediate(-32)); | ||
| 77 | Node greater = Shift(OperationCode::ILogicalShiftLeft, move(low), move(reduced)); | ||
| 78 | |||
| 79 | Node is_less = Operation(OperationCode::LogicalILessThan, shift, Immediate(32)); | ||
| 80 | Node is_zero = Operation(OperationCode::LogicalIEqual, move(shift), Immediate(0)); | ||
| 81 | |||
| 82 | Node value = Operation(OperationCode::Select, move(is_less), move(less), move(greater)); | ||
| 83 | return Operation(OperationCode::Select, move(is_zero), move(high), move(value)); | ||
| 84 | } | ||
| 85 | |||
| 86 | } // Anonymous namespace | ||
| 15 | 87 | ||
| 16 | u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { | 88 | u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { |
| 17 | const Instruction instr = {program_code[pc]}; | 89 | const Instruction instr = {program_code[pc]}; |
| @@ -28,29 +100,48 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { | |||
| 28 | } | 100 | } |
| 29 | }(); | 101 | }(); |
| 30 | 102 | ||
| 31 | switch (opcode->get().GetId()) { | 103 | switch (const auto opid = opcode->get().GetId(); opid) { |
| 32 | case OpCode::Id::SHR_C: | 104 | case OpCode::Id::SHR_C: |
| 33 | case OpCode::Id::SHR_R: | 105 | case OpCode::Id::SHR_R: |
| 34 | case OpCode::Id::SHR_IMM: { | 106 | case OpCode::Id::SHR_IMM: { |
| 35 | if (instr.shr.wrap) { | 107 | 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 | 108 | ||
| 42 | Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed, | 109 | Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed, |
| 43 | std::move(op_a), std::move(op_b)); | 110 | move(op_a), move(op_b)); |
| 44 | SetInternalFlagsFromInteger(bb, value, instr.generates_cc); | 111 | SetInternalFlagsFromInteger(bb, value, instr.generates_cc); |
| 45 | SetRegister(bb, instr.gpr0, std::move(value)); | 112 | SetRegister(bb, instr.gpr0, move(value)); |
| 46 | break; | 113 | break; |
| 47 | } | 114 | } |
| 48 | case OpCode::Id::SHL_C: | 115 | case OpCode::Id::SHL_C: |
| 49 | case OpCode::Id::SHL_R: | 116 | case OpCode::Id::SHL_R: |
| 50 | case OpCode::Id::SHL_IMM: { | 117 | case OpCode::Id::SHL_IMM: { |
| 51 | const Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b); | 118 | Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b); |
| 52 | SetInternalFlagsFromInteger(bb, value, instr.generates_cc); | 119 | SetInternalFlagsFromInteger(bb, value, instr.generates_cc); |
| 53 | SetRegister(bb, instr.gpr0, value); | 120 | SetRegister(bb, instr.gpr0, move(value)); |
| 121 | break; | ||
| 122 | } | ||
| 123 | case OpCode::Id::SHF_RIGHT_R: | ||
| 124 | case OpCode::Id::SHF_RIGHT_IMM: | ||
| 125 | case OpCode::Id::SHF_LEFT_R: | ||
| 126 | case OpCode::Id::SHF_LEFT_IMM: { | ||
| 127 | UNIMPLEMENTED_IF(instr.generates_cc); | ||
| 128 | UNIMPLEMENTED_IF_MSG(instr.shf.xmode != ShfXmode::None, "xmode={}", | ||
| 129 | static_cast<int>(instr.shf.xmode.Value())); | ||
| 130 | |||
| 131 | if (instr.is_b_imm) { | ||
| 132 | op_b = Immediate(static_cast<u32>(instr.shf.immediate)); | ||
| 133 | } | ||
| 134 | const s32 size = instr.shf.type == ShfType::Bits32 ? 32 : 64; | ||
| 135 | Node shift = instr.shf.wrap ? WrapShift(move(op_b), size) : ClampShift(move(op_b), size); | ||
| 136 | |||
| 137 | Node negated_shift = Operation(OperationCode::INegate, shift); | ||
| 138 | Node low_shift = Operation(OperationCode::IAdd, move(negated_shift), Immediate(32)); | ||
| 139 | |||
| 140 | const bool is_right = opid == OpCode::Id::SHF_RIGHT_R || opid == OpCode::Id::SHF_RIGHT_IMM; | ||
| 141 | Node value = (is_right ? ShiftRight : ShiftLeft)( | ||
| 142 | move(op_a), GetRegister(instr.gpr39), move(shift), move(low_shift), instr.shf.type); | ||
| 143 | |||
| 144 | SetRegister(bb, instr.gpr0, move(value)); | ||
| 54 | break; | 145 | break; |
| 55 | } | 146 | } |
| 56 | default: | 147 | default: |