diff --git a/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td b/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td --- a/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td +++ b/mlir/include/mlir/Dialect/StandardOps/IR/Ops.td @@ -499,7 +499,8 @@ The result represents the latest value that was stored. The region contains the code for the modification itself. The entry block has a single argument that represents the value stored in `memref[indices]` before the write is - performed. + performed. No side-effecting ops are allowed in the body of + `GenericAtomicRMWOp`. Example: diff --git a/mlir/lib/Dialect/StandardOps/IR/Ops.cpp b/mlir/lib/Dialect/StandardOps/IR/Ops.cpp --- a/mlir/lib/Dialect/StandardOps/IR/Ops.cpp +++ b/mlir/lib/Dialect/StandardOps/IR/Ops.cpp @@ -507,6 +507,18 @@ if (op.getResult().getType() != block.getArgument(0).getType()) return op.emitOpError( "expected block argument of the same type result type"); + + bool hasSideEffects = + op.body() + .walk([&](Operation *nestedOp) { + return MemoryEffectOpInterface::hasNoEffect(nestedOp) + ? WalkResult::advance() + : WalkResult::interrupt(); + }) + .wasInterrupted(); + if (hasSideEffects) + return op.emitError("body of 'generic_atomic_rmw' should contain " + "only operations with no side effects"); return success(); } diff --git a/mlir/test/IR/invalid-ops.mlir b/mlir/test/IR/invalid-ops.mlir --- a/mlir/test/IR/invalid-ops.mlir +++ b/mlir/test/IR/invalid-ops.mlir @@ -1179,6 +1179,18 @@ // ----- +func @generic_atomic_rmw_has_side_effects(%I: memref<10xf32>, %i : index) { + // expected-error@+1 {{should contain only operations with no side effects}} + %x = generic_atomic_rmw %I[%i] : memref<10xf32> { + ^bb0(%old_value : f32): + %c1 = constant 1.0 : f32 + %buf = alloc() : memref<2048xf32> + atomic_yield %c1 : f32 + } +} + +// ----- + func @atomic_yield_type_mismatch(%I: memref<10xf32>, %i : index) { // expected-error@+4 {{op types mismatch between yield op: 'i32' and its parent: 'f32'}} %x = generic_atomic_rmw %I[%i] : memref<10xf32> {