forked from suyu/suyu
71 lines
2.7 KiB
C++
71 lines
2.7 KiB
C++
// 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 {
|
|
void SHL(TranslatorVisitor& v, u64 insn, const IR::U32& unsafe_shift) {
|
|
union {
|
|
u64 insn;
|
|
BitField<0, 8, IR::Reg> dest_reg;
|
|
BitField<8, 8, IR::Reg> src_reg_a;
|
|
BitField<39, 1, u64> w;
|
|
BitField<43, 1, u64> x;
|
|
BitField<47, 1, u64> cc;
|
|
} const shl{insn};
|
|
|
|
if (shl.x != 0) {
|
|
throw NotImplementedException("SHL.X");
|
|
}
|
|
if (shl.cc != 0) {
|
|
throw NotImplementedException("SHL.CC");
|
|
}
|
|
const IR::U32 base{v.X(shl.src_reg_a)};
|
|
IR::U32 result;
|
|
if (shl.w != 0) {
|
|
// When .W is set, the shift value is wrapped
|
|
// To emulate this we just have to wrap it ourselves.
|
|
const IR::U32 shift{v.ir.BitwiseAnd(unsafe_shift, v.ir.Imm32(31))};
|
|
result = v.ir.ShiftLeftLogical(base, shift);
|
|
} else {
|
|
// When .W is not set, the shift value is clamped between 0 and 32.
|
|
// To emulate this we have to have in mind the special shift of 32, that evaluates as 0.
|
|
// We can safely evaluate an out of bounds shift according to the SPIR-V specification:
|
|
//
|
|
// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpShiftLeftLogical
|
|
// "Shift is treated as unsigned. The resulting value is undefined if Shift is greater than
|
|
// or equal to the bit width of the components of Base."
|
|
//
|
|
// And on the GLASM specification it is also safe to evaluate out of bounds:
|
|
//
|
|
// https://www.khronos.org/registry/OpenGL/extensions/NV/NV_gpu_program4.txt
|
|
// "The results of a shift operation ("<<") are undefined if the value of the second operand
|
|
// is negative, or greater than or equal to the number of bits in the first operand."
|
|
//
|
|
// Emphasis on undefined results in contrast to undefined behavior.
|
|
//
|
|
const IR::U1 is_safe{v.ir.ILessThan(unsafe_shift, v.ir.Imm32(32), false)};
|
|
const IR::U32 unsafe_result{v.ir.ShiftLeftLogical(base, unsafe_shift)};
|
|
result = v.ir.Select(is_safe, unsafe_result, v.ir.Imm32(0));
|
|
}
|
|
v.X(shl.dest_reg, result);
|
|
}
|
|
} // Anonymous namespace
|
|
|
|
void TranslatorVisitor::SHL_reg(u64) {
|
|
throw NotImplementedException("SHL_reg");
|
|
}
|
|
|
|
void TranslatorVisitor::SHL_cbuf(u64) {
|
|
throw NotImplementedException("SHL_cbuf");
|
|
}
|
|
|
|
void TranslatorVisitor::SHL_imm(u64 insn) {
|
|
SHL(*this, insn, GetImm20(insn));
|
|
}
|
|
|
|
} // namespace Shader::Maxwell
|