From d6d7b8109954308e79b1ebf09b368a1f5ac45c3a Mon Sep 17 00:00:00 2001 From: Mac Date: Mon, 31 Aug 2026 23:40:11 +0530 Subject: [PATCH] shader: emit a real ballot for S_CMP on an exec mask S_CMP_{EQ,LG}_U64 against a mask operand and zero is the idiom for 'are any lanes live'. Treating it as a scalar compare loses the per-lane information, so emit an actual ballot for that shape. --- .../recompiler/frontend/translate/Control.cpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/graphics/shader/recompiler/frontend/translate/Control.cpp b/src/graphics/shader/recompiler/frontend/translate/Control.cpp index e3b89ad46..5bf366242 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Control.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Control.cpp @@ -22,6 +22,33 @@ Decoder::Operand ConditionOperand(Decoder::OperandKind kind) { } // namespace +namespace { +bool IsMaskOperand(const Decoder::Operand& operand) { + return operand.kind == Decoder::OperandKind::VccLo || + operand.kind == Decoder::OperandKind::ExecLo || operand.kind == Decoder::OperandKind::Sgpr; +} + +bool IsZeroConstant(const Decoder::Operand& operand) { + return (operand.kind == Decoder::OperandKind::LiteralConstant || + operand.kind == Decoder::OperandKind::IntegerInlineConstant) && + operand.value == 0; +} +} // namespace + +bool Translator::S_CMP_MASK_ANY(const Decoder::Instruction& inst, bool not_equal) { + if (!IsMaskOperand(inst.src0) || !IsZeroConstant(inst.src1)) { + return false; + } + const auto predicate = ReadMask(inst.src0); + const auto ballot = ir.Emit(IR::ValueOpcode::Ballot, {predicate}); + const auto lo = ir.CompositeExtract(ballot, 0); + const auto hi = ir.CompositeExtract(ballot, 1); + const auto any = + ir.INotEqual(ir.BitwiseOr(lo, hi), IR::U32(IR::Value(0u))); + ir.SetScc(not_equal ? any : ir.LogicalNot(any)); + return true; +} + void Translator::S_SAVEEXEC(const Decoder::Instruction& inst, IR::ValueOpcode operation, bool negate_exec, bool negate_source, bool write_64) { if (write_64) {