I think we already have “local effects” through recursive effects / speculation.
No, recursive side effects don’t help with describing “local effects” and are orthogonal to the latter. An op with “local effects” as described above may or may not have any regions at all, and its local or non-local effects are independent of the ops contained in its region. I think I had already provided an example. But to make it clearer, consider:
%r = abc.wait %handle : memref<1xi32>
The above may declare a memory read effect on %handle, i.e., it reads the memory of handle. However, if the semantics of the op are to read the element of %handle and, based on that information, finish all associated memory writes/reads that were earlier issued on other memory (not reflected in the operands, but available through %handle or otherwise encoded in the op’s semantics), then the op has “non-local effects” per the proposed interface. This is just one among the numerous examples I can think of. In fact, one may have zero operand ops like “abc.flush” with such non-local effects. These ops will not implement RecursiveMemoryEffects, and in the latter case, have no memory effects at all. They are all simply non-pure.
In contrast, if there are ops that simply read/write their operands’ memory (e.g. memref.copy, affine.load/store, memref.load/ and the numerous other ops in upstream dialects) without anything else non-local, these are ops with “local effects”. They are non-pure as well but of a different kind.
The new interface trait being proposed allows utilities/analyses to distinguish between this class of ops and ones like “abc.wait” that I mentioned above. Otherwise, there is nothing in MLIR, direct or indirect, that would allow one to distinguish between these two classes. That ability can be pretty powerful and broadly applicable.