diff options
| author | 2020-02-01 02:57:01 -0300 | |
|---|---|---|
| committer | 2020-02-01 21:19:44 -0300 | |
| commit | 017474c3f89e5afcb3ffdb9fac3e412c40986092 (patch) | |
| tree | 4164fe82d9d5ee8abb9ac3ae7d7875d163195c9b /src/video_core/shader/decode | |
| 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/video_core/shader/decode')
| -rw-r--r-- | src/video_core/shader/decode/shift.cpp | 79 |
1 files changed, 69 insertions, 10 deletions
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: |