diff options
| author | 2020-02-01 02:57:01 -0300 | |
|---|---|---|
| committer | 2020-02-01 21:19:44 -0300 | |
| commit | 017474c3f89e5afcb3ffdb9fac3e412c40986092 (patch) | |
| tree | 4164fe82d9d5ee8abb9ac3ae7d7875d163195c9b /src | |
| parent | Merge pull request #3350 from ReinUsesLisp/atom (diff) | |
| download | yuzu-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.h | 20 | ||||
| -rw-r--r-- | src/video_core/shader/decode/shift.cpp | 79 |
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 | ||
| 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..98e71b5f2 100644 --- a/src/video_core/shader/decode/shift.cpp +++ b/src/video_core/shader/decode/shift.cpp | |||
| @@ -10,8 +10,30 @@ | |||
| 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 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 | |||
| 27 | Node 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 | |||
| 32 | Node WrapShift(Node shift, s32 size = 32) { | ||
| 33 | return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1)); | ||
| 34 | } | ||
| 35 | |||
| 36 | } // Anonymous namespace | ||
| 15 | 37 | ||
| 16 | u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { | 38 | u32 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: |