[flang-commits] [flang] 2c1ae80 - [mlir][side effect] refactor(*): Include more precise side effects (#94213)

via flang-commits flang-commits at lists.llvm.org
Wed Jun 19 07:10:39 PDT 2024


Author: donald chen
Date: 2024-06-19T22:10:34+08:00
New Revision: 2c1ae801e1b66a09a15028ae4ba614e0911eec00

URL: https://github.com/llvm/llvm-project/commit/2c1ae801e1b66a09a15028ae4ba614e0911eec00
DIFF: https://github.com/llvm/llvm-project/commit/2c1ae801e1b66a09a15028ae4ba614e0911eec00.diff

LOG: [mlir][side effect] refactor(*): Include more precise side effects (#94213)

This patch adds more precise side effects to the current ops with memory
effects, allowing us to determine which OpOperand/OpResult/BlockArgument
the
operation reads or writes, rather than just recording the reading and
writing
of values. This allows for convenient use of precise side effects to
achieve
analysis and optimization.

Related discussions:
https://discourse.llvm.org/t/rfc-add-operandindex-to-sideeffect-instance/79243

Added: 
    

Modified: 
    flang/lib/Optimizer/Dialect/FIROps.cpp
    flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
    flang/lib/Optimizer/HLFIR/Transforms/ScheduleOrderedAssignments.cpp
    flang/test/HLFIR/memory-effects.fir
    mlir/examples/transform/Ch2/lib/MyExtension.cpp
    mlir/examples/transform/Ch3/lib/MyExtension.cpp
    mlir/examples/transform/Ch4/lib/MyExtension.cpp
    mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
    mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
    mlir/include/mlir/Dialect/Transform/Interfaces/MatchInterfaces.h
    mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h
    mlir/include/mlir/Interfaces/SideEffectInterfaces.h
    mlir/lib/Dialect/Affine/IR/AffineOps.cpp
    mlir/lib/Dialect/Affine/TransformOps/AffineTransformOps.cpp
    mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
    mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp
    mlir/lib/Dialect/Func/TransformOps/FuncTransformOps.cpp
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
    mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp
    mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
    mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
    mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
    mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp
    mlir/lib/Dialect/Transform/IR/TransformOps.cpp
    mlir/lib/Dialect/Transform/IRDLExtension/IRDLExtensionOps.cpp
    mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp
    mlir/lib/Dialect/Transform/LoopExtension/LoopExtensionOps.cpp
    mlir/lib/Dialect/Transform/PDLExtension/PDLExtensionOps.cpp
    mlir/lib/Dialect/Vector/IR/VectorOps.cpp
    mlir/lib/Interfaces/SideEffectInterfaces.cpp
    mlir/test/Dialect/Bufferization/side-effects.mlir
    mlir/test/IR/test-side-effects.mlir
    mlir/test/lib/Dialect/Test/TestOpDefs.cpp
    mlir/test/lib/Dialect/Test/TestOps.td
    mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp
    mlir/test/lib/IR/TestSideEffects.cpp
    mlir/test/lib/Interfaces/TilingInterface/TestTilingInterfaceTransformOps.cpp
    mlir/test/mlir-tblgen/op-side-effects.td
    mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 7b5f4fd28489c..84711c5406581 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1058,9 +1058,9 @@ void fir::BoxRankOp::getEffects(
     llvm::SmallVectorImpl<
         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
         &effects) {
-  mlir::Value inputBox = getBox();
-  if (fir::isBoxAddress(inputBox.getType()))
-    effects.emplace_back(mlir::MemoryEffects::Read::get(), inputBox,
+  mlir::OpOperand &inputBox = getBoxMutable();
+  if (fir::isBoxAddress(inputBox.get().getType()))
+    effects.emplace_back(mlir::MemoryEffects::Read::get(), &inputBox,
                          mlir::SideEffects::DefaultResource::get());
 }
 
@@ -2901,9 +2901,9 @@ void fir::ReboxAssumedRankOp::getEffects(
     llvm::SmallVectorImpl<
         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
         &effects) {
-  mlir::Value inputBox = getBox();
-  if (fir::isBoxAddress(inputBox.getType()))
-    effects.emplace_back(mlir::MemoryEffects::Read::get(), inputBox,
+  mlir::OpOperand &inputBox = getBoxMutable();
+  if (fir::isBoxAddress(inputBox.get().getType()))
+    effects.emplace_back(mlir::MemoryEffects::Read::get(), &inputBox,
                          mlir::SideEffects::DefaultResource::get());
 }
 

diff  --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index bf0acc21d24b1..cbe789fed1162 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -45,7 +45,7 @@ getIntrinsicEffects(mlir::Operation *self,
          "hlfir intrinsic ops only produce 1 result");
   if (mlir::isa<hlfir::ExprType>(self->getResult(0).getType()))
     effects.emplace_back(mlir::MemoryEffects::Allocate::get(),
-                         self->getResult(0),
+                         self->getOpResult(0),
                          mlir::SideEffects::DefaultResource::get());
 
   // read effect if we read from a pointer or refference type
@@ -59,10 +59,10 @@ getIntrinsicEffects(mlir::Operation *self,
   // } to {
   //   hlfir.yield %0#0 : !fir.box<!fir.array<?x?xf32>>
   // }
-  for (mlir::Value operand : self->getOperands()) {
-    mlir::Type opTy = operand.getType();
+  for (mlir::OpOperand &operand : self->getOpOperands()) {
+    mlir::Type opTy = operand.get().getType();
     if (fir::isa_ref_type(opTy) || fir::isa_box_type(opTy))
-      effects.emplace_back(mlir::MemoryEffects::Read::get(), operand,
+      effects.emplace_back(mlir::MemoryEffects::Read::get(), &operand,
                            mlir::SideEffects::DefaultResource::get());
   }
 }

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/ScheduleOrderedAssignments.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ScheduleOrderedAssignments.cpp
index 2c840ce4ffe82..efe59b8ef988e 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ScheduleOrderedAssignments.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ScheduleOrderedAssignments.cpp
@@ -225,14 +225,14 @@ static void gatherMemoryEffects(
 
 /// Return the entity yielded by a region, or a null value if the region
 /// is not terminated by a yield.
-static mlir::Value getYieldedEntity(mlir::Region &region) {
+static mlir::OpOperand *getYieldedEntity(mlir::Region &region) {
   if (region.empty() || region.back().empty())
     return nullptr;
   if (auto yield = mlir::dyn_cast<hlfir::YieldOp>(region.back().back()))
-    return yield.getEntity();
+    return &yield.getEntityMutable();
   if (auto elementalAddr =
           mlir::dyn_cast<hlfir::ElementalAddrOp>(region.back().back()))
-    return elementalAddr.getYieldOp().getEntity();
+    return &elementalAddr.getYieldOp().getEntityMutable();
   return nullptr;
 }
 
@@ -244,7 +244,7 @@ static void gatherAssignEffects(
     hlfir::RegionAssignOp regionAssign,
     bool userDefAssignmentMayOnlyWriteToAssignedVariable,
     llvm::SmallVectorImpl<mlir::MemoryEffects::EffectInstance> &assignEffects) {
-  mlir::Value assignedVar = getYieldedEntity(regionAssign.getLhsRegion());
+  mlir::OpOperand *assignedVar = getYieldedEntity(regionAssign.getLhsRegion());
   assert(assignedVar && "lhs cannot be an empty region");
   assignEffects.emplace_back(mlir::MemoryEffects::Write::get(), assignedVar);
 
@@ -389,8 +389,8 @@ void Scheduler::saveEvaluationIfConflict(mlir::Region &yieldRegion,
   // with a finalizer, or a user defined assignment where the LHS is
   // intent(inout)).
   if (yieldIsImplicitRead) {
-    mlir::Value entity = getYieldedEntity(yieldRegion);
-    if (entity && hlfir::isFortranVariableType(entity.getType()))
+    mlir::OpOperand *entity = getYieldedEntity(yieldRegion);
+    if (entity && hlfir::isFortranVariableType(entity->get().getType()))
       effects.emplace_back(mlir::MemoryEffects::Read::get(), entity);
   }
   if (!leafRegionsMayOnlyRead && anyWrite(effects)) {
@@ -600,9 +600,9 @@ hlfir::buildEvaluationSchedule(hlfir::OrderedAssignmentTreeOpInterface root,
 }
 
 mlir::Value hlfir::SaveEntity::getSavedValue() {
-  mlir::Value saved = getYieldedEntity(*yieldRegion);
+  mlir::OpOperand *saved = getYieldedEntity(*yieldRegion);
   assert(saved && "SaveEntity must contain region terminated by YieldOp");
-  return saved;
+  return saved->get();
 }
 
 //===----------------------------------------------------------------------===//

diff  --git a/flang/test/HLFIR/memory-effects.fir b/flang/test/HLFIR/memory-effects.fir
index 66659829284fe..cac887ebe67de 100644
--- a/flang/test/HLFIR/memory-effects.fir
+++ b/flang/test/HLFIR/memory-effects.fir
@@ -3,214 +3,186 @@
 func.func @concat(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: !fir.ref<!fir.char<1, 20>>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %c30 = arith.constant 30 : index
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,20>>, index) -> (!hlfir.expr<!fir.char<1,30>>)
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @all_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %all = hlfir.all %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> !fir.logical<4>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @all_effects(%arg0: !fir.ref<!fir.array<2x10x!fir.logical<4>>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %all = hlfir.all %arg0 dim %arg1 : (!fir.ref<!fir.array<2x10x!fir.logical<4>>>, i32) -> !hlfir.expr<?x!fir.logical<4>>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @any_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %all = hlfir.any %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> !fir.logical<4>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @any_effects(%arg0: !fir.ref<!fir.array<2x10x!fir.logical<4>>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %all = hlfir.any %arg0 dim %arg1 : (!fir.ref<!fir.array<2x10x!fir.logical<4>>>, i32) -> !hlfir.expr<?x!fir.logical<4>>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @count_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %all = hlfir.count %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> i32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @count_effects(%arg0: !fir.ref<!fir.array<2x10x!fir.logical<4>>>, %arg1: i32) {
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %all = hlfir.count %arg0 dim %arg1 : (!fir.ref<!fir.array<2x10x!fir.logical<4>>>, i32) -> i32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @product_no_effects(%arg0: !hlfir.expr<?xf32>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %product = hlfir.product %arg0 : (!hlfir.expr<?xf32>) -> f32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @product_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %product = hlfir.product %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @set_length_read(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: index) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.set_length %arg0 len %arg1 : (!fir.ref<!fir.char<1,10>>, index) -> !hlfir.expr<!fir.char<1,?>>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @sum_no_effects(%arg0: !hlfir.expr<?xf32>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %sum = hlfir.sum %arg0 : (!hlfir.expr<?xf32>) -> f32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @sum_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %sum = hlfir.sum %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @maxval_no_effects(%arg0: !hlfir.expr<?xf32>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %maxval = hlfir.maxval %arg0 : (!hlfir.expr<?xf32>) -> f32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @maxval_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %maxval = hlfir.maxval %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @minval_no_effects(%arg0: !hlfir.expr<?xf32>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %minval = hlfir.minval %arg0 : (!hlfir.expr<?xf32>) -> f32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @minval_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %minval = hlfir.minval %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @minloc_effects_simple(%arg0: !hlfir.expr<?xf32>) {
-// expected-remark at +1 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
   %minloc = hlfir.minloc %arg0 : (!hlfir.expr<?xf32>) -> !hlfir.expr<?xi32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @minloc_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %minloc = hlfir.minloc %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xi32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @maxloc_effects_simple(%arg0: !hlfir.expr<?xf32>) {
-// expected-remark at +1 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
   %maxloc = hlfir.maxloc %arg0 : (!hlfir.expr<?xf32>) -> !hlfir.expr<?xi32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @maxloc_effects(%arg0: !fir.ref<!fir.array<2x2xf32>>, %arg1: i32) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %maxloc = hlfir.maxloc %arg0 dim %arg1 : (!fir.ref<!fir.array<2x2xf32>>, i32) -> !hlfir.expr<2xi32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @dot_product_no_effects(%arg0: !hlfir.expr<?xf32>, %arg1: !hlfir.expr<?xf32>) {
 // expected-remark at +1 {{operation has no memory effects}}
   %0 = hlfir.dot_product %arg0 %arg1 : (!hlfir.expr<?xf32>, !hlfir.expr<?xf32>) -> f32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @dot_product_effects(%arg0: !fir.ref<!fir.array<10xf32>>, %arg1: !fir.ref<!fir.array<10xf32>>) {
 // there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.dot_product %arg0 %arg1 : (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>) -> f32
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @matmul_no_reads(%arg0: !hlfir.expr<?x?xf32>, %arg1: !hlfir.expr<?x?xf32>) {
-// expected-remark at +1 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
   %0 = hlfir.matmul %arg0 %arg1 : (!hlfir.expr<?x?xf32>, !hlfir.expr<?x?xf32>) -> !hlfir.expr<?x?xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @matmul_reads(%arg0: !fir.ref<!fir.array<10x5xf32>>, %arg1: !fir.ref<!fir.array<5x10xf32>>) {
-// expected-remark at +3 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +3 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
 // there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.matmul %arg0 %arg1 : (!fir.ref<!fir.array<10x5xf32>>, !fir.ref<!fir.array<5x10xf32>>) -> !hlfir.expr<10x10xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @transpose_no_reads(%arg0: !hlfir.expr<?x?xf32>) {
-// expected-remark at +1 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
   %0 = hlfir.transpose %arg0 : (!hlfir.expr<?x?xf32>) -> !hlfir.expr<?x?xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @transpose_read(%arg0: !fir.ref<!fir.array<10x5xf32>>) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.transpose %arg0 : (!fir.ref<!fir.array<10x5xf32>>) -> !hlfir.expr<5x10xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @matmul_transpose_no_reads(%arg0: !hlfir.expr<?x?xf32>, %arg1: !hlfir.expr<?x?xf32>) {
-// expected-remark at +1 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
   %0 = hlfir.matmul_transpose %arg0 %arg1 : (!hlfir.expr<?x?xf32>, !hlfir.expr<?x?xf32>) -> !hlfir.expr<?x?xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @matmul_transpose_reads(%arg0: !fir.ref<!fir.array<5x10xf32>>, %arg1: !fir.ref<!fir.array<5x10xf32>>) {
-// expected-remark at +3 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +3 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
 // there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.matmul_transpose %arg0 %arg1 : (!fir.ref<!fir.array<5x10xf32>>, !fir.ref<!fir.array<5x10xf32>>) -> !hlfir.expr<10x10xf32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
@@ -219,46 +191,41 @@ func.func @associate(%arg0: i32) {
   %0:3 = hlfir.associate %arg0 {uniq_name = "x"} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
 // expected-remark at +1 {{found an instance of 'free' on resource '<Default>'}}
   hlfir.end_associate %0#1, %0#2 : !fir.ref<i32>, i1
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @as_expr_read(%arg0: !fir.ref<!fir.array<2xi32>>) {
-// expected-remark at +2 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.as_expr %arg0 : (!fir.ref<!fir.array<2xi32>>) -> !hlfir.expr<?xi32>
 // expected-remark at +1 {{found an instance of 'free' on resource '<Default>'}}
   hlfir.destroy %0 : !hlfir.expr<?xi32>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @char_extremum(%arg0: !fir.ref<!fir.char<1,10>>, %arg1: !fir.ref<!fir.char<1,20>>) {
-// expected-remark at +3 {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+// expected-remark at +3 {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
 // there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   %0 = hlfir.char_extremum min, %arg0, %arg1 : (!fir.ref<!fir.char<1, 10>>, !fir.ref<!fir.char<1,20>>) -> !hlfir.expr<!fir.char<1,10>>
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @copy_in(%box: !fir.box<!fir.array<?xf64>>, %temp: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, %is_present: i1) {
 // expected-remark at +3 {{found an instance of 'allocate' on resource '<Default>'}}
-// expected-remark at +2 {{found an instance of 'read' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'write' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'write' on a op operand, on resource '<Default>'}}
   %0:2 = hlfir.copy_in %box to %temp : (!fir.box<!fir.array<?xf64>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>) -> (!fir.box<!fir.array<?xf64>>, i1)
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }
 
 func.func @copy_out(%box: !fir.box<!fir.array<?xf64>>, %temp: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, %was_copied: i1) {
 // expected-remark at +2 {{found an instance of 'free' on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
   hlfir.copy_out %temp, %was_copied : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, i1) -> ()
 // expected-remark at +3 {{found an instance of 'free' on resource '<Default>'}}
-// expected-remark at +2 {{found an instance of 'read' on a value, on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'write' on a value, on resource '<Default>'}}
+// expected-remark at +2 {{found an instance of 'read' on a op operand, on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'write' on a op operand, on resource '<Default>'}}
   hlfir.copy_out %temp, %was_copied to %box : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, i1, !fir.box<!fir.array<?xf64>>) -> ()
-// expected-remark at +1 {{operation has no memory effects}}
   return
 }

diff  --git a/mlir/examples/transform/Ch2/lib/MyExtension.cpp b/mlir/examples/transform/Ch2/lib/MyExtension.cpp
index b2955a905b883..68d538a098018 100644
--- a/mlir/examples/transform/Ch2/lib/MyExtension.cpp
+++ b/mlir/examples/transform/Ch2/lib/MyExtension.cpp
@@ -129,7 +129,7 @@ void mlir::transform::ChangeCallTargetOp::getEffects(
   // Indicate that the `call` handle is only read by this operation because the
   // associated operation is not erased but rather modified in-place, so the
   // reference to it remains valid.
-  onlyReadsHandle(getCall(), effects);
+  onlyReadsHandle(getCallMutable(), effects);
 
   // Indicate that the payload is modified by this operation.
   modifiesPayload(effects);

diff  --git a/mlir/examples/transform/Ch3/lib/MyExtension.cpp b/mlir/examples/transform/Ch3/lib/MyExtension.cpp
index 2e4388d4cc228..f7a99423a52ee 100644
--- a/mlir/examples/transform/Ch3/lib/MyExtension.cpp
+++ b/mlir/examples/transform/Ch3/lib/MyExtension.cpp
@@ -139,7 +139,7 @@ void mlir::transform::ChangeCallTargetOp::getEffects(
   // Indicate that the `call` handle is only read by this operation because the
   // associated operation is not erased but rather modified in-place, so the
   // reference to it remains valid.
-  onlyReadsHandle(getCall(), effects);
+  onlyReadsHandle(getCallMutable(), effects);
 
   // Indicate that the payload is modified by this operation.
   modifiesPayload(effects);

diff  --git a/mlir/examples/transform/Ch4/lib/MyExtension.cpp b/mlir/examples/transform/Ch4/lib/MyExtension.cpp
index 83e2dcd750bb3..079073679fc43 100644
--- a/mlir/examples/transform/Ch4/lib/MyExtension.cpp
+++ b/mlir/examples/transform/Ch4/lib/MyExtension.cpp
@@ -160,9 +160,8 @@ mlir::transform::HasOperandSatisfyingOp::apply(
 void mlir::transform::HasOperandSatisfyingOp::getEffects(
     llvm::SmallVectorImpl<mlir::MemoryEffects::EffectInstance> &effects) {
   onlyReadsPayload(effects);
-  onlyReadsHandle(getOp(), effects);
-  producesHandle(getPosition(), effects);
-  producesHandle(getResults(), effects);
+  onlyReadsHandle(getOpMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
 }
 
 // Verify well-formedness of the operation and emit diagnostics if it is

diff  --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
index f070d04886190..5c75e102c3d40 100644
--- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
+++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
@@ -107,6 +107,9 @@ class AffineDmaStartOp
 
   /// Returns the source MemRefType for this DMA operation.
   Value getSrcMemRef() { return getOperand(getSrcMemRefOperandIndex()); }
+  OpOperand &getSrcMemRefMutable() {
+    return getOperation()->getOpOperand(getSrcMemRefOperandIndex());
+  }
   MemRefType getSrcMemRefType() {
     return cast<MemRefType>(getSrcMemRef().getType());
   }
@@ -117,7 +120,8 @@ class AffineDmaStartOp
   /// Returns the affine map used to access the source memref.
   AffineMap getSrcMap() { return getSrcMapAttr().getValue(); }
   AffineMapAttr getSrcMapAttr() {
-    return cast<AffineMapAttr>(*(*this)->getInherentAttr(getSrcMapAttrStrName()));
+    return cast<AffineMapAttr>(
+        *(*this)->getInherentAttr(getSrcMapAttrStrName()));
   }
 
   /// Returns the source memref affine map indices for this DMA operation.
@@ -139,6 +143,9 @@ class AffineDmaStartOp
 
   /// Returns the destination MemRefType for this DMA operation.
   Value getDstMemRef() { return getOperand(getDstMemRefOperandIndex()); }
+  OpOperand &getDstMemRefMutable() {
+    return getOperation()->getOpOperand(getDstMemRefOperandIndex());
+  }
   MemRefType getDstMemRefType() {
     return cast<MemRefType>(getDstMemRef().getType());
   }
@@ -156,7 +163,8 @@ class AffineDmaStartOp
   /// Returns the affine map used to access the destination memref.
   AffineMap getDstMap() { return getDstMapAttr().getValue(); }
   AffineMapAttr getDstMapAttr() {
-    return cast<AffineMapAttr>(*(*this)->getInherentAttr(getDstMapAttrStrName()));
+    return cast<AffineMapAttr>(
+        *(*this)->getInherentAttr(getDstMapAttrStrName()));
   }
 
   /// Returns the destination memref indices for this DMA operation.
@@ -173,6 +181,9 @@ class AffineDmaStartOp
 
   /// Returns the Tag MemRef for this DMA operation.
   Value getTagMemRef() { return getOperand(getTagMemRefOperandIndex()); }
+  OpOperand &getTagMemRefMutable() {
+    return getOperation()->getOpOperand(getTagMemRefOperandIndex());
+  }
   MemRefType getTagMemRefType() {
     return cast<MemRefType>(getTagMemRef().getType());
   }
@@ -185,7 +196,8 @@ class AffineDmaStartOp
   /// Returns the affine map used to access the tag memref.
   AffineMap getTagMap() { return getTagMapAttr().getValue(); }
   AffineMapAttr getTagMapAttr() {
-    return cast<AffineMapAttr>(*(*this)->getInherentAttr(getTagMapAttrStrName()));
+    return cast<AffineMapAttr>(
+        *(*this)->getInherentAttr(getTagMapAttrStrName()));
   }
 
   /// Returns the tag memref indices for this DMA operation.
@@ -300,6 +312,7 @@ class AffineDmaWaitOp
 
   /// Returns the Tag MemRef associated with the DMA operation being waited on.
   Value getTagMemRef() { return getOperand(0); }
+  OpOperand &getTagMemRefMutable() { return getOperation()->getOpOperand(0); }
   MemRefType getTagMemRefType() {
     return cast<MemRefType>(getTagMemRef().getType());
   }
@@ -307,7 +320,8 @@ class AffineDmaWaitOp
   /// Returns the affine map used to access the tag memref.
   AffineMap getTagMap() { return getTagMapAttr().getValue(); }
   AffineMapAttr getTagMapAttr() {
-    return cast<AffineMapAttr>(*(*this)->getInherentAttr(getTagMapAttrStrName()));
+    return cast<AffineMapAttr>(
+        *(*this)->getInherentAttr(getTagMapAttrStrName()));
   }
 
   /// Returns the tag memref index for this DMA operation.

diff  --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index df40e7a17a15f..2ff9d612a5efa 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -706,6 +706,7 @@ def MemRef_DmaStartOp : MemRef_Op<"dma_start"> {
   let extraClassDeclaration = [{
     // Returns the source MemRefType for this DMA operation.
     Value getSrcMemRef() { return getOperand(0); }
+    OpOperand &getSrcMemRefMutable() { return getOperation()->getOpOperand(0); }
     // Returns the rank (number of indices) of the source MemRefType.
     unsigned getSrcMemRefRank() {
       return ::llvm::cast<MemRefType>(getSrcMemRef().getType()).getRank();
@@ -718,6 +719,7 @@ def MemRef_DmaStartOp : MemRef_Op<"dma_start"> {
 
     // Returns the destination MemRefType for this DMA operations.
     Value getDstMemRef() { return getOperand(1 + getSrcMemRefRank()); }
+    OpOperand &getDstMemRefMutable() { return getOperation()->getOpOperand(1 + getSrcMemRefRank()); }
     // Returns the rank (number of indices) of the destination MemRefType.
     unsigned getDstMemRefRank() {
       return ::llvm::cast<MemRefType>(getDstMemRef().getType()).getRank();
@@ -745,6 +747,9 @@ def MemRef_DmaStartOp : MemRef_Op<"dma_start"> {
     Value getTagMemRef() {
       return getOperand(1 + getSrcMemRefRank() + 1 + getDstMemRefRank() + 1);
     }
+    OpOperand &getTagMemRefMutable() {
+      return getOperation()->getOpOperand(1 + getSrcMemRefRank() + 1 + getDstMemRefRank() + 1);
+    }
 
     // Returns the rank (number of indices) of the tag MemRefType.
     unsigned getTagMemRefRank() {
@@ -801,11 +806,11 @@ def MemRef_DmaStartOp : MemRef_Op<"dma_start"> {
     void getEffects(
         SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>> &
         effects) {
-      effects.emplace_back(MemoryEffects::Read::get(), getSrcMemRef(),
+      effects.emplace_back(MemoryEffects::Read::get(), &getSrcMemRefMutable(),
                            SideEffects::DefaultResource::get());
-      effects.emplace_back(MemoryEffects::Write::get(), getDstMemRef(),
+      effects.emplace_back(MemoryEffects::Write::get(), &getDstMemRefMutable(),
                            SideEffects::DefaultResource::get());
-      effects.emplace_back(MemoryEffects::Read::get(), getTagMemRef(),
+      effects.emplace_back(MemoryEffects::Read::get(), &getTagMemRefMutable(),
                            SideEffects::DefaultResource::get());
     }
   }];
@@ -852,7 +857,7 @@ def MemRef_DmaWaitOp : MemRef_Op<"dma_wait"> {
     void getEffects(
         SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>> &
         effects) {
-      effects.emplace_back(MemoryEffects::Read::get(), getTagMemRef(),
+      effects.emplace_back(MemoryEffects::Read::get(), &getTagMemRefMutable(),
                            SideEffects::DefaultResource::get());
     }
   }];

diff  --git a/mlir/include/mlir/Dialect/Transform/Interfaces/MatchInterfaces.h b/mlir/include/mlir/Dialect/Transform/Interfaces/MatchInterfaces.h
index ad3e375c326fe..43abfbd6c070a 100644
--- a/mlir/include/mlir/Dialect/Transform/Interfaces/MatchInterfaces.h
+++ b/mlir/include/mlir/Dialect/Transform/Interfaces/MatchInterfaces.h
@@ -102,8 +102,8 @@ class AtMostOneOpMatcherOpTrait
   }
 
   void getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-    onlyReadsHandle(this->getOperation()->getOperands(), effects);
-    producesHandle(this->getOperation()->getResults(), effects);
+    onlyReadsHandle(this->getOperation()->getOpOperands(), effects);
+    producesHandle(this->getOperation()->getOpResults(), effects);
     onlyReadsPayload(effects);
   }
 };
@@ -163,8 +163,8 @@ class SingleValueMatcherOpTrait
   }
 
   void getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-    onlyReadsHandle(this->getOperation()->getOperands(), effects);
-    producesHandle(this->getOperation()->getResults(), effects);
+    onlyReadsHandle(this->getOperation()->getOpOperands(), effects);
+    producesHandle(this->getOperation()->getOpResults(), effects);
     onlyReadsPayload(effects);
   }
 };

diff  --git a/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h b/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h
index 21795753ac5f3..b8353043ee09d 100644
--- a/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h
+++ b/mlir/include/mlir/Dialect/Transform/Interfaces/TransformInterfaces.h
@@ -1261,11 +1261,13 @@ struct PayloadIRResource
 ///   - consumes = Read + Free,
 ///   - produces = Allocate + Write,
 ///   - onlyReads = Read.
-void consumesHandle(ValueRange handles,
+void consumesHandle(MutableArrayRef<OpOperand> handles,
                     SmallVectorImpl<MemoryEffects::EffectInstance> &effects);
-void producesHandle(ValueRange handles,
+void producesHandle(ResultRange handles,
                     SmallVectorImpl<MemoryEffects::EffectInstance> &effects);
-void onlyReadsHandle(ValueRange handles,
+void producesHandle(MutableArrayRef<BlockArgument> handles,
+                    SmallVectorImpl<MemoryEffects::EffectInstance> &effects);
+void onlyReadsHandle(MutableArrayRef<OpOperand> handles,
                      SmallVectorImpl<MemoryEffects::EffectInstance> &effects);
 
 /// Checks whether the transform op consumes the given handle.
@@ -1296,8 +1298,8 @@ class FunctionalStyleTransformOpTrait
   /// the results by allocating and writing it and reads/writes the payload IR
   /// in the process.
   void getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-    consumesHandle(this->getOperation()->getOperands(), effects);
-    producesHandle(this->getOperation()->getResults(), effects);
+    consumesHandle(this->getOperation()->getOpOperands(), effects);
+    producesHandle(this->getOperation()->getOpResults(), effects);
     modifiesPayload(effects);
   }
 
@@ -1322,8 +1324,8 @@ class NavigationTransformOpTrait
   /// This op produces handles to the Payload IR without consuming the original
   /// handles and without modifying the IR itself.
   void getEffects(SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-    onlyReadsHandle(this->getOperation()->getOperands(), effects);
-    producesHandle(this->getOperation()->getResults(), effects);
+    onlyReadsHandle(this->getOperation()->getOpOperands(), effects);
+    producesHandle(this->getOperation()->getOpResults(), effects);
     if (llvm::any_of(this->getOperation()->getOperandTypes(), [](Type t) {
           return isa<TransformHandleTypeInterface,
                      TransformValueHandleTypeInterface>(t);

diff  --git a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
index ec4e36263bbe6..aef7ec622fe4f 100644
--- a/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
+++ b/mlir/include/mlir/Interfaces/SideEffectInterfaces.h
@@ -145,12 +145,19 @@ class EffectInstance {
                  Resource *resource = DefaultResource::get())
       : effect(effect), resource(resource), stage(stage),
         effectOnFullRegion(effectOnFullRegion) {}
-  EffectInstance(EffectT *effect, Value value,
+  template <typename T,
+            std::enable_if_t<
+                llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
+                bool> = true>
+  EffectInstance(EffectT *effect, T value,
                  Resource *resource = DefaultResource::get())
       : effect(effect), resource(resource), value(value), stage(0),
         effectOnFullRegion(false) {}
-  EffectInstance(EffectT *effect, Value value, int stage,
-                 bool effectOnFullRegion,
+  template <typename T,
+            std::enable_if_t<
+                llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
+                bool> = true>
+  EffectInstance(EffectT *effect, T value, int stage, bool effectOnFullRegion,
                  Resource *resource = DefaultResource::get())
       : effect(effect), resource(resource), value(value), stage(stage),
         effectOnFullRegion(effectOnFullRegion) {}
@@ -172,11 +179,19 @@ class EffectInstance {
                  Resource *resource = DefaultResource::get())
       : effect(effect), resource(resource), parameters(parameters),
         stage(stage), effectOnFullRegion(effectOnFullRegion) {}
-  EffectInstance(EffectT *effect, Value value, Attribute parameters,
+  template <typename T,
+            std::enable_if_t<
+                llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
+                bool> = true>
+  EffectInstance(EffectT *effect, T value, Attribute parameters,
                  Resource *resource = DefaultResource::get())
       : effect(effect), resource(resource), value(value),
         parameters(parameters), stage(0), effectOnFullRegion(false) {}
-  EffectInstance(EffectT *effect, Value value, Attribute parameters, int stage,
+  template <typename T,
+            std::enable_if_t<
+                llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
+                bool> = true>
+  EffectInstance(EffectT *effect, T value, Attribute parameters, int stage,
                  bool effectOnFullRegion,
                  Resource *resource = DefaultResource::get())
       : effect(effect), resource(resource), value(value),
@@ -199,7 +214,26 @@ class EffectInstance {
   /// Return the value the effect is applied on, or nullptr if there isn't a
   /// known value being affected.
   Value getValue() const {
-    return value ? llvm::dyn_cast_if_present<Value>(value) : Value();
+    if (!value || llvm::isa_and_present<SymbolRefAttr>(value)) {
+      return Value();
+    }
+    if (OpOperand *operand = llvm::dyn_cast_if_present<OpOperand *>(value)) {
+      return operand->get();
+    }
+    if (OpResult result = llvm::dyn_cast_if_present<OpResult>(value)) {
+      return result;
+    }
+    return cast_if_present<BlockArgument>(value);
+  }
+
+  /// Returns the OpOperand effect is applied on, or nullptr if there isn't a
+  /// known value being effected.
+  template <typename T,
+            std::enable_if_t<
+                llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
+                bool> = true>
+  T getEffectValue() const {
+    return value ? dyn_cast_if_present<T>(value) : nullptr;
   }
 
   /// Return the symbol reference the effect is applied on, or nullptr if there
@@ -228,8 +262,9 @@ class EffectInstance {
   /// The resource that the given value resides in.
   Resource *resource;
 
-  /// The Symbol or Value that the effect applies to. This is optionally null.
-  PointerUnion<SymbolRefAttr, Value> value;
+  /// The Symbol, OpOperand, OpResult or BlockArgument that the effect applies
+  /// to. This is optionally null.
+  PointerUnion<SymbolRefAttr, OpOperand *, OpResult, BlockArgument> value;
 
   /// Additional parameters of the effect instance. An attribute is used for
   /// type-safe structured storage and context-based uniquing. Concrete effects
@@ -348,17 +383,32 @@ struct Write : public Effect::Base<Write> {};
 // SideEffect Utilities
 //===----------------------------------------------------------------------===//
 
+/// Returns true if `op` has only an effect of type `EffectTy`.
+template <typename EffectTy>
+bool hasSingleEffect(Operation *op);
+
 /// Returns true if `op` has only an effect of type `EffectTy` (and of no other
-/// type) on `value`. If no value is provided, simply check if effects of that
-/// type and only of that type are present.
+/// type) on `value`.
 template <typename EffectTy>
-bool hasSingleEffect(Operation *op, Value value = nullptr);
+bool hasSingleEffect(Operation *op, Value value);
+
+/// Returns true if `op` has only an effect of type `EffectTy` (and of no other
+/// type) on `value` of type `ValueTy`.
+template <typename ValueTy, typename EffectTy>
+bool hasSingleEffect(Operation *op, ValueTy value);
 
-/// Returns true if `op` has an effect of type `EffectTy` on `value`. If no
-/// `value` is provided, simply check if effects of the given type(s) are
-/// present.
+/// Returns true if `op` has an effect of type `EffectTy`.
 template <typename... EffectTys>
-bool hasEffect(Operation *op, Value value = nullptr);
+bool hasEffect(Operation *op);
+
+/// Returns true if `op` has an effect of type `EffectTy` on `value`.
+template <typename... EffectTys>
+bool hasEffect(Operation *op, Value value);
+
+/// Returns true if `op` has an effect of type `EffectTy` on `value` of type
+/// `ValueTy`.
+template <typename ValueTy, typename... EffectTys>
+bool hasEffect(Operation *op, ValueTy value);
 
 /// Return true if the given operation is unused, and has no side effects on
 /// memory that prevent erasing.

diff  --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
index 6baed92d208fb..a40ffd53f9d71 100644
--- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
+++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
@@ -1707,11 +1707,11 @@ LogicalResult AffineDmaStartOp::fold(ArrayRef<Attribute> cstOperands,
 void AffineDmaStartOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
-  effects.emplace_back(MemoryEffects::Read::get(), getSrcMemRef(),
+  effects.emplace_back(MemoryEffects::Read::get(), &getSrcMemRefMutable(),
                        SideEffects::DefaultResource::get());
-  effects.emplace_back(MemoryEffects::Write::get(), getDstMemRef(),
+  effects.emplace_back(MemoryEffects::Write::get(), &getDstMemRefMutable(),
                        SideEffects::DefaultResource::get());
-  effects.emplace_back(MemoryEffects::Read::get(), getTagMemRef(),
+  effects.emplace_back(MemoryEffects::Read::get(), &getTagMemRefMutable(),
                        SideEffects::DefaultResource::get());
 }
 
@@ -1797,7 +1797,7 @@ LogicalResult AffineDmaWaitOp::fold(ArrayRef<Attribute> cstOperands,
 void AffineDmaWaitOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
-  effects.emplace_back(MemoryEffects::Read::get(), getTagMemRef(),
+  effects.emplace_back(MemoryEffects::Read::get(), &getTagMemRefMutable(),
                        SideEffects::DefaultResource::get());
 }
 

diff  --git a/mlir/lib/Dialect/Affine/TransformOps/AffineTransformOps.cpp b/mlir/lib/Dialect/Affine/TransformOps/AffineTransformOps.cpp
index e8bfd4421f5ca..6457655cfe416 100644
--- a/mlir/lib/Dialect/Affine/TransformOps/AffineTransformOps.cpp
+++ b/mlir/lib/Dialect/Affine/TransformOps/AffineTransformOps.cpp
@@ -142,9 +142,9 @@ SimplifyBoundedAffineOpsOp::apply(transform::TransformRewriter &rewriter,
 
 void SimplifyBoundedAffineOpsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  for (Value v : getBoundedValues())
-    onlyReadsHandle(v, effects);
+  consumesHandle(getTargetMutable(), effects);
+  for (OpOperand &operand : getBoundedValuesMutable())
+    onlyReadsHandle(operand, effects);
   modifiesPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
index 3b7b412842bfb..04a8ff30ee946 100644
--- a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
+++ b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
@@ -728,7 +728,7 @@ void MaterializeInDestinationOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
   if (isa<BaseMemRefType>(getDest().getType()))
-    effects.emplace_back(MemoryEffects::Write::get(), getDest(),
+    effects.emplace_back(MemoryEffects::Write::get(), &getDestMutable(),
                          SideEffects::DefaultResource::get());
 }
 

diff  --git a/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp b/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp
index cbb36639a3383..e10c7bd914e35 100644
--- a/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp
+++ b/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp
@@ -36,7 +36,7 @@ DiagnosedSilenceableFailure transform::BufferLoopHoistingOp::applyToOne(
 
 void transform::BufferLoopHoistingOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getTarget(), effects);
+  onlyReadsHandle(getTargetMutable(), effects);
   modifiesPayload(effects);
 }
 
@@ -110,7 +110,7 @@ transform::OneShotBufferizeOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::EliminateEmptyTensorsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getTarget(), effects);
+  onlyReadsHandle(getTargetMutable(), effects);
   modifiesPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/Func/TransformOps/FuncTransformOps.cpp b/mlir/lib/Dialect/Func/TransformOps/FuncTransformOps.cpp
index 1e262736226f7..b632b25d0cc67 100644
--- a/mlir/lib/Dialect/Func/TransformOps/FuncTransformOps.cpp
+++ b/mlir/lib/Dialect/Func/TransformOps/FuncTransformOps.cpp
@@ -216,14 +216,14 @@ LogicalResult transform::CastAndCallOp::verify() {
 
 void transform::CastAndCallOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getInsertionPoint(), effects);
+  transform::onlyReadsHandle(getInsertionPointMutable(), effects);
   if (getInputs())
-    transform::onlyReadsHandle(getInputs(), effects);
+    transform::onlyReadsHandle(getInputsMutable(), effects);
   if (getOutputs())
-    transform::onlyReadsHandle(getOutputs(), effects);
+    transform::onlyReadsHandle(getOutputsMutable(), effects);
   if (getFunction())
-    transform::onlyReadsHandle(getFunction(), effects);
-  transform::producesHandle(getResult(), effects);
+    transform::onlyReadsHandle(getFunctionMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::modifiesPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index fff6d4d757815..d1280aceeb7b6 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -825,7 +825,7 @@ Type GEPOp::getResultPtrElementType() {
 void LoadOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
-  effects.emplace_back(MemoryEffects::Read::get(), getAddr());
+  effects.emplace_back(MemoryEffects::Read::get(), &getAddrMutable());
   // Volatile operations can have target-specific read-write effects on
   // memory besides the one referred to by the pointer operand.
   // Similarly, atomic operations that are monotonic or stricter cause
@@ -902,7 +902,7 @@ void LoadOp::build(OpBuilder &builder, OperationState &state, Type type,
 void StoreOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
-  effects.emplace_back(MemoryEffects::Write::get(), getAddr());
+  effects.emplace_back(MemoryEffects::Write::get(), &getAddrMutable());
   // Volatile operations can have target-specific read-write effects on
   // memory besides the one referred to by the pointer operand.
   // Similarly, atomic operations that are monotonic or stricter cause

diff  --git a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
index b79afebfa8158..7b6256050e772 100644
--- a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
+++ b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
@@ -1123,28 +1123,23 @@ static void getGenericEffectsImpl(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects,
     LinalgOp linalgOp) {
-  SmallVector<Value> inputOperands = linalgOp.getDpsInputs();
-  for (auto [index, operand] : llvm::enumerate(inputOperands)) {
+  for (auto [index, operand] : llvm::enumerate(linalgOp.getDpsInputs())) {
     if (!llvm::isa<MemRefType>(operand.getType()))
       continue;
-    if (linalgOp.payloadUsesValueFromOperand(&linalgOp->getOpOperand(index))) {
-      effects.emplace_back(MemoryEffects::Read::get(), operand, /*stage=*/0,
-                           /*effectOnFullRegion=*/true,
-                           SideEffects::DefaultResource::get());
-    }
+    effects.emplace_back(
+        MemoryEffects::Read::get(), &linalgOp->getOpOperand(index), /*stage=*/0,
+        /*effectOnFullRegion=*/true, SideEffects::DefaultResource::get());
   }
-  unsigned inputOperandSize = inputOperands.size();
 
-  for (auto [index, operand] : llvm::enumerate(linalgOp.getDpsInits())) {
-    if (!llvm::isa<MemRefType>(operand.getType()))
+  for (OpOperand &operand : linalgOp.getDpsInitsMutable()) {
+    if (!llvm::isa<MemRefType>(operand.get().getType()))
       continue;
-    if (linalgOp.payloadUsesValueFromOperand(
-            &linalgOp->getOpOperand(index + inputOperandSize))) {
-      effects.emplace_back(MemoryEffects::Read::get(), operand, /*stage=*/0,
+    if (linalgOp.payloadUsesValueFromOperand(&operand)) {
+      effects.emplace_back(MemoryEffects::Read::get(), &operand, /*stage=*/0,
                            /*effectOnFullRegion=*/true,
                            SideEffects::DefaultResource::get());
     }
-    effects.emplace_back(MemoryEffects::Write::get(), operand, /*stage=*/0,
+    effects.emplace_back(MemoryEffects::Write::get(), &operand, /*stage=*/0,
                          /*effectOnFullRegion=*/true,
                          SideEffects::DefaultResource::get());
   }
@@ -2546,20 +2541,22 @@ SoftmaxOp::reifyResultShapes(OpBuilder &b,
 void SoftmaxOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
-  for (Value operand : getDpsInputs()) {
+  for (auto [index, operand] : llvm::enumerate(getDpsInputs())) {
     if (!llvm::isa<MemRefType>(operand.getType()))
       continue;
-    effects.emplace_back(MemoryEffects::Read::get(), operand, /*stage=*/0,
+    effects.emplace_back(MemoryEffects::Read::get(),
+                         &getOperation()->getOpOperand(index), /*stage=*/0,
                          /*effectOnFullRegion=*/true,
                          SideEffects::DefaultResource::get());
   }
-  for (Value operand : getDpsInits()) {
-    if (!llvm::isa<MemRefType>(operand.getType()))
+
+  for (OpOperand &operand : getDpsInitsMutable()) {
+    if (!llvm::isa<MemRefType>(operand.get().getType()))
       continue;
-    effects.emplace_back(MemoryEffects::Read::get(), operand, /*stage=*/0,
+    effects.emplace_back(MemoryEffects::Read::get(), &operand, /*stage=*/0,
                          /*effectOnFullRegion=*/true,
                          SideEffects::DefaultResource::get());
-    effects.emplace_back(MemoryEffects::Write::get(), operand, /*stage=*/0,
+    effects.emplace_back(MemoryEffects::Write::get(), &operand, /*stage=*/0,
                          /*effectOnFullRegion=*/true,
                          SideEffects::DefaultResource::get());
   }

diff  --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp
index 768df0953fc5c..be4ab361083b9 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgMatchOps.cpp
@@ -115,9 +115,9 @@ DiagnosedSilenceableFailure transform::MatchStructuredOp::matchOperation(
 
 void transform::MatchStructuredOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getCurrent(), effects);
+  onlyReadsHandle(getCurrentMutable(), effects);
   onlyReadsPayload(effects);
-  producesHandle(getOutputs(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
 }
 
 LogicalResult transform::MatchStructuredOp::verify() {
@@ -707,7 +707,7 @@ LogicalResult transform::MatchStructuredResultOp::verify() {
 
 void transform::MatchStructuredYieldOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getHandles(), effects);
+  onlyReadsHandle(getHandlesMutable(), effects);
   onlyReadsPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
index 2807b3ce42abd..bc02788f9c441 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
@@ -369,12 +369,11 @@ void transform::BufferizeToAllocationOp::getEffects(
   if (getBufferizeDestinationOnly()) {
     // The destination is replaced with a newly allocated buffer, but the op
     // itself remains in place.
-    onlyReadsHandle(getTarget(), effects);
+    onlyReadsHandle(getTargetMutable(), effects);
   } else {
-    consumesHandle(getTarget(), effects);
+    consumesHandle(getTargetMutable(), effects);
   }
-  producesHandle(getAllocatedBuffer(), effects);
-  producesHandle(getNewOps(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -463,7 +462,7 @@ DiagnosedSilenceableFailure transform::DecomposeInterfaceOp::applyToOne(
 
 void transform::EliminateLinalgOpAnchoredEmptyTensorsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getTarget(), effects);
+  onlyReadsHandle(getTargetMutable(), effects);
   modifiesPayload(effects);
 }
 
@@ -1040,9 +1039,9 @@ transform::FuseIntoContainingOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::FuseIntoContainingOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getProducerOp(), effects);
-  onlyReadsHandle(getContainingOp(), effects);
-  producesHandle(getResults(), effects);
+  consumesHandle(getProducerOpMutable(), effects);
+  onlyReadsHandle(getContainingOpMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -1391,8 +1390,8 @@ DiagnosedSilenceableFailure transform::MultiTileSizesOp::applyToOne(
 
 void transform::MultiTileSizesOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getTarget(), effects);
-  producesHandle(getResults(), effects);
+  onlyReadsHandle(getTargetMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   if (isa<TransformParamTypeInterface>(getLowSize().getType()))
     onlyReadsPayload(effects);
   else
@@ -1478,9 +1477,9 @@ transform::PackOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::PackOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::consumesHandle(getTarget(), effects);
-  transform::onlyReadsHandle(getPackedSizes(), effects);
-  transform::producesHandle(getPackedOp(), effects);
+  transform::consumesHandle(getTargetMutable(), effects);
+  transform::onlyReadsHandle(getPackedSizesMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -1549,9 +1548,9 @@ SmallVector<OpFoldResult> PackGreedilyOp::getMixedMatmulPackedSizes() {
 
 void transform::PackGreedilyOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::consumesHandle(getTarget(), effects);
-  transform::onlyReadsHandle(getMatmulPackedSizes(), effects);
-  transform::producesHandle(getPackedOp(), effects);
+  transform::consumesHandle(getTargetMutable(), effects);
+  transform::onlyReadsHandle(getMatmulPackedSizesMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -1761,11 +1760,9 @@ void transform::PadOp::build(OpBuilder &b, OperationState &result, Value target,
 
 void PadOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  onlyReadsHandle(getPadToMultipleOf(), effects);
-  producesHandle(getPadded(), effects);
-  producesHandle(getPad(), effects);
-  producesHandle(getCopy(), effects);
+  consumesHandle(getTargetMutable(), effects);
+  onlyReadsHandle(getPadToMultipleOfMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -1992,9 +1989,9 @@ LogicalResult transform::HoistPadBuildPackingLoopNestOp::verify() {
 
 void transform::HoistPadBuildPackingLoopNestOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
-  transform::onlyReadsHandle(getLoop(), effects);
-  transform::producesHandle(getPackingLoop(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
+  transform::onlyReadsHandle(getLoopMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -2135,8 +2132,8 @@ transform::ReplaceOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::ReplaceOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  producesHandle(getReplacement(), effects);
+  consumesHandle(getTargetMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -2361,10 +2358,10 @@ SplitOp::apply(transform::TransformRewriter &rewriter,
 
 void SplitOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
+  consumesHandle(getTargetMutable(), effects);
   if (getDynamicSplitPoint())
-    onlyReadsHandle(getDynamicSplitPoint(), effects);
-  producesHandle(getResults(), effects);
+    onlyReadsHandle(getDynamicSplitPointMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -2831,10 +2828,9 @@ SmallVector<OpFoldResult> transform::TileUsingForOp::getMixedSizes() {
 
 void transform::TileUsingForOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  onlyReadsHandle(getDynamicSizes(), effects);
-  producesHandle(getTiledLinalgOp(), effects);
-  producesHandle(getLoops(), effects);
+  consumesHandle(getTargetMutable(), effects);
+  onlyReadsHandle(getDynamicSizesMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -2999,12 +2995,12 @@ DiagnosedSilenceableFailure transform::TileUsingForallOp::apply(
 
 void transform::TileUsingForallOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  onlyReadsHandle(getTileSizes(), effects);
-  onlyReadsHandle(getNumThreads(), effects);
-  onlyReadsHandle(getPackedNumThreads(), effects);
-  onlyReadsHandle(getPackedTileSizes(), effects);
-  producesHandle(getResults(), effects);
+  consumesHandle(getTargetMutable(), effects);
+  onlyReadsHandle(getTileSizesMutable(), effects);
+  onlyReadsHandle(getNumThreadsMutable(), effects);
+  onlyReadsHandle(getPackedNumThreadsMutable(), effects);
+  onlyReadsHandle(getPackedTileSizesMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -3182,8 +3178,8 @@ DiagnosedSilenceableFailure transform::VectorizeOp::apply(
 
 void transform::VectorizeOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  onlyReadsHandle(getVectorSizes(), effects);
+  consumesHandle(getTargetMutable(), effects);
+  onlyReadsHandle(getVectorSizesMutable(), effects);
   modifiesPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp b/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
index 3c9475c2d143a..8469e84c668cb 100644
--- a/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
+++ b/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
@@ -181,9 +181,8 @@ transform::MemRefAllocaToGlobalOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::MemRefAllocaToGlobalOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  producesHandle(getGlobal(), effects);
-  producesHandle(getGetGlobal(), effects);
-  consumesHandle(getAlloca(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
+  consumesHandle(getAllocaMutable(), effects);
   modifiesPayload(effects);
 }
 
@@ -249,7 +248,7 @@ transform::MemRefEraseDeadAllocAndStoresOp::applyToOne(
 
 void transform::MemRefEraseDeadAllocAndStoresOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }
 void transform::MemRefEraseDeadAllocAndStoresOp::build(OpBuilder &builder,

diff  --git a/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp b/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
index 4e256aea0be37..7d3d868b326c6 100644
--- a/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
+++ b/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
@@ -134,8 +134,8 @@ transform::ApplyNVGPUToNVVMConversionPatternsOp::verifyTypeConverter(
 
 void transform::CreateAsyncGroupsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::consumesHandle(getTarget(), effects);
-  transform::producesHandle(getResult(), effects);
+  transform::consumesHandle(getTargetMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::modifiesPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp b/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp
index 15b8aca5e267f..6919de393b668 100644
--- a/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp
+++ b/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp
@@ -330,7 +330,7 @@ DiagnosedSilenceableFailure transform::LoopPromoteIfOneIterationOp::applyToOne(
 
 void transform::LoopPromoteIfOneIterationOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
+  consumesHandle(getTargetMutable(), effects);
   modifiesPayload(effects);
 }
 
@@ -415,7 +415,7 @@ DiagnosedSilenceableFailure transform::TakeAssumedBranchOp::applyToOne(
 
 void transform::TakeAssumedBranchOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getTarget(), effects);
+  onlyReadsHandle(getTargetMutable(), effects);
   modifiesPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/Transform/IR/TransformOps.cpp b/mlir/lib/Dialect/Transform/IR/TransformOps.cpp
index 1a7ec030f0eb1..1efe708a5e349 100644
--- a/mlir/lib/Dialect/Transform/IR/TransformOps.cpp
+++ b/mlir/lib/Dialect/Transform/IR/TransformOps.cpp
@@ -211,8 +211,8 @@ transform::AlternativesOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::AlternativesOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getOperands(), effects);
-  producesHandle(getResults(), effects);
+  consumesHandle(getOperation()->getOpOperands(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   for (Region *region : getRegions()) {
     if (!region->empty())
       producesHandle(region->front().getArguments(), effects);
@@ -269,8 +269,8 @@ transform::AnnotateOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::AnnotateOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getTarget(), effects);
-  onlyReadsHandle(getParam(), effects);
+  onlyReadsHandle(getTargetMutable(), effects);
+  onlyReadsHandle(getParamMutable(), effects);
   modifiesPayload(effects);
 }
 
@@ -296,7 +296,7 @@ transform::ApplyCommonSubexpressionEliminationOp::applyToOne(
 
 void transform::ApplyCommonSubexpressionEliminationOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -361,7 +361,7 @@ DiagnosedSilenceableFailure transform::ApplyDeadCodeEliminationOp::applyToOne(
 
 void transform::ApplyDeadCodeEliminationOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -469,7 +469,7 @@ LogicalResult transform::ApplyPatternsOp::verify() {
 
 void transform::ApplyPatternsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -674,9 +674,9 @@ LogicalResult transform::ApplyConversionPatternsOp::verify() {
 void transform::ApplyConversionPatternsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   if (!getPreserveHandles()) {
-    transform::consumesHandle(getTarget(), effects);
+    transform::consumesHandle(getTargetMutable(), effects);
   } else {
-    transform::onlyReadsHandle(getTarget(), effects);
+    transform::onlyReadsHandle(getTargetMutable(), effects);
   }
   transform::modifiesPayload(effects);
 }
@@ -757,7 +757,7 @@ transform::ApplyLoopInvariantCodeMotionOp::applyToOne(
 
 void transform::ApplyLoopInvariantCodeMotionOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -820,8 +820,8 @@ transform::CastOp::applyToOne(transform::TransformRewriter &rewriter,
 void transform::CastOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   onlyReadsPayload(effects);
-  onlyReadsHandle(getInput(), effects);
-  producesHandle(getOutput(), effects);
+  onlyReadsHandle(getInputMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
 }
 
 bool transform::CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
@@ -964,8 +964,8 @@ transform::CollectMatchingOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::CollectMatchingOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getRoot(), effects);
-  producesHandle(getResults(), effects);
+  onlyReadsHandle(getRootMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   onlyReadsPayload(effects);
 }
 
@@ -1159,9 +1159,9 @@ void transform::ForeachMatchOp::getEffects(
     return modifiesPayload(effects);
   }
 
-  consumesHandle(getRoot(), effects);
-  onlyReadsHandle(getForwardedInputs(), effects);
-  producesHandle(getResults(), effects);
+  consumesHandle(getRootMutable(), effects);
+  onlyReadsHandle(getForwardedInputsMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -1458,7 +1458,7 @@ void transform::ForeachOp::getEffects(
   // NB: this `zip` should be `zip_equal` - while this op's verifier catches
   // arity errors, this method might get called before/in absence of `verify()`.
   for (auto &&[target, blockArg] :
-       llvm::zip(getTargets(), getBody().front().getArguments())) {
+       llvm::zip(getTargetsMutable(), getBody().front().getArguments())) {
     BlockArgument blockArgument = blockArg;
     if (any_of(getBody().front().without_terminator(), [&](Operation &op) {
           return isHandleConsumed(blockArgument,
@@ -1480,8 +1480,7 @@ void transform::ForeachOp::getEffects(
     onlyReadsPayload(effects);
   }
 
-  for (Value result : getResults())
-    producesHandle(result, effects);
+  producesHandle(getOperation()->getOpResults(), effects);
 }
 
 void transform::ForeachOp::getSuccessorRegions(
@@ -1733,8 +1732,8 @@ LogicalResult transform::GetResultOp::verify() {
 
 void transform::GetTypeOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getValue(), effects);
-  producesHandle(getResult(), effects);
+  onlyReadsHandle(getValueMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   onlyReadsPayload(effects);
 }
 
@@ -1833,12 +1832,14 @@ void transform::IncludeOp::getEffects(
   modifiesPayload(effects);
 
   // Results are always produced.
-  producesHandle(getResults(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
 
   // Adds default effects to operands and results. This will be added if
   // preconditions fail so the trait verifier doesn't complain about missing
   // effects and the real precondition failure is reported later on.
-  auto defaultEffects = [&] { onlyReadsHandle(getOperands(), effects); };
+  auto defaultEffects = [&] {
+    onlyReadsHandle(getOperation()->getOpOperands(), effects);
+  };
 
   // Bail if the callee is unknown. This may run as part of the verification
   // process before we verified the validity of the callee or of this op.
@@ -1859,9 +1860,9 @@ void transform::IncludeOp::getEffects(
 
   for (unsigned i = 0, e = getNumOperands(); i < e; ++i) {
     if (callee.getArgAttr(i, TransformDialect::kArgConsumedAttrName))
-      consumesHandle(getOperand(i), effects);
+      consumesHandle(getOperation()->getOpOperand(i), effects);
     else
-      onlyReadsHandle(getOperand(i), effects);
+      onlyReadsHandle(getOperation()->getOpOperand(i), effects);
   }
 }
 
@@ -2022,8 +2023,8 @@ transform::MatchParamCmpIOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::MatchParamCmpIOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getParam(), effects);
-  onlyReadsHandle(getReference(), effects);
+  onlyReadsHandle(getParamMutable(), effects);
+  onlyReadsHandle(getReferenceMutable(), effects);
 }
 
 //===----------------------------------------------------------------------===//
@@ -2098,8 +2099,8 @@ bool transform::MergeHandlesOp::allowsRepeatedHandleOperands() {
 
 void transform::MergeHandlesOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getHandles(), effects);
-  producesHandle(getResult(), effects);
+  onlyReadsHandle(getHandlesMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
 
   // There are no effects on the Payload IR as this is only a handle
   // manipulation.
@@ -2440,8 +2441,8 @@ transform::SplitHandleOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::SplitHandleOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getHandle(), effects);
-  producesHandle(getResults(), effects);
+  onlyReadsHandle(getHandleMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   // There are no effects on the Payload IR as this is only a handle
   // manipulation.
 }
@@ -2489,9 +2490,9 @@ transform::ReplicateOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::ReplicateOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getPattern(), effects);
-  onlyReadsHandle(getHandles(), effects);
-  producesHandle(getReplicated(), effects);
+  onlyReadsHandle(getPatternMutable(), effects);
+  onlyReadsHandle(getHandlesMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
 }
 
 //===----------------------------------------------------------------------===//
@@ -2802,7 +2803,7 @@ void transform::PrintOp::getEffects(
   // unconditionally casts to a specific type before verification could run
   // here.
   if (!getTargetMutable().empty())
-    onlyReadsHandle(getTargetMutable()[0].get(), effects);
+    onlyReadsHandle(getTargetMutable()[0], effects);
   onlyReadsPayload(effects);
 
   // There is no resource for stderr file descriptor, so just declare print
@@ -2830,7 +2831,7 @@ transform::VerifyOp::applyToOne(transform::TransformRewriter &rewriter,
 
 void transform::VerifyOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
 }
 
 //===----------------------------------------------------------------------===//
@@ -2839,5 +2840,5 @@ void transform::VerifyOp::getEffects(
 
 void transform::YieldOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getOperands(), effects);
+  onlyReadsHandle(getOperandsMutable(), effects);
 }

diff  --git a/mlir/lib/Dialect/Transform/IRDLExtension/IRDLExtensionOps.cpp b/mlir/lib/Dialect/Transform/IRDLExtension/IRDLExtensionOps.cpp
index 9cc579e65edf9..93b0bc591ca02 100644
--- a/mlir/lib/Dialect/Transform/IRDLExtension/IRDLExtensionOps.cpp
+++ b/mlir/lib/Dialect/Transform/IRDLExtension/IRDLExtensionOps.cpp
@@ -50,8 +50,8 @@ IRDLCollectMatchingOp::apply(TransformRewriter &rewriter,
 
 void IRDLCollectMatchingOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getRoot(), effects);
-  producesHandle(getMatched(), effects);
+  onlyReadsHandle(getRootMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   onlyReadsPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp b/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp
index b6a35e23a5d1f..ff02cb2372b4e 100644
--- a/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp
+++ b/mlir/lib/Dialect/Transform/Interfaces/TransformInterfaces.cpp
@@ -1603,7 +1603,8 @@ transform::detail::makeTransformStateForTesting(Region *region,
 /// Appends to `effects` the memory effect instances on `target` with the same
 /// resource and effect as the ones the operation `iface` having on `source`.
 static void
-remapEffects(MemoryEffectOpInterface iface, BlockArgument source, Value target,
+remapEffects(MemoryEffectOpInterface iface, BlockArgument source,
+             OpOperand *target,
              SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   SmallVector<MemoryEffects::EffectInstance> nestedEffects;
   iface.getEffectsOnValue(source, nestedEffects);
@@ -1614,7 +1615,7 @@ remapEffects(MemoryEffectOpInterface iface, BlockArgument source, Value target,
 /// Appends to `effects` the same effects as the operations of `block` have on
 /// block arguments but associated with `operands.`
 static void
-remapArgumentEffects(Block &block, ValueRange operands,
+remapArgumentEffects(Block &block, MutableArrayRef<OpOperand> operands,
                      SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   for (Operation &op : block) {
     auto iface = dyn_cast<MemoryEffectOpInterface>(&op);
@@ -1622,7 +1623,7 @@ remapArgumentEffects(Block &block, ValueRange operands,
       continue;
 
     for (auto &&[source, target] : llvm::zip(block.getArguments(), operands)) {
-      remapEffects(iface, source, target, effects);
+      remapEffects(iface, source, &target, effects);
     }
 
     SmallVector<MemoryEffects::EffectInstance> nestedEffects;
@@ -1635,8 +1636,8 @@ remapArgumentEffects(Block &block, ValueRange operands,
 void transform::detail::getPotentialTopLevelEffects(
     Operation *operation, Value root, Block &body,
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(operation->getOperands(), effects);
-  transform::producesHandle(operation->getResults(), effects);
+  transform::onlyReadsHandle(operation->getOpOperands(), effects);
+  transform::producesHandle(operation->getOpResults(), effects);
 
   if (!root) {
     for (Operation &op : body) {
@@ -1652,7 +1653,7 @@ void transform::detail::getPotentialTopLevelEffects(
 
   // Carry over all effects on arguments of the entry block as those on the
   // operands, this is the same value just remapped.
-  remapArgumentEffects(body, operation->getOperands(), effects);
+  remapArgumentEffects(body, operation->getOpOperands(), effects);
 }
 
 LogicalResult transform::detail::mapPossibleTopLevelTransformOpBlockArguments(
@@ -1761,10 +1762,10 @@ void transform::detail::getParamProducerTransformOpTraitEffects(
     Operation *op, SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   producesHandle(op->getResults(), effects);
   bool hasPayloadOperands = false;
-  for (Value operand : op->getOperands()) {
+  for (OpOperand &operand : op->getOpOperands()) {
     onlyReadsHandle(operand, effects);
     if (llvm::isa<TransformHandleTypeInterface,
-                  TransformValueHandleTypeInterface>(operand.getType()))
+                  TransformValueHandleTypeInterface>(operand.get().getType()))
       hasPayloadOperands = true;
   }
   if (hasPayloadOperands)
@@ -1796,12 +1797,12 @@ transform::detail::verifyParamProducerTransformOpTrait(Operation *op) {
 //===----------------------------------------------------------------------===//
 
 void transform::consumesHandle(
-    ValueRange handles,
+    MutableArrayRef<OpOperand> handles,
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  for (Value handle : handles) {
-    effects.emplace_back(MemoryEffects::Read::get(), handle,
+  for (OpOperand &handle : handles) {
+    effects.emplace_back(MemoryEffects::Read::get(), &handle,
                          TransformMappingResource::get());
-    effects.emplace_back(MemoryEffects::Free::get(), handle,
+    effects.emplace_back(MemoryEffects::Free::get(), &handle,
                          TransformMappingResource::get());
   }
 }
@@ -1826,9 +1827,20 @@ bool transform::isHandleConsumed(Value handle,
 }
 
 void transform::producesHandle(
-    ValueRange handles,
+    ResultRange handles,
+    SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+  for (OpResult handle : handles) {
+    effects.emplace_back(MemoryEffects::Allocate::get(), handle,
+                         TransformMappingResource::get());
+    effects.emplace_back(MemoryEffects::Write::get(), handle,
+                         TransformMappingResource::get());
+  }
+}
+
+void transform::producesHandle(
+    MutableArrayRef<BlockArgument> handles,
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  for (Value handle : handles) {
+  for (BlockArgument handle : handles) {
     effects.emplace_back(MemoryEffects::Allocate::get(), handle,
                          TransformMappingResource::get());
     effects.emplace_back(MemoryEffects::Write::get(), handle,
@@ -1837,10 +1849,10 @@ void transform::producesHandle(
 }
 
 void transform::onlyReadsHandle(
-    ValueRange handles,
+    MutableArrayRef<OpOperand> handles,
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  for (Value handle : handles) {
-    effects.emplace_back(MemoryEffects::Read::get(), handle,
+  for (OpOperand &handle : handles) {
+    effects.emplace_back(MemoryEffects::Read::get(), &handle,
                          TransformMappingResource::get());
   }
 }

diff  --git a/mlir/lib/Dialect/Transform/LoopExtension/LoopExtensionOps.cpp b/mlir/lib/Dialect/Transform/LoopExtension/LoopExtensionOps.cpp
index c992fd15946f3..34d6221d15fb0 100644
--- a/mlir/lib/Dialect/Transform/LoopExtension/LoopExtensionOps.cpp
+++ b/mlir/lib/Dialect/Transform/LoopExtension/LoopExtensionOps.cpp
@@ -31,6 +31,6 @@ DiagnosedSilenceableFailure transform::HoistLoopInvariantSubsetsOp::applyToOne(
 
 void transform::HoistLoopInvariantSubsetsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }

diff  --git a/mlir/lib/Dialect/Transform/PDLExtension/PDLExtensionOps.cpp b/mlir/lib/Dialect/Transform/PDLExtension/PDLExtensionOps.cpp
index 5585afc1caaff..85f61245eb734 100644
--- a/mlir/lib/Dialect/Transform/PDLExtension/PDLExtensionOps.cpp
+++ b/mlir/lib/Dialect/Transform/PDLExtension/PDLExtensionOps.cpp
@@ -158,8 +158,8 @@ transform::PDLMatchOp::apply(transform::TransformRewriter &rewriter,
 
 void transform::PDLMatchOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  onlyReadsHandle(getRoot(), effects);
-  producesHandle(getMatched(), effects);
+  onlyReadsHandle(getRootMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   onlyReadsPayload(effects);
 }
 

diff  --git a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
index 89805d90ea1b0..6734c80f2760d 100644
--- a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
+++ b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
@@ -4232,7 +4232,7 @@ void TransferReadOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
   if (llvm::isa<MemRefType>(getShapedType()))
-    effects.emplace_back(MemoryEffects::Read::get(), getSource(),
+    effects.emplace_back(MemoryEffects::Read::get(), &getSourceMutable(),
                          SideEffects::DefaultResource::get());
 }
 
@@ -4606,7 +4606,7 @@ void TransferWriteOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
   if (llvm::isa<MemRefType>(getShapedType()))
-    effects.emplace_back(MemoryEffects::Write::get(), getSource(),
+    effects.emplace_back(MemoryEffects::Write::get(), &getSourceMutable(),
                          SideEffects::DefaultResource::get());
 }
 

diff  --git a/mlir/lib/Interfaces/SideEffectInterfaces.cpp b/mlir/lib/Interfaces/SideEffectInterfaces.cpp
index 967225333ae04..c9feb001a1984 100644
--- a/mlir/lib/Interfaces/SideEffectInterfaces.cpp
+++ b/mlir/lib/Interfaces/SideEffectInterfaces.cpp
@@ -103,6 +103,28 @@ static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) {
   return true;
 }
 
+template <typename EffectTy>
+bool mlir::hasSingleEffect(Operation *op) {
+  auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
+  if (!memOp)
+    return false;
+  SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
+  memOp.getEffects(effects);
+  bool hasSingleEffectOnVal = false;
+  // Iterate through `effects` and check if an effect of type `EffectTy` and
+  // only of that type is present.
+  for (auto &effect : effects) {
+    hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
+    if (!hasSingleEffectOnVal)
+      return false;
+  }
+  return hasSingleEffectOnVal;
+}
+template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *);
+template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *);
+template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *);
+template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *);
+
 template <typename EffectTy>
 bool mlir::hasSingleEffect(Operation *op, Value value) {
   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
@@ -112,10 +134,9 @@ bool mlir::hasSingleEffect(Operation *op, Value value) {
   memOp.getEffects(effects);
   bool hasSingleEffectOnVal = false;
   // Iterate through `effects` and check if an effect of type `EffectTy` and
-  // only of that type is present. A `value` to check the effect on may or may
-  // not have been provided.
+  // only of that type is present.
   for (auto &effect : effects) {
-    if (value && effect.getValue() != value)
+    if (effect.getValue() != value)
       continue;
     hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
     if (!hasSingleEffectOnVal)
@@ -125,10 +146,84 @@ bool mlir::hasSingleEffect(Operation *op, Value value) {
 }
 
 template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *,
-                                                             Value);
-template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *, Value);
-template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *, Value);
-template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *, Value);
+                                                             Value value);
+template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *,
+                                                         Value value);
+template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *,
+                                                         Value value);
+template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *,
+                                                          Value value);
+
+template <typename ValueTy, typename EffectTy>
+bool mlir::hasSingleEffect(Operation *op, ValueTy value) {
+  auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
+  if (!memOp)
+    return false;
+  SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
+  memOp.getEffects(effects);
+  bool hasSingleEffectOnVal = false;
+  // Iterate through `effects` and check if an effect of type `EffectTy` and
+  // only of that type is present on value.
+  for (auto &effect : effects) {
+    if (effect.getEffectValue<ValueTy>() != value)
+      continue;
+    hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
+    if (!hasSingleEffectOnVal)
+      return false;
+  }
+  return hasSingleEffectOnVal;
+}
+
+template bool
+mlir::hasSingleEffect<OpOperand *, MemoryEffects::Allocate>(Operation *,
+                                                            OpOperand *);
+template bool
+mlir::hasSingleEffect<OpOperand *, MemoryEffects::Free>(Operation *,
+                                                        OpOperand *);
+template bool
+mlir::hasSingleEffect<OpOperand *, MemoryEffects::Read>(Operation *,
+                                                        OpOperand *);
+template bool
+mlir::hasSingleEffect<OpOperand *, MemoryEffects::Write>(Operation *,
+                                                         OpOperand *);
+template bool
+mlir::hasSingleEffect<OpResult, MemoryEffects::Allocate>(Operation *, OpResult);
+template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Free>(Operation *,
+                                                                   OpResult);
+template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Read>(Operation *,
+                                                                   OpResult);
+template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Write>(Operation *,
+                                                                    OpResult);
+template bool
+mlir::hasSingleEffect<BlockArgument, MemoryEffects::Allocate>(Operation *,
+                                                              BlockArgument);
+template bool
+mlir::hasSingleEffect<BlockArgument, MemoryEffects::Free>(Operation *,
+                                                          BlockArgument);
+template bool
+mlir::hasSingleEffect<BlockArgument, MemoryEffects::Read>(Operation *,
+                                                          BlockArgument);
+template bool
+mlir::hasSingleEffect<BlockArgument, MemoryEffects::Write>(Operation *,
+                                                           BlockArgument);
+
+template <typename... EffectTys>
+bool mlir::hasEffect(Operation *op) {
+  auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
+  if (!memOp)
+    return false;
+  SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
+  memOp.getEffects(effects);
+  return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
+    return isa<EffectTys...>(effect.getEffect());
+  });
+}
+template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *);
+template bool mlir::hasEffect<MemoryEffects::Free>(Operation *);
+template bool mlir::hasEffect<MemoryEffects::Read>(Operation *);
+template bool mlir::hasEffect<MemoryEffects::Write>(Operation *);
+template bool
+mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *);
 
 template <typename... EffectTys>
 bool mlir::hasEffect(Operation *op, Value value) {
@@ -138,17 +233,70 @@ bool mlir::hasEffect(Operation *op, Value value) {
   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
   memOp.getEffects(effects);
   return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
-    if (value && effect.getValue() != value)
+    if (effect.getValue() != value)
+      return false;
+    return isa<EffectTys...>(effect.getEffect());
+  });
+}
+template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *,
+                                                       Value value);
+template bool mlir::hasEffect<MemoryEffects::Free>(Operation *, Value value);
+template bool mlir::hasEffect<MemoryEffects::Read>(Operation *, Value value);
+template bool mlir::hasEffect<MemoryEffects::Write>(Operation *, Value value);
+template bool
+mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *,
+                                                           Value value);
+
+template <typename ValueTy, typename... EffectTys>
+bool mlir::hasEffect(Operation *op, ValueTy value) {
+  auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
+  if (!memOp)
+    return false;
+  SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
+  memOp.getEffects(effects);
+  return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
+    if (effect.getEffectValue<ValueTy>() != value)
       return false;
     return isa<EffectTys...>(effect.getEffect());
   });
 }
-template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *, Value);
-template bool mlir::hasEffect<MemoryEffects::Free>(Operation *, Value);
-template bool mlir::hasEffect<MemoryEffects::Read>(Operation *, Value);
-template bool mlir::hasEffect<MemoryEffects::Write>(Operation *, Value);
 template bool
-mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *, Value);
+mlir::hasEffect<OpOperand *, MemoryEffects::Allocate>(Operation *, OpOperand *);
+template bool mlir::hasEffect<OpOperand *, MemoryEffects::Free>(Operation *,
+                                                                OpOperand *);
+template bool mlir::hasEffect<OpOperand *, MemoryEffects::Read>(Operation *,
+                                                                OpOperand *);
+template bool mlir::hasEffect<OpOperand *, MemoryEffects::Write>(Operation *,
+                                                                 OpOperand *);
+template bool
+mlir::hasEffect<OpOperand *, MemoryEffects::Write, MemoryEffects::Free>(
+    Operation *, OpOperand *);
+
+template bool mlir::hasEffect<OpResult, MemoryEffects::Allocate>(Operation *,
+                                                                 OpResult);
+template bool mlir::hasEffect<OpResult, MemoryEffects::Free>(Operation *,
+                                                             OpResult);
+template bool mlir::hasEffect<OpResult, MemoryEffects::Read>(Operation *,
+                                                             OpResult);
+template bool mlir::hasEffect<OpResult, MemoryEffects::Write>(Operation *,
+                                                              OpResult);
+template bool
+mlir::hasEffect<OpResult, MemoryEffects::Write, MemoryEffects::Free>(
+    Operation *, OpResult);
+
+template bool
+mlir::hasEffect<BlockArgument, MemoryEffects::Allocate>(Operation *,
+                                                        BlockArgument);
+template bool
+mlir::hasEffect<BlockArgument, MemoryEffects::Free>(Operation *, BlockArgument);
+template bool
+mlir::hasEffect<BlockArgument, MemoryEffects::Read>(Operation *, BlockArgument);
+template bool
+mlir::hasEffect<BlockArgument, MemoryEffects::Write>(Operation *,
+                                                     BlockArgument);
+template bool
+mlir::hasEffect<BlockArgument, MemoryEffects::Write, MemoryEffects::Free>(
+    Operation *, BlockArgument);
 
 bool mlir::wouldOpBeTriviallyDead(Operation *op) {
   if (op->mightHaveTrait<OpTrait::IsTerminator>())

diff  --git a/mlir/test/Dialect/Bufferization/side-effects.mlir b/mlir/test/Dialect/Bufferization/side-effects.mlir
index 680219a48b450..841490e9f3234 100644
--- a/mlir/test/Dialect/Bufferization/side-effects.mlir
+++ b/mlir/test/Dialect/Bufferization/side-effects.mlir
@@ -1,10 +1,9 @@
 // RUN: mlir-opt %s --test-side-effects --verify-diagnostics
 
 func.func @test_side_effects(%arg0: memref<2xi32>) -> memref<2xi32> {
-  // expected-remark @below {{found an instance of 'read' on a value, on resource '<Default>'}}
-  // expected-remark @below {{found an instance of 'write' on a value, on resource '<Default>'}}
-  // expected-remark @below {{found an instance of 'allocate' on a value, on resource '<Default>'}}
+  // expected-remark @below {{found an instance of 'read' on a op operand, on resource '<Default>'}}
+  // expected-remark @below {{found an instance of 'write' on a op result, on resource '<Default>'}}
+  // expected-remark @below {{found an instance of 'allocate' on a op result, on resource '<Default>'}}
   %0 = bufferization.clone %arg0 : memref<2xi32> to memref<2xi32>
-  // expected-remark @below {{operation has no memory effects}}
   return %0 : memref<2xi32>
 }

diff  --git a/mlir/test/IR/test-side-effects.mlir b/mlir/test/IR/test-side-effects.mlir
index 947faff99d265..efce4856041a1 100644
--- a/mlir/test/IR/test-side-effects.mlir
+++ b/mlir/test/IR/test-side-effects.mlir
@@ -1,38 +1,60 @@
 // RUN: mlir-opt %s -test-side-effects -verify-diagnostics
 
-// expected-remark at +1 {{operation has no memory effects}}
-%0 = "test.side_effect_op"() {} : () -> i32
+func.func @side_effect(%arg : index) {
+  // expected-remark at +1 {{operation has no memory effects}}
+  %0 = "test.side_effect_op"() {} : () -> i32
+  
+  // expected-remark at +2 {{found an instance of 'read' on resource '<Default>'}}
+  // expected-remark at +1 {{found an instance of 'free' on resource '<Default>'}}
+  %1 = "test.side_effect_op"() {effects = [
+    {effect="read"}, {effect="free"}
+  ]} : () -> i32
+  
+  // expected-remark at +1 {{found an instance of 'write' on resource '<Test>'}}
+  %2 = "test.side_effect_op"() {effects = [
+    {effect="write", test_resource}
+  ]} : () -> i32
+  
+  // expected-remark at +1 {{found an instance of 'allocate' on a op result, on resource '<Test>'}}
+  %3 = "test.side_effect_op"() {effects = [
+    {effect="allocate", on_result, test_resource}
+  ]} : () -> i32
+  
+  // expected-remark at +1 {{found an instance of 'read' on a symbol '@foo_ref', on resource '<Test>'}}
+  "test.side_effect_op"() {effects = [
+    {effect="read", on_reference = @foo_ref, test_resource}
+  ]} : () -> i32
+  
+  // No _memory_ effects, but a parametric test effect.
+  // expected-remark at +2 {{operation has no memory effects}}
+  // expected-remark at +1 {{found a parametric effect with affine_map<(d0, d1) -> (d1, d0)>}}
+  %4 = "test.side_effect_op"() {
+    effect_parameter = affine_map<(i, j) -> (j, i)>
+  } : () -> i32
+  
+  // Check with this unregistered operation to test the fallback on the dialect.
+  // expected-remark at +1 {{found a parametric effect with affine_map<(d0, d1) -> (d1, d0)>}}
+  %5 = "test.unregistered_side_effect_op"() {
+    effect_parameter = affine_map<(i, j) -> (j, i)>
+  } : () -> i32
 
-// expected-remark at +2 {{found an instance of 'read' on resource '<Default>'}}
-// expected-remark at +1 {{found an instance of 'free' on resource '<Default>'}}
-%1 = "test.side_effect_op"() {effects = [
-  {effect="read"}, {effect="free"}
-]} : () -> i32
+  // expected-remark at +1 {{found an instance of 'allocate' on a op operand, on resource '<Test>'}}
+  %6 = test.side_effect_with_region_op (%arg) {
+  ^bb0(%arg0 : index):
+    test.region_yield %arg0 : index 
+  } {effects = [ {effect="allocate", on_operand, test_resource} ]} : index -> index
 
-// expected-remark at +1 {{found an instance of 'write' on resource '<Test>'}}
-%2 = "test.side_effect_op"() {effects = [
-  {effect="write", test_resource}
-]} : () -> i32
+  // expected-remark at +1 {{found an instance of 'allocate' on a op result, on resource '<Test>'}}
+  %7 = test.side_effect_with_region_op (%arg) {
+  ^bb0(%arg0 : index):
+    test.region_yield %arg0 : index 
+  } {effects = [ {effect="allocate", on_result, test_resource} ]} : index -> index
 
-// expected-remark at +1 {{found an instance of 'allocate' on a value, on resource '<Test>'}}
-%3 = "test.side_effect_op"() {effects = [
-  {effect="allocate", on_result, test_resource}
-]} : () -> i32
+  // expected-remark at +1 {{found an instance of 'allocate' on a block argument, on resource '<Test>'}}
+  %8 = test.side_effect_with_region_op (%arg) {
+  ^bb0(%arg0 : index):
+    test.region_yield %arg0 : index 
+  } {effects = [ {effect="allocate", on_argument, test_resource} ]} : index -> index
 
-// expected-remark at +1 {{found an instance of 'read' on a symbol '@foo_ref', on resource '<Test>'}}
-"test.side_effect_op"() {effects = [
-  {effect="read", on_reference = @foo_ref, test_resource}
-]} : () -> i32
-
-// No _memory_ effects, but a parametric test effect.
-// expected-remark at +2 {{operation has no memory effects}}
-// expected-remark at +1 {{found a parametric effect with affine_map<(d0, d1) -> (d1, d0)>}}
-%4 = "test.side_effect_op"() {
-  effect_parameter = affine_map<(i, j) -> (j, i)>
-} : () -> i32
-
-// Check with this unregistered operation to test the fallback on the dialect.
-// expected-remark at +1 {{found a parametric effect with affine_map<(d0, d1) -> (d1, d0)>}}
-%5 = "test.unregistered_side_effect_op"() {
-  effect_parameter = affine_map<(i, j) -> (j, i)>
-} : () -> i32
+  func.return 
+}

diff  --git a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
index b058a8e1abbcb..9b36748b54dbd 100644
--- a/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
+++ b/mlir/test/lib/Dialect/Test/TestOpDefs.cpp
@@ -329,8 +329,6 @@ void SideEffectOp::getEffects(
   if (!effectsAttr)
     return;
 
-  // If there is one, it is an array of dictionary attributes that hold
-  // information on the effects of this operation.
   for (Attribute element : effectsAttr) {
     DictionaryAttr effectElement = cast<DictionaryAttr>(element);
 
@@ -350,7 +348,7 @@ void SideEffectOp::getEffects(
 
     // Check for a result to affect.
     if (effectElement.get("on_result"))
-      effects.emplace_back(effect, getResult(), resource);
+      effects.emplace_back(effect, getOperation()->getOpResults()[0], resource);
     else if (Attribute ref = effectElement.get("on_reference"))
       effects.emplace_back(effect, cast<SymbolRefAttr>(ref), resource);
     else
@@ -363,6 +361,51 @@ void SideEffectOp::getEffects(
   testSideEffectOpGetEffect(getOperation(), effects);
 }
 
+void SideEffectWithRegionOp::getEffects(
+    SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+  // Check for an effects attribute on the op instance.
+  ArrayAttr effectsAttr = (*this)->getAttrOfType<ArrayAttr>("effects");
+  if (!effectsAttr)
+    return;
+
+  for (Attribute element : effectsAttr) {
+    DictionaryAttr effectElement = cast<DictionaryAttr>(element);
+
+    // Get the specific memory effect.
+    MemoryEffects::Effect *effect =
+        StringSwitch<MemoryEffects::Effect *>(
+            cast<StringAttr>(effectElement.get("effect")).getValue())
+            .Case("allocate", MemoryEffects::Allocate::get())
+            .Case("free", MemoryEffects::Free::get())
+            .Case("read", MemoryEffects::Read::get())
+            .Case("write", MemoryEffects::Write::get());
+
+    // Check for a non-default resource to use.
+    SideEffects::Resource *resource = SideEffects::DefaultResource::get();
+    if (effectElement.get("test_resource"))
+      resource = TestResource::get();
+
+    // Check for a result to affect.
+    if (effectElement.get("on_result"))
+      effects.emplace_back(effect, getOperation()->getOpResults()[0], resource);
+    else if (effectElement.get("on_operand"))
+      effects.emplace_back(effect, &getOperation()->getOpOperands()[0],
+                           resource);
+    else if (effectElement.get("on_argument"))
+      effects.emplace_back(effect, getOperation()->getRegion(0).getArgument(0),
+                           resource);
+    else if (Attribute ref = effectElement.get("on_reference"))
+      effects.emplace_back(effect, cast<SymbolRefAttr>(ref), resource);
+    else
+      effects.emplace_back(effect, resource);
+  }
+}
+
+void SideEffectWithRegionOp::getEffects(
+    SmallVectorImpl<TestEffects::EffectInstance> &effects) {
+  testSideEffectOpGetEffect(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // StringAttrPrettyNameOp
 //===----------------------------------------------------------------------===//
@@ -1027,7 +1070,7 @@ void ReadBufferOp::getEffects(
     SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
         &effects) {
   // The buffer operand is read.
-  effects.emplace_back(MemoryEffects::Read::get(), getBuffer(),
+  effects.emplace_back(MemoryEffects::Read::get(), &getBufferMutable(),
                        SideEffects::DefaultResource::get());
   // The buffer contents are dumped.
   effects.emplace_back(MemoryEffects::Write::get(),

diff  --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td
index 9d7e0a7928ab8..cce926d2cf63d 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -2105,6 +2105,17 @@ def SideEffectOp : TEST_Op<"side_effect_op",
   let results = (outs AnyType:$result);
 }
 
+def SideEffectWithRegionOp : TEST_Op<"side_effect_with_region_op",
+    [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
+     DeclareOpInterfaceMethods<TestEffectOpInterface>]> {
+  let arguments = (ins AnyType:$operand);
+  let results = (outs AnyType:$result);
+  let regions = (region AnyRegion:$region);
+  let assemblyFormat = [{
+    `(` $operand`)` $region attr-dict `:`  type($operand)  `->` type($result)
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // Test CopyOpInterface
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp b/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp
index 2b39668035bc0..b8a4b9470d736 100644
--- a/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp
+++ b/mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp
@@ -128,8 +128,8 @@ mlir::test::TestProduceSelfHandleOrForwardOperandOp::apply(
 void mlir::test::TestProduceSelfHandleOrForwardOperandOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   if (getOperand())
-    transform::onlyReadsHandle(getOperand(), effects);
-  transform::producesHandle(getRes(), effects);
+    transform::onlyReadsHandle(getOperandMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
 }
 
 DiagnosedSilenceableFailure
@@ -142,8 +142,8 @@ mlir::test::TestProduceValueHandleToSelfOperand::apply(
 
 void mlir::test::TestProduceValueHandleToSelfOperand::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getIn(), effects);
-  transform::producesHandle(getOut(), effects);
+  transform::onlyReadsHandle(getInMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::onlyReadsPayload(effects);
 }
 
@@ -160,8 +160,8 @@ mlir::test::TestProduceValueHandleToResult::applyToOne(
 
 void mlir::test::TestProduceValueHandleToResult::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getIn(), effects);
-  transform::producesHandle(getOut(), effects);
+  transform::onlyReadsHandle(getInMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::onlyReadsPayload(effects);
 }
 
@@ -181,8 +181,8 @@ mlir::test::TestProduceValueHandleToArgumentOfParentBlock::applyToOne(
 
 void mlir::test::TestProduceValueHandleToArgumentOfParentBlock::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getIn(), effects);
-  transform::producesHandle(getOut(), effects);
+  transform::onlyReadsHandle(getInMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::onlyReadsPayload(effects);
 }
 
@@ -199,9 +199,9 @@ mlir::test::TestConsumeOperand::apply(transform::TransformRewriter &rewriter,
 
 void mlir::test::TestConsumeOperand::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::consumesHandle(getOperand(), effects);
+  transform::consumesHandle(getOperation()->getOpOperands(), effects);
   if (getSecondOperand())
-    transform::consumesHandle(getSecondOperand(), effects);
+    transform::consumesHandle(getSecondOperandMutable(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -223,7 +223,7 @@ DiagnosedSilenceableFailure mlir::test::TestConsumeOperandOfOpKindOrFail::apply(
 
 void mlir::test::TestConsumeOperandOfOpKindOrFail::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::consumesHandle(getOperand(), effects);
+  transform::consumesHandle(getOperation()->getOpOperands(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -242,7 +242,7 @@ mlir::test::TestSucceedIfOperandOfOpKind::matchOperation(
 
 void mlir::test::TestSucceedIfOperandOfOpKind::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getOperand(), effects);
+  transform::onlyReadsHandle(getOperation()->getOpOperands(), effects);
   transform::onlyReadsPayload(effects);
 }
 
@@ -281,7 +281,7 @@ mlir::test::TestCheckIfTestExtensionPresentOp::apply(
 
 void mlir::test::TestCheckIfTestExtensionPresentOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getOperand(), effects);
+  transform::onlyReadsHandle(getOperation()->getOpOperands(), effects);
   transform::onlyReadsPayload(effects);
 }
 
@@ -302,8 +302,8 @@ DiagnosedSilenceableFailure mlir::test::TestRemapOperandPayloadToSelfOp::apply(
 
 void mlir::test::TestRemapOperandPayloadToSelfOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getOperand(), effects);
-  transform::producesHandle(getOut(), effects);
+  transform::onlyReadsHandle(getOperation()->getOpOperands(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::onlyReadsPayload(effects);
 }
 
@@ -356,7 +356,7 @@ DiagnosedSilenceableFailure mlir::test::TestEmitRemarkAndEraseOperandOp::apply(
 
 void mlir::test::TestEmitRemarkAndEraseOperandOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::consumesHandle(getTarget(), effects);
+  transform::consumesHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -425,8 +425,8 @@ mlir::test::TestCopyPayloadOp::apply(transform::TransformRewriter &rewriter,
 
 void mlir::test::TestCopyPayloadOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getHandle(), effects);
-  transform::producesHandle(getCopy(), effects);
+  transform::onlyReadsHandle(getHandleMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
   transform::onlyReadsPayload(effects);
 }
 
@@ -460,7 +460,7 @@ DiagnosedSilenceableFailure mlir::transform::TestDialectParamType::checkPayload(
 
 void mlir::test::TestReportNumberOfTrackedHandlesNestedUnder::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
 }
 
 DiagnosedSilenceableFailure
@@ -530,9 +530,8 @@ mlir::test::TestProduceParamOp::apply(transform::TransformRewriter &rewriter,
 
 void mlir::test::TestProduceTransformParamOrForwardOperandOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getIn(), effects);
-  transform::producesHandle(getOut(), effects);
-  transform::producesHandle(getParam(), effects);
+  transform::onlyReadsHandle(getInMutable(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
 }
 
 DiagnosedSilenceableFailure
@@ -560,7 +559,7 @@ mlir::test::TestProduceTransformParamOrForwardOperandOp::applyToOne(
 
 void mlir::test::TestProduceNullPayloadOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::producesHandle(getOut(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
 }
 
 DiagnosedSilenceableFailure mlir::test::TestProduceNullPayloadOp::apply(
@@ -580,7 +579,7 @@ DiagnosedSilenceableFailure mlir::test::TestProduceEmptyPayloadOp::apply(
 
 void mlir::test::TestProduceNullParamOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::producesHandle(getOut(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
 }
 
 DiagnosedSilenceableFailure mlir::test::TestProduceNullParamOp::apply(
@@ -592,7 +591,7 @@ DiagnosedSilenceableFailure mlir::test::TestProduceNullParamOp::apply(
 
 void mlir::test::TestProduceNullValueOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::producesHandle(getOut(), effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
 }
 
 DiagnosedSilenceableFailure mlir::test::TestProduceNullValueOp::apply(
@@ -605,12 +604,15 @@ DiagnosedSilenceableFailure mlir::test::TestProduceNullValueOp::apply(
 void mlir::test::TestRequiredMemoryEffectsOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
   if (getHasOperandEffect())
-    transform::consumesHandle(getIn(), effects);
+    transform::consumesHandle(getInMutable(), effects);
 
-  if (getHasResultEffect())
-    transform::producesHandle(getOut(), effects);
-  else
-    transform::onlyReadsHandle(getOut(), effects);
+  if (getHasResultEffect()) {
+    transform::producesHandle(getOperation()->getOpResults(), effects);
+  } else {
+    effects.emplace_back(MemoryEffects::Read::get(),
+                         llvm::cast<OpResult>(getOut()),
+                         transform::TransformMappingResource::get());
+  }
 
   if (getModifiesPayload())
     transform::modifiesPayload(effects);
@@ -625,14 +627,13 @@ DiagnosedSilenceableFailure mlir::test::TestRequiredMemoryEffectsOp::apply(
 
 void mlir::test::TestTrackedRewriteOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getIn(), effects);
+  transform::onlyReadsHandle(getInMutable(), effects);
   transform::modifiesPayload(effects);
 }
 
 void mlir::test::TestDummyPayloadOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  for (OpResult result : getResults())
-    transform::producesHandle(result, effects);
+  transform::producesHandle(getOperation()->getOpResults(), effects);
 }
 
 LogicalResult mlir::test::TestDummyPayloadOp::verify() {
@@ -719,7 +720,7 @@ void mlir::test::ApplyTestPatternsOp::populatePatterns(
 
 void mlir::test::TestReEnterRegionOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::consumesHandle(getOperands(), effects);
+  transform::consumesHandle(getOperation()->getOpOperands(), effects);
   transform::modifiesPayload(effects);
 }
 
@@ -782,8 +783,8 @@ DiagnosedSilenceableFailure mlir::test::TestNotifyPayloadOpReplacedOp::apply(
 
 void mlir::test::TestNotifyPayloadOpReplacedOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getOriginal(), effects);
-  transform::onlyReadsHandle(getReplacement(), effects);
+  transform::onlyReadsHandle(getOriginalMutable(), effects);
+  transform::onlyReadsHandle(getReplacementMutable(), effects);
 }
 
 DiagnosedSilenceableFailure mlir::test::TestProduceInvalidIR::applyToOne(
@@ -799,7 +800,7 @@ DiagnosedSilenceableFailure mlir::test::TestProduceInvalidIR::applyToOne(
 
 void mlir::test::TestProduceInvalidIR::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  transform::onlyReadsHandle(getTarget(), effects);
+  transform::onlyReadsHandle(getTargetMutable(), effects);
   transform::modifiesPayload(effects);
 }
 

diff  --git a/mlir/test/lib/IR/TestSideEffects.cpp b/mlir/test/lib/IR/TestSideEffects.cpp
index 8e13dd9751398..7e01509d55685 100644
--- a/mlir/test/lib/IR/TestSideEffects.cpp
+++ b/mlir/test/lib/IR/TestSideEffects.cpp
@@ -29,6 +29,10 @@ struct SideEffectsPass
       effects.clear();
       op.getEffects(effects);
 
+      if (op->hasTrait<OpTrait::IsTerminator>()) {
+        return;
+      }
+
       // Check to see if this operation has any memory effects.
       if (effects.empty()) {
         op.emitRemark() << "operation has no memory effects";
@@ -47,9 +51,14 @@ struct SideEffectsPass
         else if (isa<MemoryEffects::Write>(instance.getEffect()))
           diag << "'write'";
 
-        if (instance.getValue())
-          diag << " on a value,";
-        else if (SymbolRefAttr symbolRef = instance.getSymbolRef())
+        if (instance.getValue()) {
+          if (instance.getEffectValue<OpOperand *>())
+            diag << " on a op operand,";
+          else if (instance.getEffectValue<OpResult>())
+            diag << " on a op result,";
+          else if (instance.getEffectValue<BlockArgument>())
+            diag << " on a block argument,";
+        } else if (SymbolRefAttr symbolRef = instance.getSymbolRef())
           diag << " on a symbol '" << symbolRef << "',";
 
         diag << " on resource '" << instance.getResource()->getName() << "'";

diff  --git a/mlir/test/lib/Interfaces/TilingInterface/TestTilingInterfaceTransformOps.cpp b/mlir/test/lib/Interfaces/TilingInterface/TestTilingInterfaceTransformOps.cpp
index 833fb3cc65b81..8f206d9077272 100644
--- a/mlir/test/lib/Interfaces/TilingInterface/TestTilingInterfaceTransformOps.cpp
+++ b/mlir/test/lib/Interfaces/TilingInterface/TestTilingInterfaceTransformOps.cpp
@@ -207,9 +207,8 @@ transform::TestFuseConsumerOp::apply(TransformRewriter &rewriter,
 
 void transform::TestFuseConsumerOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  producesHandle(getConsumer(), effects);
-  producesHandle(getFusedConsumer(), effects);
+  consumesHandle(getTargetMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -285,9 +284,8 @@ transform::TestTileUsingForallOp::apply(TransformRewriter &rewriter,
 
 void transform::TestTileUsingForallOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getTarget(), effects);
-  producesHandle(getTiledOp(), effects);
-  producesHandle(getLoops(), effects);
+  consumesHandle(getTargetMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 
@@ -375,9 +373,8 @@ transform::TestFuseUsingForallOp::apply(TransformRewriter &rewriter,
 
 void transform::TestFuseUsingForallOp::getEffects(
     SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
-  consumesHandle(getRootOp(), effects);
-  producesHandle(getTiledOps(), effects);
-  producesHandle(getLoops(), effects);
+  consumesHandle(getRootOpMutable(), effects);
+  producesHandle(getOperation()->getOpResults(), effects);
   modifiesPayload(effects);
 }
 

diff  --git a/mlir/test/mlir-tblgen/op-side-effects.td b/mlir/test/mlir-tblgen/op-side-effects.td
index 09612db905899..f08b373605f33 100644
--- a/mlir/test/mlir-tblgen/op-side-effects.td
+++ b/mlir/test/mlir-tblgen/op-side-effects.td
@@ -25,16 +25,28 @@ def SideEffectOpB : TEST_Op<"side_effect_op_b",
     [MemoryEffects<[MemWrite<CustomResource, 0>]>]>;
 
 // CHECK: void SideEffectOpA::getEffects
-// CHECK:   for (::mlir::Value value : getODSOperands(0))
-// CHECK:     effects.emplace_back(::mlir::MemoryEffects::Read::get(), value, 0, false, ::mlir::SideEffects::DefaultResource::get());
-// CHECK:   for (::mlir::Value value : getODSOperands(1))
-// CHECK:     effects.emplace_back(::mlir::MemoryEffects::Write::get(), value, 1, true, ::mlir::SideEffects::DefaultResource::get());
+// CHECK:  {
+// CHECK:    auto valueRange = getODSOperandIndexAndLength(0);
+// CHECK:    for (unsigned idx = valueRange.first; idx < valueRange.first + valueRange.second; idx++) {
+// CHECK:      effects.emplace_back(::mlir::MemoryEffects::Read::get(), &getOperation()->getOpOperand(idx), 0, false, ::mlir::SideEffects::DefaultResource::get());
+// CHECK:    }
+// CHECK:  }
+// CHECK:  {
+// CHECK:    auto valueRange = getODSOperandIndexAndLength(1);
+// CHECK:    for (unsigned idx = valueRange.first; idx < valueRange.first + valueRange.second; idx++) {
+// CHECK:      effects.emplace_back(::mlir::MemoryEffects::Write::get(), &getOperation()->getOpOperand(idx), 1, true, ::mlir::SideEffects::DefaultResource::get());
+// CHECK:    }
+// CHECK:  }
 // CHECK:   effects.emplace_back(::mlir::MemoryEffects::Read::get(), getSymbolAttr(), 0, false, ::mlir::SideEffects::DefaultResource::get());
 // CHECK:   effects.emplace_back(::mlir::MemoryEffects::Write::get(), getFlatSymbolAttr(), 0, false, ::mlir::SideEffects::DefaultResource::get());
 // CHECK:   if (auto symbolRef = getOptionalSymbolAttr())
 // CHECK:     effects.emplace_back(::mlir::MemoryEffects::Read::get(), symbolRef, 0, false, ::mlir::SideEffects::DefaultResource::get());
-// CHECK:   for (::mlir::Value value : getODSResults(0))
-// CHECK:     effects.emplace_back(::mlir::MemoryEffects::Allocate::get(), value, 0, false, CustomResource::get());
+// CHECK:  {
+// CHECK:    auto valueRange = getODSResultIndexAndLength(0);
+// CHECK:    for (unsigned idx = valueRange.first; idx < valueRange.first + valueRange.second; idx++) {
+// CHECK:      effects.emplace_back(::mlir::MemoryEffects::Allocate::get(), getOperation()->getOpResult(idx), 0, false, CustomResource::get());
+// CHECK:    }
+// CHECK:  }
 
 // CHECK: void SideEffectOpB::getEffects
 // CHECK:   effects.emplace_back(::mlir::MemoryEffects::Write::get(), 0, false, CustomResource::get());

diff  --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index adda7ce6fc6c9..3146e65a1d961 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -3423,12 +3423,18 @@ void OpEmitter::genSideEffectInterfaceMethods() {
         }
       } else {
         // Otherwise this is an operand/result, so we need to attach the Value.
-        body << "  for (::mlir::Value value : getODS"
-             << (location.kind == EffectKind::Operand ? "Operands" : "Results")
-             << "(" << location.index << "))\n  "
-             << llvm::formatv(addEffectCode, effect, "value, ", stage,
-                              effectOnFullRegion, resource)
-                    .str();
+        body << "  {\n    auto valueRange = getODS"
+             << (location.kind == EffectKind::Operand ? "Operand" : "Result")
+             << "IndexAndLength(" << location.index << ");\n"
+             << "    for (unsigned idx = valueRange.first; idx < "
+                "valueRange.first"
+             << " + valueRange.second; idx++) {\n    "
+             << llvm::formatv(addEffectCode, effect,
+                              (location.kind == EffectKind::Operand
+                                   ? "&getOperation()->getOpOperand(idx), "
+                                   : "getOperation()->getOpResult(idx), "),
+                              stage, effectOnFullRegion, resource)
+             << "    }\n  }\n";
       }
     }
   }


        


More information about the flang-commits mailing list