fix(shader): treat an image read as a use that only reads where its exec is active

An ImageRead carries a trailing exec argument like the buffer loads, but it
was in neither the read-only-where-active list nor the lane-local list, so a
masked select feeding its address was kept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
xXPBSXxandClaude Sonnet 5.5 authored and Dean Galvin committed 2026-10-11 17:55:54 +13:00
1 parent 98f99d3883
commit 83f8c193c9
2 files changed
+10 -2

No files matched your search

@@ -636,6 +636,13 @@ int main() {
case IrOpcode::LoadBufferU32:
b.keep(b.select(exec, b.emit(opcode, IrType::U32, {&b.emit(IrOpcode::GetBufferResource, IrType::BufferResource, {}), &written, &b.constant(0u), &b.constant(0u), &active}), old));
break;
case IrOpcode::ImageRead: {
auto& address = b.emit(IrOpcode::MakeImageAddress, IrType::ImageAddress, {&written, &old});
auto& image = b.emit(IrOpcode::GetImageResource, IrType::ImageResource, {});
auto& read = b.emit(opcode, IrType::U32x4, {&image, &address, &active});
b.keep(b.select(exec, b.emit(IrOpcode::CompositeExtractU32x4, IrType::U32, {&read, &b.constant(0u)}), old));
break;
}
default:
b.emit(opcode, IrType::Void, {&b.emit(IrOpcode::CompositeConstructU32x4, IrType::U32x4, {&written, &old, &old, &old}), &active});
break;
@@ -645,11 +652,11 @@ int main() {
};
passed &= run("a store, load or export whose exec implies the write's exec drops the select", [&] {
return guarded(IrOpcode::WriteSharedU32, true, false) && guarded(IrOpcode::LoadBufferU32, true, false) && guarded(IrOpcode::SetAttribute, true, false);
return guarded(IrOpcode::WriteSharedU32, true, false) && guarded(IrOpcode::LoadBufferU32, true, false) && guarded(IrOpcode::ImageRead, true, false) && guarded(IrOpcode::SetAttribute, true, false);
});
passed &= run("a store, load or export under a wider exec keeps the select", [&] {
return !guarded(IrOpcode::WriteSharedU32, false, false) && !guarded(IrOpcode::LoadBufferU32, false, false) && !guarded(IrOpcode::SetAttribute, false, false);
return !guarded(IrOpcode::WriteSharedU32, false, false) && !guarded(IrOpcode::LoadBufferU32, false, false) && !guarded(IrOpcode::ImageRead, false, false) && !guarded(IrOpcode::SetAttribute, false, false);
});
passed &= run("a value used as a store's exec keeps the select", [&] {
@@ -204,6 +204,7 @@ bool readsOnlyWhereActive(IrOpcode opcode) {
case IrOpcode::WriteSharedU32x3:
case IrOpcode::WriteSharedU32x4:
case IrOpcode::SetAttribute:
case IrOpcode::ImageRead:
return true;
default:
return false;