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

+13 -8
View File
@@ -695,7 +695,7 @@ void TestCompleteWaveReduction() {
Shift, FetchInactive, BoundControl, Dpp8, MoveExec, UpdateExec,
Previous, DppSource, CrossExec, CrossRow, CrossSelectorLow,
CrossSelectorHigh, CrossFetch, CrossBound, CrossSource, FinalExec,
Endpoint, EndpointSource, CrossBlock, WrongOperation
Endpoint, EndpointSource, CrossBlock, WrongOperation, Or
};
for (const auto test : {Case::Masked, Case::ScalarExec, Case::Wave32,
Case::Wave32Rows, Case::Wave32Maximum, Case::RowMask, Case::BankMask,
@@ -704,7 +704,7 @@ void TestCompleteWaveReduction() {
Case::CrossExec, Case::CrossRow, Case::CrossSelectorLow,
Case::CrossSelectorHigh, Case::CrossFetch, Case::CrossBound,
Case::CrossSource, Case::FinalExec, Case::Endpoint, Case::EndpointSource,
Case::CrossBlock, Case::WrongOperation}) {
Case::CrossBlock, Case::WrongOperation, Case::Or}) {
Fixture fixture(test == Case::CrossBlock ? 2 : 1);
const auto source = fixture.Emit(ValueOpcode::LaneId);
const auto mask = fixture.Emit(ValueOpcode::ULessThan32, {source, Value(19u)});
@@ -720,14 +720,20 @@ void TestCompleteWaveReduction() {
enabled = fixture.Emit(ValueOpcode::INotEqual32,
{fixture.Emit(ValueOpcode::BitwiseAnd32, {shifted, Value(1u)}), Value(0u)});
}
// A UMax scan seeds lanes outside EXEC with zero.
// UMax and OR scans seed lanes outside EXEC with zero.
const bool maximum = test == Case::Wave32Maximum;
const uint32_t neutral = maximum ? 0u : UINT32_MAX;
const bool bitwise_or = test == Case::Or;
const uint32_t neutral = maximum || bitwise_or ? 0u : UINT32_MAX;
const auto seed = fixture.Emit(ValueOpcode::SelectU32, {mask, source, Value(neutral)});
auto prefix = fixture.Emit(ValueOpcode::SelectU32, {enabled, seed, source});
Value preserved;
auto operation = maximum ? ValueOpcode::UMax32 : ValueOpcode::UMin32;
if (test == Case::WrongOperation) operation = ValueOpcode::BitwiseOr32;
auto reduction_opcode = maximum ? ValueOpcode::SubgroupUMaxU32 : ValueOpcode::SubgroupUMinU32;
if (bitwise_or) {
operation = ValueOpcode::BitwiseOr32;
reduction_opcode = ValueOpcode::SubgroupOrU32;
}
if (test == Case::WrongOperation) operation = ValueOpcode::IAdd32;
for (const uint32_t shift : {1u, 2u, 4u, 8u}) {
DppMoveFlags flags{.control = 0x110u + shift};
if (shift == 2) {
@@ -787,13 +793,12 @@ void TestCompleteWaveReduction() {
const uint32_t wave_size = test == Case::Wave32 || rows ? 32u : 64u;
ConstantPropagationPass(fixture.program.blocks, wave_size);
const auto stats = EliminateReadLane(fixture.program, wave_size);
const bool matches = test == Case::Masked || rows;
const bool matches = test == Case::Masked || rows || bitwise_or;
Check(stats.rewritten_reductions == (matches ? 1u : 0u) && stats.rewritten_reads == 0,
("wave reduction proof failed case " + std::to_string(static_cast<unsigned>(test))).c_str());
if (matches) {
const auto *reduction = use.Instruction()->Arg(0).ResolveInstruction();
Check(reduction->GetOpcode() ==
(maximum ? ValueOpcode::SubgroupUMaxU32 : ValueOpcode::SubgroupUMinU32) &&
Check(reduction->GetOpcode() == reduction_opcode &&
reduction->Arg(0).Resolve() == seed.Resolve(),
"wave reduction changed the neutral-masked input");
RemoveIdentities(fixture.program);