shader: lower whole-wave OR scans to subgroup reductions

This commit is contained in:
Artyom Zabroda authored and nmzik committed 2026-10-30 04:31:24 +01:00
1 parent eb3cb47296
commit 0c2546e850
8 files changed
+80 -41

No files matched your search

@@ -224,6 +224,7 @@ VALUE_OPCODE(ReadFirstLane, U32, U32, U1)
VALUE_OPCODE(ReadLane, U32, U32, U32)
VALUE_OPCODE(SubgroupUMinU32, U32, U32)
VALUE_OPCODE(SubgroupUMaxU32, U32, U32)
VALUE_OPCODE(SubgroupOrU32, U32, U32)
VALUE_OPCODE(WriteLane, U32, U32, U32, U32)
VALUE_OPCODE(Permlane16U32, U32, U32, U32, U32, U1, U32)
VALUE_OPCODE(PermuteU32, U32, U32, U32, U1)
@@ -1,7 +1,7 @@
#include "graphics/shader/recompiler/ir/passes/ReadLaneElimination.h"
#include <algorithm>
#include <optional>
#include <queue>
#include <unordered_map>
@@ -186,6 +186,16 @@ private:
ValueOpcode operation;
};
// The subgroup reduction that replaces a proven whole-wave scan of operation.
std::optional<ValueOpcode> WaveReduction(ValueOpcode operation) {
switch (operation) {
case ValueOpcode::UMin32: return ValueOpcode::SubgroupUMinU32;
case ValueOpcode::UMax32: return ValueOpcode::SubgroupUMaxU32;
case ValueOpcode::BitwiseOr32: return ValueOpcode::SubgroupOrU32;
default: return std::nullopt;
}
}
} // namespace
ReadLaneStats EliminateReadLane(Program& program, uint32_t wave_size) {
@@ -197,15 +207,12 @@ ReadLaneStats EliminateReadLane(Program& program, uint32_t wave_size) {
for (auto* block: program.blocks) {
for (auto& inst: *block) {
const auto opcode = inst.GetOpcode();
if (opcode == ValueOpcode::UMin32 || opcode == ValueOpcode::UMax32) {
if (const auto reduce = WaveReduction(opcode)) {
const auto seed = WaveReductionMatcher(block, opcode).Match(inst, wave_size);
if (!seed.IsEmpty()) {
const auto position = std::find_if(block->begin(), block->end(),
[&](const Inst& candidate) { return &candidate == &inst; });
const auto reduce = opcode == ValueOpcode::UMin32
? ValueOpcode::SubgroupUMinU32
: ValueOpcode::SubgroupUMaxU32;
auto& reduction = *block->PrependNewInst(position, reduce, {seed});
auto& reduction = *block->PrependNewInst(position, *reduce, {seed});
inst.ReplaceUsesWith(Value(&reduction));
stats.rewritten_reductions++;
}
@@ -524,7 +524,8 @@ void Visit(Program& program, ShaderStageInputInfo input_info, InputUsage& inputs
case ValueOpcode::Ballot: info.subgroup_ballot = true; break;
case ValueOpcode::LiveMask: info.subgroup_ballot = info.helper_invocation = true; break;
case ValueOpcode::SubgroupUMinU32:
case ValueOpcode::SubgroupUMaxU32: info.subgroup_arithmetic = true; break;
case ValueOpcode::SubgroupUMaxU32:
case ValueOpcode::SubgroupOrU32: info.subgroup_arithmetic = true; break;
case ValueOpcode::DppMoveU32:
case ValueOpcode::ReadFirstLane:
case ValueOpcode::ReadLane: {