diff options
| author | 2020-02-01 21:18:36 -0300 | |
|---|---|---|
| committer | 2020-02-01 21:20:02 -0300 | |
| commit | 729ca120e379b67f99663e1fde57285e4cbefc4c (patch) | |
| tree | 6bf94bcd31a703c17036a9c27364dff7b2969c72 /src | |
| parent | shader/shift: Implement SHF_LEFT_{IMM,R} (diff) | |
| download | yuzu-729ca120e379b67f99663e1fde57285e4cbefc4c.tar.gz yuzu-729ca120e379b67f99663e1fde57285e4cbefc4c.tar.xz yuzu-729ca120e379b67f99663e1fde57285e4cbefc4c.zip | |
shader/shift: Implement SHIFT_RIGHT_{IMM,R}
Shifts a pair of registers to the right and returns the low register.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/shader/decode/shift.cpp | 84 |
1 files changed, 58 insertions, 26 deletions
diff --git a/src/video_core/shader/decode/shift.cpp b/src/video_core/shader/decode/shift.cpp index 98e71b5f2..3b391d3e6 100644 --- a/src/video_core/shader/decode/shift.cpp +++ b/src/video_core/shader/decode/shift.cpp | |||
| @@ -18,10 +18,14 @@ using Tegra::Shader::ShfXmode; | |||
| 18 | 18 | ||
| 19 | namespace { | 19 | namespace { |
| 20 | 20 | ||
| 21 | Node IsFull(Node shift) { | ||
| 22 | return Operation(OperationCode::LogicalIEqual, move(shift), Immediate(32)); | ||
| 23 | } | ||
| 24 | |||
| 21 | Node Shift(OperationCode opcode, Node value, Node shift) { | 25 | Node Shift(OperationCode opcode, Node value, Node shift) { |
| 22 | Node is_full = Operation(OperationCode::LogicalIEqual, shift, Immediate(32)); | 26 | Node is_full = Operation(OperationCode::LogicalIEqual, shift, Immediate(32)); |
| 23 | Node shifted = Operation(opcode, move(value), move(shift)); | 27 | Node shifted = Operation(opcode, move(value), shift); |
| 24 | return Operation(OperationCode::Select, move(is_full), Immediate(0), move(shifted)); | 28 | return Operation(OperationCode::Select, IsFull(move(shift)), Immediate(0), move(shifted)); |
| 25 | } | 29 | } |
| 26 | 30 | ||
| 27 | Node ClampShift(Node shift, s32 size = 32) { | 31 | Node ClampShift(Node shift, s32 size = 32) { |
| @@ -33,6 +37,52 @@ Node WrapShift(Node shift, s32 size = 32) { | |||
| 33 | return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1)); | 37 | return Operation(OperationCode::UBitwiseAnd, move(shift), Immediate(size - 1)); |
| 34 | } | 38 | } |
| 35 | 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 | |||
| 36 | } // Anonymous namespace | 86 | } // Anonymous namespace |
| 37 | 87 | ||
| 38 | u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { | 88 | u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { |
| @@ -50,7 +100,7 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { | |||
| 50 | } | 100 | } |
| 51 | }(); | 101 | }(); |
| 52 | 102 | ||
| 53 | switch (opcode->get().GetId()) { | 103 | switch (const auto opid = opcode->get().GetId(); opid) { |
| 54 | case OpCode::Id::SHR_C: | 104 | case OpCode::Id::SHR_C: |
| 55 | case OpCode::Id::SHR_R: | 105 | case OpCode::Id::SHR_R: |
| 56 | case OpCode::Id::SHR_IMM: { | 106 | case OpCode::Id::SHR_IMM: { |
| @@ -70,6 +120,8 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { | |||
| 70 | SetRegister(bb, instr.gpr0, move(value)); | 120 | SetRegister(bb, instr.gpr0, move(value)); |
| 71 | break; | 121 | break; |
| 72 | } | 122 | } |
| 123 | case OpCode::Id::SHF_RIGHT_R: | ||
| 124 | case OpCode::Id::SHF_RIGHT_IMM: | ||
| 73 | case OpCode::Id::SHF_LEFT_R: | 125 | case OpCode::Id::SHF_LEFT_R: |
| 74 | case OpCode::Id::SHF_LEFT_IMM: { | 126 | case OpCode::Id::SHF_LEFT_IMM: { |
| 75 | UNIMPLEMENTED_IF(instr.generates_cc); | 127 | UNIMPLEMENTED_IF(instr.generates_cc); |
| @@ -85,29 +137,9 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) { | |||
| 85 | Node negated_shift = Operation(OperationCode::INegate, shift); | 137 | Node negated_shift = Operation(OperationCode::INegate, shift); |
| 86 | Node low_shift = Operation(OperationCode::IAdd, move(negated_shift), Immediate(32)); | 138 | Node low_shift = Operation(OperationCode::IAdd, move(negated_shift), Immediate(32)); |
| 87 | 139 | ||
| 88 | Node low = move(op_a); | 140 | const bool is_right = opid == OpCode::Id::SHF_RIGHT_R || opid == OpCode::Id::SHF_RIGHT_IMM; |
| 89 | Node high = GetRegister(instr.gpr39); | 141 | Node value = (is_right ? ShiftRight : ShiftLeft)( |
| 90 | Node value; | 142 | move(op_a), GetRegister(instr.gpr39), move(shift), move(low_shift), instr.shf.type); |
| 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 | 143 | ||
| 112 | SetRegister(bb, instr.gpr0, move(value)); | 144 | SetRegister(bb, instr.gpr0, move(value)); |
| 113 | break; | 145 | break; |