shader: Implement SHF
This commit is contained in:
parent
5465cb1561
commit
924f0a9149
|
@ -78,6 +78,7 @@ add_library(shader_recompiler STATIC
|
||||||
frontend/maxwell/translate/impl/integer_add_three_input.cpp
|
frontend/maxwell/translate/impl/integer_add_three_input.cpp
|
||||||
frontend/maxwell/translate/impl/integer_compare.cpp
|
frontend/maxwell/translate/impl/integer_compare.cpp
|
||||||
frontend/maxwell/translate/impl/integer_compare_and_set.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_minimum_maximum.cpp
|
||||||
frontend/maxwell/translate/impl/integer_popcount.cpp
|
frontend/maxwell/translate/impl/integer_popcount.cpp
|
||||||
frontend/maxwell/translate/impl/integer_scaled_add.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 EmitINeg64(EmitContext& ctx, Id value);
|
||||||
Id EmitIAbs32(EmitContext& ctx, Id value);
|
Id EmitIAbs32(EmitContext& ctx, Id value);
|
||||||
Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift);
|
Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift);
|
||||||
Id EmitShiftRightLogical32(EmitContext& ctx, Id a, Id b);
|
Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift);
|
||||||
Id EmitShiftRightLogical64(EmitContext& ctx, Id a, Id b);
|
Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift);
|
||||||
Id EmitShiftRightArithmetic32(EmitContext& ctx, Id a, Id b);
|
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 EmitBitwiseAnd32(EmitContext& ctx, Id a, Id b);
|
||||||
Id EmitBitwiseOr32(EmitContext& ctx, Id a, Id b);
|
Id EmitBitwiseOr32(EmitContext& ctx, Id a, Id b);
|
||||||
Id EmitBitwiseXor32(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);
|
return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitShiftRightLogical32(EmitContext& ctx, Id a, Id b) {
|
Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift) {
|
||||||
return ctx.OpShiftRightLogical(ctx.U32[1], a, b);
|
return ctx.OpShiftLeftLogical(ctx.U64, base, shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitShiftRightLogical64(EmitContext& ctx, Id a, Id b) {
|
Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift) {
|
||||||
return ctx.OpShiftRightLogical(ctx.U64, a, b);
|
return ctx.OpShiftRightLogical(ctx.U32[1], base, shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitShiftRightArithmetic32(EmitContext& ctx, Id a, Id b) {
|
Id EmitShiftRightLogical64(EmitContext& ctx, Id base, Id shift) {
|
||||||
return ctx.OpShiftRightArithmetic(ctx.U32[1], a, b);
|
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) {
|
Id EmitBitwiseAnd32(EmitContext& ctx, Id a, Id b) {
|
||||||
|
|
|
@ -813,8 +813,15 @@ U32 IREmitter::IAbs(const U32& value) {
|
||||||
return Inst<U32>(Opcode::IAbs32, value);
|
return Inst<U32>(Opcode::IAbs32, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 IREmitter::ShiftLeftLogical(const U32& base, const U32& shift) {
|
U32U64 IREmitter::ShiftLeftLogical(const U32U64& base, const U32& shift) {
|
||||||
|
switch (base.Type()) {
|
||||||
|
case Type::U32:
|
||||||
return Inst<U32>(Opcode::ShiftLeftLogical32, base, shift);
|
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) {
|
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) {
|
U32U64 IREmitter::ShiftRightArithmetic(const U32U64& base, const U32& shift) {
|
||||||
|
switch (base.Type()) {
|
||||||
|
case Type::U32:
|
||||||
return Inst<U32>(Opcode::ShiftRightArithmetic32, base, shift);
|
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) {
|
U32 IREmitter::BitwiseAnd(const U32& a, const U32& b) {
|
||||||
|
|
|
@ -150,9 +150,9 @@ public:
|
||||||
[[nodiscard]] U32 IMul(const U32& a, const U32& b);
|
[[nodiscard]] U32 IMul(const U32& a, const U32& b);
|
||||||
[[nodiscard]] U32U64 INeg(const U32U64& value);
|
[[nodiscard]] U32U64 INeg(const U32U64& value);
|
||||||
[[nodiscard]] U32 IAbs(const U32& 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]] 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 BitwiseAnd(const U32& a, const U32& b);
|
||||||
[[nodiscard]] U32 BitwiseOr(const U32& a, const U32& b);
|
[[nodiscard]] U32 BitwiseOr(const U32& a, const U32& b);
|
||||||
[[nodiscard]] U32 BitwiseXor(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(INeg64, U64, U64, )
|
||||||
OPCODE(IAbs32, U32, U32, )
|
OPCODE(IAbs32, U32, U32, )
|
||||||
OPCODE(ShiftLeftLogical32, U32, U32, U32, )
|
OPCODE(ShiftLeftLogical32, U32, U32, U32, )
|
||||||
|
OPCODE(ShiftLeftLogical64, U64, U64, U32, )
|
||||||
OPCODE(ShiftRightLogical32, U32, U32, U32, )
|
OPCODE(ShiftRightLogical32, U32, U32, U32, )
|
||||||
OPCODE(ShiftRightLogical64, U64, U64, U32, )
|
OPCODE(ShiftRightLogical64, U64, U64, U32, )
|
||||||
OPCODE(ShiftRightArithmetic32, U32, U32, U32, )
|
OPCODE(ShiftRightArithmetic32, U32, U32, U32, )
|
||||||
|
OPCODE(ShiftRightArithmetic64, U64, U64, U32, )
|
||||||
OPCODE(BitwiseAnd32, U32, U32, U32, )
|
OPCODE(BitwiseAnd32, U32, U32, U32, )
|
||||||
OPCODE(BitwiseOr32, U32, U32, U32, )
|
OPCODE(BitwiseOr32, U32, U32, U32, )
|
||||||
OPCODE(BitwiseXor32, 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);
|
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) {
|
void TranslatorVisitor::SHFL(u64) {
|
||||||
ThrowNotImplemented(Opcode::SHFL);
|
ThrowNotImplemented(Opcode::SHFL);
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue