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