Add `iree-stream-resource-alias-mutable-bindings` flag. (#13965)
This pass option is currently necessary to run some WebGPU programs
correctly, so this adds a compiler flag to set it. Without the option, I
see errors like
```
Writable storage buffer binding aliasing found between [BindGroup] set at bind group index 0, binding index 0, and [BindGroup] set at bind group index 0, binding index 2, with overlapping ranges (offset: 0, size: 256) and (offset: 0, size: 256) in [Buffer].
- While encoding [ComputePassEncoder].DispatchWorkgroups(1, 5, 1).
[Invalid CommandBuffer] is invalid.
at ValidateObject (../../third_party/dawn/src/dawn/native/Device.cpp:689)
at ValidateSubmit (../../third_party/dawn/src/dawn/native/Queue.cpp:442)
```
We can't enable the option by default yet, since it causes some severe
performance regressions on CUDA:
https://github.com/openxla/iree/pull/13323. The tests also have a few
suspicious TODOs, but I want to unblock correctness testing on WebGPU
before digging in deeper.
diff --git a/compiler/src/iree/compiler/Dialect/Stream/IR/StreamBase.td b/compiler/src/iree/compiler/Dialect/Stream/IR/StreamBase.td
index 77d3427..1288878 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/IR/StreamBase.td
+++ b/compiler/src/iree/compiler/Dialect/Stream/IR/StreamBase.td
@@ -319,7 +319,9 @@
// bindings.
"int64_t":$minBufferRangeAlignment,
// Number of bits in `index` values as passed across device boundaries.
- "int64_t":$indexBits
+ "int64_t":$indexBits,
+ // Fuses bindings that are mutable instead of leaving them split.
+ "bool":$aliasMutableBindings
);
let valueType = NoneType;
diff --git a/compiler/src/iree/compiler/Dialect/Stream/IR/StreamTypes.cpp b/compiler/src/iree/compiler/Dialect/Stream/IR/StreamTypes.cpp
index 49baca2..8a922ca 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/IR/StreamTypes.cpp
+++ b/compiler/src/iree/compiler/Dialect/Stream/IR/StreamTypes.cpp
@@ -63,6 +63,11 @@
"iree-stream-resource-index-bits",
llvm::cl::desc("Bit width of indices used to reference resource offsets."),
llvm::cl::init(32));
+static llvm::cl::opt<bool> clResourceAliasMutableBindings(
+ "iree-stream-resource-alias-mutable-bindings",
+ llvm::cl::desc(
+ "Fuses bindings that are mutable instead of leaving them split."),
+ llvm::cl::init(false));
//===----------------------------------------------------------------------===//
// #stream.resource_config<...>
@@ -77,6 +82,7 @@
int64_t maxBufferRange = 0;
int64_t minBufferRangeAlignment = 0;
int64_t indexBits = 32;
+ bool aliasMutableBindings = false;
while (failed(p.parseOptionalRBrace())) {
StringRef key;
int64_t value = 0;
@@ -94,14 +100,16 @@
minBufferRangeAlignment = value;
} else if (key == "index_bits") {
indexBits = value;
+ } else if (key == "alias_mutable_bindings") {
+ aliasMutableBindings = (bool)value;
}
(void)p.parseOptionalComma();
}
if (failed(p.parseGreater())) return {};
- return ResourceConfigAttr::get(p.getContext(), maxAllocationSize,
- minBufferOffsetAlignment, maxBufferRange,
- minBufferRangeAlignment, indexBits);
+ return ResourceConfigAttr::get(
+ p.getContext(), maxAllocationSize, minBufferOffsetAlignment,
+ maxBufferRange, minBufferRangeAlignment, indexBits, aliasMutableBindings);
}
void ResourceConfigAttr::print(AsmPrinter &p) const {
@@ -112,7 +120,8 @@
<< ", ";
os << "max_buffer_range = " << getMaxBufferRange() << ", ";
os << "min_buffer_range_alignment = " << getMinBufferRangeAlignment() << ", ";
- os << "index_bits = " << getIndexBits();
+ os << "index_bits = " << getIndexBits() << ", ";
+ os << "alias_mutable_bindings = " << getAliasMutableBindings();
os << "}>";
}
@@ -130,7 +139,8 @@
std::min(lhs.getMaxBufferRange(), rhs.getMaxBufferRange()),
std::max(lhs.getMinBufferRangeAlignment(),
rhs.getMinBufferRangeAlignment()),
- std::max(lhs.getIndexBits(), rhs.getIndexBits()));
+ std::max(lhs.getIndexBits(), rhs.getIndexBits()),
+ rhs.getAliasMutableBindings() && lhs.getAliasMutableBindings());
}
// static
@@ -141,7 +151,8 @@
// only use this during testing by ensuring affinities are always assigned.
return ResourceConfigAttr::get(
context, clResourceMaxAllocationSize, clResourceMinOffsetAlignment,
- clResourceMaxRange, clResourceMinOffsetAlignment, clResourceIndexBits);
+ clResourceMaxRange, clResourceMinOffsetAlignment, clResourceIndexBits,
+ clResourceAliasMutableBindings);
}
// static
diff --git a/compiler/src/iree/compiler/Dialect/Stream/Transforms/FuseDispatchBindings.cpp b/compiler/src/iree/compiler/Dialect/Stream/Transforms/FuseDispatchBindings.cpp
index 017e607..4b90e35 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/Transforms/FuseDispatchBindings.cpp
+++ b/compiler/src/iree/compiler/Dialect/Stream/Transforms/FuseDispatchBindings.cpp
@@ -315,11 +315,14 @@
IREE::Stream::ExecutableOp executableOp,
IREE::Stream::ExecutableExportOp exportOp,
ArrayRef<IREE::Stream::CmdDispatchOp> dispatchOps,
- bool aliasMutableBindings, MemoizedCmdZeros &memoizedZeros) {
+ MemoizedCmdZeros &memoizedZeros) {
if (dispatchOps.empty()) return; // no-op if no dispatches
auto anyDispatchOp = dispatchOps.front();
unsigned bindingCount = anyDispatchOp.getResources().size();
+ auto configAttr = IREE::Stream::ResourceConfigAttr::lookup(exportOp);
+ bool aliasMutableBindings = configAttr.getAliasMutableBindings();
+
LLVM_DEBUG({
AsmState asmState(executableOp->getParentOp());
llvm::dbgs() << "---- fuseDispatchBindings(@" << executableOp.getSymName()
@@ -448,7 +451,7 @@
for (auto exportOp :
executableOp.getOps<IREE::Stream::ExecutableExportOp>()) {
fuseDispatchBindings(executableOp, exportOp, entryDispatchMap[exportOp],
- aliasMutableBindings, memoizedZeros);
+ memoizedZeros);
}
}
}
diff --git a/compiler/src/iree/compiler/Dialect/Stream/Transforms/Passes.td b/compiler/src/iree/compiler/Dialect/Stream/Transforms/Passes.td
index 788771e..ed72ab0 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/Transforms/Passes.td
+++ b/compiler/src/iree/compiler/Dialect/Stream/Transforms/Passes.td
@@ -190,11 +190,6 @@
let constructor = [{
mlir::iree_compiler::IREE::Stream::createFuseDispatchBindingsPass()
}];
- let options = [
- Option<"aliasMutableBindings", "alias-mutable-bindings",
- "bool", /*default=*/"false",
- "Fuses bindings that are mutable instead of leaving them split.">
- ];
}
def SpecializeDispatches :
diff --git a/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings.mlir b/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings.mlir
index 764c788..198ad3f 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings.mlir
+++ b/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings.mlir
@@ -1,4 +1,4 @@
-// RUN: iree-opt --split-input-file --pass-pipeline='builtin.module(iree-stream-fuse-dispatch-bindings{alias-mutable-bindings=true})' %s | FileCheck %s
+// RUN: iree-opt --split-input-file --pass-pipeline='builtin.module(iree-stream-fuse-dispatch-bindings)' %s | FileCheck %s
// Test that bindings that are unique are rebased to the widest possible access
// and to have a 0 offset by passing in the actual offset as operands. The
@@ -8,9 +8,13 @@
// TODO(benvanik): do this in a canonicalize bindings pass. This should not be
// happening here!
+#aliasConfig = #stream.resource_config<{
+ alias_mutable_bindings = true
+}>
+
// CHECK-LABEL: @rebaseBindingsEx
stream.executable private @rebaseBindingsEx {
- stream.executable.export public @dispatch
+ stream.executable.export public @dispatch attributes {stream.resources = #aliasConfig}
builtin.module {
// CHECK: func.func @dispatch(%[[BINDING_A:.+]]: !stream.binding, %[[BINDING_B:.+]]: !stream.binding,
// CHECK-SAME: %[[OFFSET_A:.+]]: index, %[[OFFSET_B:.+]]: index, %[[OPERAND:.+]]: index)
@@ -85,9 +89,13 @@
// in the order of the deduplicated bindings instead of the original order.
// This is a bit weird and it would be nice to preserve the order in the future.
+#aliasConfig = #stream.resource_config<{
+ alias_mutable_bindings = true
+}>
+
// CHECK-LABEL: @deduplicateBindingsEx
stream.executable private @deduplicateBindingsEx {
- stream.executable.export public @dispatch
+ stream.executable.export public @dispatch attributes {stream.resources = #aliasConfig}
builtin.module {
// CHECK: func.func @dispatch(%[[BINDING_A:.+]]: !stream.binding, %[[BINDING_B:.+]]: !stream.binding,
// CHECK-SAME: %[[OFFSET_A:.+]]: index, %[[OFFSET_C:.+]]: index, %[[OFFSET_B:.+]]: index, %[[OPERAND:.+]]: index)
diff --git a/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings_noalias.mlir b/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings_noalias.mlir
index da1abe6..686819f 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings_noalias.mlir
+++ b/compiler/src/iree/compiler/Dialect/Stream/Transforms/test/fuse_dispatch_bindings_noalias.mlir
@@ -1,13 +1,17 @@
-// RUN: iree-opt --split-input-file --pass-pipeline='builtin.module(iree-stream-fuse-dispatch-bindings{alias-mutable-bindings=false})' %s | FileCheck %s
+// RUN: iree-opt --split-input-file --pass-pipeline='builtin.module(iree-stream-fuse-dispatch-bindings)' %s | FileCheck %s
// TODO(benvanik): remove this file when aliasing mutable bindings is fixed.
// Tests that bindings that are duplicated at all dispatch sites are folded
// so long as they are not mutable.
+#noaliasConfig = #stream.resource_config<{
+ alias_mutable_bindings = false
+}>
+
// CHECK-LABEL: @deduplicateBindingsEx
stream.executable private @deduplicateBindingsEx {
- stream.executable.export public @dispatch
+ stream.executable.export public @dispatch attributes {stream.resources = #noaliasConfig}
builtin.module {
// CHECK: func.func @dispatch(%[[BINDING_A:.+]]: !stream.binding, %[[BINDING_C:.+]]: !stream.binding,
// CHECK-SAME: %[[OFFSET_A:.+]]: index, %[[OFFSET_B:.+]]: index, %[[OFFSET_C:.+]]: index, %[[OPERAND:.+]]: index)
diff --git a/experimental/web/sample_webgpu/build_sample.sh b/experimental/web/sample_webgpu/build_sample.sh
index 9360374..58dafa3 100755
--- a/experimental/web/sample_webgpu/build_sample.sh
+++ b/experimental/web/sample_webgpu/build_sample.sh
@@ -53,6 +53,7 @@
--iree-input-type=$2 \
--iree-hal-target-backends=webgpu \
--iree-codegen-gpu-native-math-precision=true \
+ --iree-stream-resource-alias-mutable-bindings=true \
--o ${BINARY_DIR}/$1_webgpu.vmfb
}
diff --git a/experimental/web/sample_webgpu/index.html b/experimental/web/sample_webgpu/index.html
index 1196e72..949d98b 100644
--- a/experimental/web/sample_webgpu/index.html
+++ b/experimental/web/sample_webgpu/index.html
@@ -177,7 +177,8 @@
<textarea type="text" readonly spellcheck="false"
class="form-control" style="width:610px; height:90px; resize:none; font-family: monospace;">
--iree-hal-target-backends=webgpu \
---iree-codegen-gpu-native-math-precision=true \</textarea>
+--iree-codegen-gpu-native-math-precision=true \
+--iree-stream-resource-alias-mutable-bindings=true \</textarea>
</div>