[shader_recompiler/Maxwell] Rewrite ISBERD and fix potential downsides #192

Closed
SDK-Chan wants to merge 3 commits from rewrite-ISBERD into master

View file

@ -10,6 +10,7 @@
namespace Shader::Maxwell { namespace Shader::Maxwell {
namespace { namespace {
enum class Mode : u64 { enum class Mode : u64 {
Default, Default,
Patch, Patch,
@ -39,66 +40,82 @@ void TranslatorVisitor::ISBERD(u64 insn) {
BitField<47, 2, Shift> shift; BitField<47, 2, Shift> shift;
} const isberd{insn}; } const isberd{insn};
if (isberd.skew != 0) { bool is_only_skew_op = true;
IR::U32 current_lane_id{ir.LaneId()}; bool no_other_op = true;
IR::U32 result{ir.IAdd(X(isberd.src_reg), current_lane_id)}; auto apply_shift = [&](IR::U32 result) -> IR::U32 {
X(isberd.dest_reg, result); switch (isberd.shift.Value()) {
} case Shift::U16:
case Shift::B32:
return ir.ShiftLeftLogical(result, ir.Imm32(1));
default:
return result;
}
};
if (isberd.o != 0) { if (isberd.o != 0) {
IR::U32 address{}; IR::U32 address{};
IR::F32 result{};
if (isberd.src_reg_num == 0xFF) { if (isberd.src_reg_num == 0xFF) {
address = ir.Imm32(isberd.imm); address = ir.Imm32(isberd.imm);
result = ir.GetAttributeIndexed(address);
} else { } else {
IR::U32 offset = ir.Imm32(isberd.imm); IR::U32 offset = ir.Imm32(isberd.imm);
address = ir.IAdd(X(isberd.src_reg), offset); address = ir.IAdd(X(isberd.src_reg), offset);
result = ir.GetAttributeIndexed(address); if (isberd.skew != 0) {
address = ir.IAdd(address, ir.LaneId());
}
} }
X(isberd.dest_reg, ir.BitCast<IR::U32>(result));
IR::U32 result = ir.BitCast<IR::U32>(ir.GetAttributeIndexed(address));
if (isberd.shift != Shift::Default) {
result = apply_shift(result);
}
is_only_skew_op = false;
no_other_op = false;
X(isberd.dest_reg, result);
} }
if (isberd.mode != Mode::Default) {
IR::F32 result{}; else if (isberd.mode != Mode::Default) {
IR::U32 index{}; IR::U32 index{};
if (isberd.src_reg_num == 0xFF) { if (isberd.src_reg_num == 0xFF) {
index = ir.Imm32(isberd.imm); index = ir.Imm32(isberd.imm);
} else { } else {
index = ir.IAdd(X(isberd.src_reg), ir.Imm32(isberd.imm)); index = ir.IAdd(X(isberd.src_reg), ir.Imm32(isberd.imm));
if (isberd.skew != 0) {
index = ir.IAdd(index, ir.LaneId());
}
} }
switch (static_cast<u64>(isberd.mode.Value())) { IR::F32 result_f32{};
case static_cast<u64>(Mode::Patch): switch (isberd.mode.Value()) {
result = ir.GetPatch(index.Patch()); case Mode::Patch:
result_f32 = ir.GetPatch(index.Patch());
break; break;
case static_cast<u64>(Mode::Prim): case Mode::Prim:
result = ir.GetAttribute(index.Attribute()); result_f32 = ir.GetAttribute(index.Attribute());
break; break;
case static_cast<u64>(Mode::Attr): case Mode::Attr:
result = ir.GetAttributeIndexed(index); result_f32 = ir.GetAttributeIndexed(index);
break;
default:
break; break;
} }
X(isberd.dest_reg, ir.BitCast<IR::U32>(result));
} IR::U32 result_u32 = ir.BitCast<IR::U32>(result_f32);
if (isberd.shift != Shift::Default) { if (isberd.shift != Shift::Default) {
IR::U32 result{}; result_u32 = apply_shift(result_u32);
switch (static_cast<u64>(isberd.shift.Value())) {
case static_cast<u64>(Shift::U16):
result = ir.ShiftLeftLogical(result, static_cast<IR::U32>(ir.Imm16(1)));
break;
case static_cast<u64>(Shift::B32):
result = ir.ShiftLeftLogical(result, ir.Imm32(1));
break;
} }
X(isberd.dest_reg, result);
is_only_skew_op = false;
no_other_op = false;
X(isberd.dest_reg, result_u32);
} }
//LOG_DEBUG(Shader, "(STUBBED) called {}", insn);
if (isberd.src_reg_num == 0xFF) { if (isberd.skew != 0 && is_only_skew_op) {
IR::U32 src_imm{ir.Imm32(static_cast<u32>(isberd.imm))}; IR::U32 result = ir.IAdd(X(isberd.src_reg), ir.LaneId());
IR::U32 result{ir.IAdd(X(isberd.src_reg), src_imm)};
X(isberd.dest_reg, result); X(isberd.dest_reg, result);
} else { } else if (no_other_op) {
X(isberd.dest_reg, X(isberd.src_reg)); X(isberd.dest_reg, X(isberd.src_reg));
} }
} }
} // namespace Shader::Maxwell } // namespace Shader::Maxwell