shader: Implement SHF
This commit is contained in:
		| @@ -78,6 +78,7 @@ add_library(shader_recompiler STATIC | ||||
|     frontend/maxwell/translate/impl/integer_add_three_input.cpp | ||||
|     frontend/maxwell/translate/impl/integer_compare.cpp | ||||
|     frontend/maxwell/translate/impl/integer_compare_and_set.cpp | ||||
|     frontend/maxwell/translate/impl/integer_funnel_shift.cpp | ||||
|     frontend/maxwell/translate/impl/integer_minimum_maximum.cpp | ||||
|     frontend/maxwell/translate/impl/integer_popcount.cpp | ||||
|     frontend/maxwell/translate/impl/integer_scaled_add.cpp | ||||
|   | ||||
| @@ -232,9 +232,11 @@ Id EmitINeg32(EmitContext& ctx, Id value); | ||||
| Id EmitINeg64(EmitContext& ctx, Id value); | ||||
| Id EmitIAbs32(EmitContext& ctx, Id value); | ||||
| Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift); | ||||
| Id EmitShiftRightLogical32(EmitContext& ctx, Id a, Id b); | ||||
| Id EmitShiftRightLogical64(EmitContext& ctx, Id a, Id b); | ||||
| Id EmitShiftRightArithmetic32(EmitContext& ctx, Id a, Id b); | ||||
| Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift); | ||||
| Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift); | ||||
| Id EmitShiftRightLogical64(EmitContext& ctx, Id base, Id shift); | ||||
| Id EmitShiftRightArithmetic32(EmitContext& ctx, Id base, Id shift); | ||||
| Id EmitShiftRightArithmetic64(EmitContext& ctx, Id base, Id shift); | ||||
| Id EmitBitwiseAnd32(EmitContext& ctx, Id a, Id b); | ||||
| Id EmitBitwiseOr32(EmitContext& ctx, Id a, Id b); | ||||
| Id EmitBitwiseXor32(EmitContext& ctx, Id a, Id b); | ||||
|   | ||||
| @@ -74,16 +74,24 @@ Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) { | ||||
|     return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift); | ||||
| } | ||||
|  | ||||
| Id EmitShiftRightLogical32(EmitContext& ctx, Id a, Id b) { | ||||
|     return ctx.OpShiftRightLogical(ctx.U32[1], a, b); | ||||
| Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift) { | ||||
|     return ctx.OpShiftLeftLogical(ctx.U64, base, shift); | ||||
| } | ||||
|  | ||||
| Id EmitShiftRightLogical64(EmitContext& ctx, Id a, Id b) { | ||||
|     return ctx.OpShiftRightLogical(ctx.U64, a, b); | ||||
| Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift) { | ||||
|     return ctx.OpShiftRightLogical(ctx.U32[1], base, shift); | ||||
| } | ||||
|  | ||||
| Id EmitShiftRightArithmetic32(EmitContext& ctx, Id a, Id b) { | ||||
|     return ctx.OpShiftRightArithmetic(ctx.U32[1], a, b); | ||||
| Id EmitShiftRightLogical64(EmitContext& ctx, Id base, Id shift) { | ||||
|     return ctx.OpShiftRightLogical(ctx.U64, base, shift); | ||||
| } | ||||
|  | ||||
| Id EmitShiftRightArithmetic32(EmitContext& ctx, Id base, Id shift) { | ||||
|     return ctx.OpShiftRightArithmetic(ctx.U32[1], base, shift); | ||||
| } | ||||
|  | ||||
| Id EmitShiftRightArithmetic64(EmitContext& ctx, Id base, Id shift) { | ||||
|     return ctx.OpShiftRightArithmetic(ctx.U64, base, shift); | ||||
| } | ||||
|  | ||||
| Id EmitBitwiseAnd32(EmitContext& ctx, Id a, Id b) { | ||||
|   | ||||
| @@ -813,8 +813,15 @@ U32 IREmitter::IAbs(const U32& value) { | ||||
|     return Inst<U32>(Opcode::IAbs32, value); | ||||
| } | ||||
|  | ||||
| U32 IREmitter::ShiftLeftLogical(const U32& base, const U32& shift) { | ||||
|     return Inst<U32>(Opcode::ShiftLeftLogical32, base, shift); | ||||
| U32U64 IREmitter::ShiftLeftLogical(const U32U64& base, const U32& shift) { | ||||
|     switch (base.Type()) { | ||||
|     case Type::U32: | ||||
|         return Inst<U32>(Opcode::ShiftLeftLogical32, base, shift); | ||||
|     case Type::U64: | ||||
|         return Inst<U64>(Opcode::ShiftLeftLogical64, base, shift); | ||||
|     default: | ||||
|         ThrowInvalidType(base.Type()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| U32U64 IREmitter::ShiftRightLogical(const U32U64& base, const U32& shift) { | ||||
| @@ -828,8 +835,15 @@ U32U64 IREmitter::ShiftRightLogical(const U32U64& base, const U32& shift) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| U32 IREmitter::ShiftRightArithmetic(const U32& base, const U32& shift) { | ||||
|     return Inst<U32>(Opcode::ShiftRightArithmetic32, base, shift); | ||||
| U32U64 IREmitter::ShiftRightArithmetic(const U32U64& base, const U32& shift) { | ||||
|     switch (base.Type()) { | ||||
|     case Type::U32: | ||||
|         return Inst<U32>(Opcode::ShiftRightArithmetic32, base, shift); | ||||
|     case Type::U64: | ||||
|         return Inst<U64>(Opcode::ShiftRightArithmetic64, base, shift); | ||||
|     default: | ||||
|         ThrowInvalidType(base.Type()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| U32 IREmitter::BitwiseAnd(const U32& a, const U32& b) { | ||||
|   | ||||
| @@ -150,9 +150,9 @@ public: | ||||
|     [[nodiscard]] U32 IMul(const U32& a, const U32& b); | ||||
|     [[nodiscard]] U32U64 INeg(const U32U64& value); | ||||
|     [[nodiscard]] U32 IAbs(const U32& value); | ||||
|     [[nodiscard]] U32 ShiftLeftLogical(const U32& base, const U32& shift); | ||||
|     [[nodiscard]] U32U64 ShiftLeftLogical(const U32U64& base, const U32& shift); | ||||
|     [[nodiscard]] U32U64 ShiftRightLogical(const U32U64& base, const U32& shift); | ||||
|     [[nodiscard]] U32 ShiftRightArithmetic(const U32& base, const U32& shift); | ||||
|     [[nodiscard]] U32U64 ShiftRightArithmetic(const U32U64& base, const U32& shift); | ||||
|     [[nodiscard]] U32 BitwiseAnd(const U32& a, const U32& b); | ||||
|     [[nodiscard]] U32 BitwiseOr(const U32& a, const U32& b); | ||||
|     [[nodiscard]] U32 BitwiseXor(const U32& a, const U32& b); | ||||
|   | ||||
| @@ -236,9 +236,11 @@ OPCODE(INeg32,                                              U32,            U32, | ||||
| OPCODE(INeg64,                                              U64,            U64,                                                            ) | ||||
| OPCODE(IAbs32,                                              U32,            U32,                                                            ) | ||||
| OPCODE(ShiftLeftLogical32,                                  U32,            U32,            U32,                                            ) | ||||
| OPCODE(ShiftLeftLogical64,                                  U64,            U64,            U32,                                            ) | ||||
| OPCODE(ShiftRightLogical32,                                 U32,            U32,            U32,                                            ) | ||||
| OPCODE(ShiftRightLogical64,                                 U64,            U64,            U32,                                            ) | ||||
| OPCODE(ShiftRightArithmetic32,                              U32,            U32,            U32,                                            ) | ||||
| OPCODE(ShiftRightArithmetic64,                              U64,            U64,            U32,                                            ) | ||||
| OPCODE(BitwiseAnd32,                                        U32,            U32,            U32,                                            ) | ||||
| OPCODE(BitwiseOr32,                                         U32,            U32,            U32,                                            ) | ||||
| OPCODE(BitwiseXor32,                                        U32,            U32,            U32,                                            ) | ||||
|   | ||||
| @@ -0,0 +1,77 @@ | ||||
| // Copyright 2021 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_types.h" | ||||
| #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||||
|  | ||||
| namespace Shader::Maxwell { | ||||
| namespace { | ||||
| enum class MaxShift : u64 { | ||||
|     U32, | ||||
|     Undefined, | ||||
|     U64, | ||||
|     S64, | ||||
| }; | ||||
|  | ||||
| IR::U64 PackedShift(IR::IREmitter& ir, const IR::U64& packed_int, const IR::U32& safe_shift, | ||||
|                     bool right_shift, bool is_signed) { | ||||
|     if (!right_shift) { | ||||
|         return ir.ShiftLeftLogical(packed_int, safe_shift); | ||||
|     } | ||||
|     if (is_signed) { | ||||
|         return ir.ShiftRightArithmetic(packed_int, safe_shift); | ||||
|     } | ||||
|     return ir.ShiftRightLogical(packed_int, safe_shift); | ||||
| } | ||||
|  | ||||
| void SHF(TranslatorVisitor& v, u64 insn, const IR::U32& shift, const IR::U32& high_bits, | ||||
|          bool right_shift) { | ||||
|     union { | ||||
|         u64 insn; | ||||
|         BitField<0, 8, IR::Reg> dest_reg; | ||||
|         BitField<0, 8, IR::Reg> lo_bits_reg; | ||||
|         BitField<37, 2, MaxShift> max_shift; | ||||
|         BitField<48, 2, u64> x_mode; | ||||
|         BitField<50, 1, u64> wrap; | ||||
|     } const shf{insn}; | ||||
|     if (shf.x_mode != 0) { | ||||
|         throw NotImplementedException("SHF X Mode"); | ||||
|     } | ||||
|     if (shf.max_shift == MaxShift::Undefined) { | ||||
|         throw NotImplementedException("SHF Use of undefined MaxShift value"); | ||||
|     } | ||||
|     const IR::U32 low_bits{v.X(shf.lo_bits_reg)}; | ||||
|     const IR::U64 packed_int{v.ir.PackUint2x32(v.ir.CompositeConstruct(low_bits, high_bits))}; | ||||
|     const IR::U32 max_shift{shf.max_shift == MaxShift::U32 ? v.ir.Imm32(32) : v.ir.Imm32(63)}; | ||||
|     const IR::U32 safe_shift{shf.wrap != 0 | ||||
|                                  ? v.ir.BitwiseAnd(shift, v.ir.ISub(max_shift, v.ir.Imm32(1))) | ||||
|                                  : v.ir.UMin(shift, max_shift)}; | ||||
|  | ||||
|     const bool is_signed{shf.max_shift == MaxShift::S64}; | ||||
|     const IR::U64 shifted_value{PackedShift(v.ir, packed_int, safe_shift, right_shift, is_signed)}; | ||||
|     const IR::Value unpacked_value{v.ir.UnpackUint2x32(shifted_value)}; | ||||
|  | ||||
|     const IR::U32 result{v.ir.CompositeExtract(unpacked_value, right_shift ? 0 : 1)}; | ||||
|     v.X(shf.dest_reg, result); | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
| void TranslatorVisitor::SHF_l_reg(u64 insn) { | ||||
|     SHF(*this, insn, GetReg20(insn), GetReg39(insn), false); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHF_l_imm(u64 insn) { | ||||
|     SHF(*this, insn, GetImm20(insn), GetReg39(insn), false); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHF_r_reg(u64 insn) { | ||||
|     SHF(*this, insn, GetReg20(insn), GetReg39(insn), true); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHF_r_imm(u64 insn) { | ||||
|     SHF(*this, insn, GetImm20(insn), GetReg39(insn), true); | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Maxwell | ||||
| @@ -553,22 +553,6 @@ void TranslatorVisitor::SETLMEMBASE(u64) { | ||||
|     ThrowNotImplemented(Opcode::SETLMEMBASE); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHF_l_reg(u64) { | ||||
|     ThrowNotImplemented(Opcode::SHF_l_reg); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHF_l_imm(u64) { | ||||
|     ThrowNotImplemented(Opcode::SHF_l_imm); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHF_r_reg(u64) { | ||||
|     ThrowNotImplemented(Opcode::SHF_r_reg); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHF_r_imm(u64) { | ||||
|     ThrowNotImplemented(Opcode::SHF_r_imm); | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::SHFL(u64) { | ||||
|     ThrowNotImplemented(Opcode::SHFL); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user