[flang-commits] [flang] 43d729d - [flang][HLFIR] add more memory effects interfaces

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Wed Sep 6 03:33:04 PDT 2023


Author: Tom Eccles
Date: 2023-09-06T10:29:57Z
New Revision: 43d729dda460b529c46f396c00d4602b50b91986

URL: https://github.com/llvm/llvm-project/commit/43d729dda460b529c46f396c00d4602b50b91986
DIFF: https://github.com/llvm/llvm-project/commit/43d729dda460b529c46f396c00d4602b50b91986.diff

LOG: [flang][HLFIR] add more memory effects interfaces

Anything that produces a hlfir.expr should have an allocation side
effect so that it is not removed by CSE (which would result in two
hlfir.destroy operations for the same expression). Similarly for
hlfir.associate, which has hlfir.end_associate.

Also adds read effects on arguments which are pointer-like or boxes.

I see no regressions from this change when running llvm-testsuite with
optimization enabled, or from SPEC2017 rate benchmarks.

To test this, I have added MLIR's pass for testing side effect
interfaces to fir-opt.

Differential Revision: https://reviews.llvm.org/D158662

Added: 
    flang/test/HLFIR/memory-effects.fir

Modified: 
    flang/include/flang/Optimizer/HLFIR/HLFIROps.td
    flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
    flang/test/HLFIR/order_assignments/where-scheduling.f90
    flang/tools/fir-opt/CMakeLists.txt
    flang/tools/fir-opt/fir-opt.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index f9b755c58dd81e..8aab44f176c0ec 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -319,7 +319,8 @@ def hlfir_ParentComponentOp : hlfir_Op<"parent_comp", [AttrSizedOperandSegments,
   let hasVerifier = 1;
 }
 
-def hlfir_ConcatOp : hlfir_Op<"concat", []> {
+def hlfir_ConcatOp : hlfir_Op<"concat",
+    [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "concatenate characters";
   let description = [{
     Concatenate two or more character strings of a same character kind.
@@ -340,7 +341,7 @@ def hlfir_ConcatOp : hlfir_Op<"concat", []> {
   let hasVerifier = 1;
 }
 
-def hlfir_AllOp : hlfir_Op<"all", []> {
+def hlfir_AllOp : hlfir_Op<"all", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "ALL transformational intrinsic";
   let description = [{
     Takes a logical array MASK as argument, optionally along a particular dimension,
@@ -361,7 +362,7 @@ def hlfir_AllOp : hlfir_Op<"all", []> {
   let hasVerifier = 1;
 }
 
-def hlfir_AnyOp : hlfir_Op<"any", []> {
+def hlfir_AnyOp : hlfir_Op<"any", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "ANY transformational intrinsic";
   let description = [{
     Takes a logical array MASK as argument, optionally along a particular dimension,
@@ -382,7 +383,7 @@ def hlfir_AnyOp : hlfir_Op<"any", []> {
   let hasVerifier = 1;
 }
 
-def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments]> {
+def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments, DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "COUNT transformational intrinsic";
   let description = [{
     Takes a logical and counts the number of true values.
@@ -403,9 +404,9 @@ def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments]> {
   let hasVerifier = 1;
 }
 
-
 def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments,
-    DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
+    DeclareOpInterfaceMethods<ArithFastMathInterface>,
+    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "PRODUCT transformational intrinsic";
   let description = [{
     Multiplies the elements of an array, optionally along a particular dimension,
@@ -429,7 +430,8 @@ def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments,
   let hasVerifier = 1;
 }
 
-def hlfir_SetLengthOp : hlfir_Op<"set_length", []> {
+def hlfir_SetLengthOp : hlfir_Op<"set_length",
+  [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "change the length of a character entity";
   let description = [{
     Change the length of character entity. This trims or pads the
@@ -468,7 +470,8 @@ def hlfir_GetLengthOp : hlfir_Op<"get_length", [Pure]> {
 }
 
 def hlfir_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments,
-    DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
+    DeclareOpInterfaceMethods<ArithFastMathInterface>,
+    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "SUM transformational intrinsic";
   let description = [{
     Sums the elements of an array, optionally along a particular dimension,
@@ -493,7 +496,8 @@ def hlfir_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments,
 }
 
 def hlfir_DotProductOp : hlfir_Op<"dot_product",
-    [DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
+    [DeclareOpInterfaceMethods<ArithFastMathInterface>,
+    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "DOT_PRODUCT transformational intrinsic";
   let description = [{
     Dot product of two vectors
@@ -516,7 +520,8 @@ def hlfir_DotProductOp : hlfir_Op<"dot_product",
 }
 
 def hlfir_MatmulOp : hlfir_Op<"matmul",
-    [DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
+    [DeclareOpInterfaceMethods<ArithFastMathInterface>,
+    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "MATMUL transformational intrinsic";
   let description = [{
     Matrix multiplication
@@ -541,7 +546,8 @@ def hlfir_MatmulOp : hlfir_Op<"matmul",
   let hasVerifier = 1;
 }
 
-def hlfir_TransposeOp : hlfir_Op<"transpose", []> {
+def hlfir_TransposeOp : hlfir_Op<"transpose",
+    [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "TRANSPOSE transformational intrinsic";
   let description = [{
     Transpose a rank 2 array
@@ -559,7 +565,8 @@ def hlfir_TransposeOp : hlfir_Op<"transpose", []> {
 }
 
 def hlfir_MatmulTransposeOp : hlfir_Op<"matmul_transpose",
-    [DeclareOpInterfaceMethods<ArithFastMathInterface>]> {
+    [DeclareOpInterfaceMethods<ArithFastMathInterface>,
+    DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "Optimized MATMUL(TRANSPOSE(...), ...)";
   let description = [{
     Matrix multiplication where the left hand side is transposed
@@ -581,8 +588,12 @@ def hlfir_MatmulTransposeOp : hlfir_Op<"matmul_transpose",
   let hasVerifier = 1;
 }
 
+// An allocation effect is needed because the value produced by the associate
+// is "deallocated" by hlfir.end_associate (the end_associate must not be
+// removed, and there must be only one hlfir.end_associate).
 def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments,
-    DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>]> {
+    DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>,
+    MemoryEffects<[MemAlloc]>]> {
   let summary = "Create a variable from an expression value";
   let description = [{
     Create a variable from an expression value.
@@ -635,7 +646,7 @@ def hlfir_AssociateOp : hlfir_Op<"associate", [AttrSizedOperandSegments,
   }];
 }
 
-def hlfir_EndAssociateOp : hlfir_Op<"end_associate", []> {
+def hlfir_EndAssociateOp : hlfir_Op<"end_associate", [MemoryEffects<[MemFree]>]> {
   let summary = "Mark the end of life of a variable associated to an expression";
 
   let description = [{
@@ -652,7 +663,8 @@ def hlfir_EndAssociateOp : hlfir_Op<"end_associate", []> {
   let builders = [OpBuilder<(ins "hlfir::AssociateOp":$associate)>];
 }
 
-def hlfir_AsExprOp : hlfir_Op<"as_expr", []> {
+def hlfir_AsExprOp : hlfir_Op<"as_expr",
+    [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "Take the value of an array, character or derived variable";
 
   let description = [{
@@ -934,7 +946,7 @@ def hlfir_DestroyOp : hlfir_Op<"destroy", [MemoryEffects<[MemFree]>]> {
   let assemblyFormat = "$expr attr-dict `:` qualified(type($expr))";
 }
 
-def hlfir_CopyInOp : hlfir_Op<"copy_in", []> {
+def hlfir_CopyInOp : hlfir_Op<"copy_in", [MemoryEffects<[MemAlloc]>]> {
   let summary = "copy a variable into a contiguous temporary if it is not contiguous";
   let description = [{
     Copy a variable into a contiguous temporary if the variable is not
@@ -954,7 +966,7 @@ def hlfir_CopyInOp : hlfir_Op<"copy_in", []> {
     is true and, when it is false, the original value will be returned instead.
   }];
 
-  let arguments = (ins fir_BaseBoxType:$var,
+  let arguments = (ins Arg<fir_BaseBoxType, "", [MemRead]>:$var,
                    Optional<I1>:$var_is_present);
 
   let results = (outs fir_BaseBoxType, I1);
@@ -981,7 +993,7 @@ def hlfir_CopyInOp : hlfir_Op<"copy_in", []> {
   }];
 }
 
-def hlfir_CopyOutOp : hlfir_Op<"copy_out", []> {
+def hlfir_CopyOutOp : hlfir_Op<"copy_out", [MemoryEffects<[MemFree]>]> {
   let summary = "copy out a variable after a copy in";
   let description = [{
     If the variable was copied in a temporary in the related hlfir.copy_in,
@@ -992,9 +1004,9 @@ def hlfir_CopyOutOp : hlfir_Op<"copy_out", []> {
     The deallocation of $temp is done if $was_copied is true.
   }];
 
-  let arguments = (ins fir_BaseBoxType:$temp,
+  let arguments = (ins Arg<fir_BaseBoxType, "", [MemRead]>:$temp,
                        I1:$was_copied,
-                       Optional<fir_BaseBoxType>:$var);
+                       Arg<Optional<fir_BaseBoxType>, "", [MemWrite]>:$var);
 
   let assemblyFormat = [{
     $temp `,` $was_copied (`to` $var^)?
@@ -1546,7 +1558,8 @@ def hlfir_ForallIndexOp : hlfir_Op<"forall_index", [fir_FortranVariableOpInterfa
   let hasCanonicalizeMethod = 1;
 }
 
-def hlfir_CharExtremumOp : hlfir_Op<"char_extremum", []> {
+def hlfir_CharExtremumOp : hlfir_Op<"char_extremum",
+    [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
   let summary = "Find max/min from given character strings";
   let description = [{
     Find the lexicographical minimum or maximum of two or more character 

diff  --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 0b4b9c1588efaf..5bb954647fb275 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -24,9 +24,43 @@
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include <iterator>
+#include <mlir/Interfaces/SideEffectInterfaces.h>
 #include <optional>
 #include <tuple>
 
+/// generic implementation of the memory side effects interface for hlfir
+/// transformational intrinsic operations
+static void
+getIntrinsicEffects(mlir::Operation *self,
+                    llvm::SmallVectorImpl<mlir::SideEffects::EffectInstance<
+                        mlir::MemoryEffects::Effect>> &effects) {
+  // allocation effect if we return an expr
+  assert(self->getNumResults() == 1 &&
+         "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),
+                         mlir::SideEffects::DefaultResource::get());
+
+  // read effect if we read from a pointer or refference type
+  // or a box who'se pointer is read from inside of the intrinsic so that
+  // loop conflicts can be detected in code like
+  // hlfir.region_assign {
+  //   %2 = hlfir.transpose %0#0 : (!fir.box<!fir.array<?x?xf32>>) ->
+  //   !hlfir.expr<?x?xf32> hlfir.yield %2 : !hlfir.expr<?x?xf32> cleanup {
+  //     hlfir.destroy %2 : !hlfir.expr<?x?xf32>
+  //   }
+  // } to {
+  //   hlfir.yield %0#0 : !fir.box<!fir.array<?x?xf32>>
+  // }
+  for (mlir::Value operand : self->getOperands()) {
+    mlir::Type opTy = operand.getType();
+    if (fir::isa_ref_type(opTy) || fir::isa_box_type(opTy))
+      effects.emplace_back(mlir::MemoryEffects::Read::get(), operand,
+                           mlir::SideEffects::DefaultResource::get());
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // DeclareOp
 //===----------------------------------------------------------------------===//
@@ -501,6 +535,13 @@ mlir::LogicalResult hlfir::AllOp::verify() {
   return verifyLogicalReductionOp<hlfir::AllOp *>(this);
 }
 
+void hlfir::AllOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // AnyOp
 //===----------------------------------------------------------------------===//
@@ -509,6 +550,13 @@ mlir::LogicalResult hlfir::AnyOp::verify() {
   return verifyLogicalReductionOp<hlfir::AnyOp *>(this);
 }
 
+void hlfir::AnyOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // CountOp
 //===----------------------------------------------------------------------===//
@@ -546,6 +594,13 @@ mlir::LogicalResult hlfir::CountOp::verify() {
   return mlir::success();
 }
 
+void hlfir::CountOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // ConcatOp
 //===----------------------------------------------------------------------===//
@@ -593,6 +648,13 @@ void hlfir::ConcatOp::build(mlir::OpBuilder &builder,
   build(builder, result, resultType, strings, len);
 }
 
+void hlfir::ConcatOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // NumericalReductionOp
 //===----------------------------------------------------------------------===//
@@ -680,6 +742,13 @@ mlir::LogicalResult hlfir::ProductOp::verify() {
   return verifyNumericalReductionOp<hlfir::ProductOp *>(this);
 }
 
+void hlfir::ProductOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // SetLengthOp
 //===----------------------------------------------------------------------===//
@@ -698,6 +767,13 @@ void hlfir::SetLengthOp::build(mlir::OpBuilder &builder,
   build(builder, result, resultType, string, len);
 }
 
+void hlfir::SetLengthOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // SumOp
 //===----------------------------------------------------------------------===//
@@ -706,6 +782,13 @@ mlir::LogicalResult hlfir::SumOp::verify() {
   return verifyNumericalReductionOp<hlfir::SumOp *>(this);
 }
 
+void hlfir::SumOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // DotProductOp
 //===----------------------------------------------------------------------===//
@@ -755,6 +838,13 @@ mlir::LogicalResult hlfir::DotProductOp::verify() {
   return mlir::success();
 }
 
+void hlfir::DotProductOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // MatmulOp
 //===----------------------------------------------------------------------===//
@@ -873,6 +963,13 @@ hlfir::MatmulOp::canonicalize(MatmulOp matmulOp,
   return mlir::failure();
 }
 
+void hlfir::MatmulOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // TransposeOp
 //===----------------------------------------------------------------------===//
@@ -906,6 +1003,13 @@ mlir::LogicalResult hlfir::TransposeOp::verify() {
   return mlir::success();
 }
 
+void hlfir::TransposeOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // MatmulTransposeOp
 //===----------------------------------------------------------------------===//
@@ -971,6 +1075,13 @@ mlir::LogicalResult hlfir::MatmulTransposeOp::verify() {
   return mlir::success();
 }
 
+void hlfir::MatmulTransposeOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // AssociateOp
 //===----------------------------------------------------------------------===//
@@ -1029,6 +1140,17 @@ void hlfir::AsExprOp::build(mlir::OpBuilder &builder,
   return build(builder, result, resultType, var, mustFree);
 }
 
+void hlfir::AsExprOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  // this isn't a transformational intrinsic but follows the same pattern: it
+  // creates a hlfir.expr and so needs to have an allocation effect, plus it
+  // might have a pointer-like argument, in which case it has a read effect
+  // upon those
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // ElementalOp
 //===----------------------------------------------------------------------===//
@@ -1525,6 +1647,13 @@ void hlfir::CharExtremumOp::build(mlir::OpBuilder &builder,
   build(builder, result, resultType, predicate, strings);
 }
 
+void hlfir::CharExtremumOp::getEffects(
+    llvm::SmallVectorImpl<
+        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
+        &effects) {
+  getIntrinsicEffects(getOperation(), effects);
+}
+
 //===----------------------------------------------------------------------===//
 // GetLength
 //===----------------------------------------------------------------------===//

diff  --git a/flang/test/HLFIR/memory-effects.fir b/flang/test/HLFIR/memory-effects.fir
new file mode 100644
index 00000000000000..a49dc167811636
--- /dev/null
+++ b/flang/test/HLFIR/memory-effects.fir
@@ -0,0 +1,203 @@
+// RUN: fir-opt %s --test-side-effects --verify-diagnostics
+
+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>'}}
+  %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>'}}
+  %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>'}}
+  %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>'}}
+  %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>'}}
+  %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>'}}
+  %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>'}}
+  %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 @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>'}}
+  %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>'}}
+  %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>'}}
+// 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>'}}
+  %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>'}}
+  %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>'}}
+  %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>'}}
+  %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>'}}
+// 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>'}}
+  %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
+}
+
+func.func @associate(%arg0: i32) {
+// expected-remark at +1 {{found an instance of 'allocate' on resource '<Default>'}}
+  %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>'}}
+  %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>'}}
+// 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>'}}
+  %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>>, %is_present: i1) {
+// expected-remark at +2 {{found an instance of 'allocate' on resource '<Default>'}}
+// expected-remark at +1 {{found an instance of 'read' on a value, on resource '<Default>'}}
+  %0:2 = hlfir.copy_in %box : (!fir.box<!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.box<!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>'}}
+  hlfir.copy_out %temp, %was_copied : (!fir.box<!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>'}}
+  hlfir.copy_out %temp, %was_copied to %box : (!fir.box<!fir.array<?xf64>>, i1, !fir.box<!fir.array<?xf64>>) -> ()
+// expected-remark at +1 {{operation has no memory effects}}
+  return
+}

diff  --git a/flang/test/HLFIR/order_assignments/where-scheduling.f90 b/flang/test/HLFIR/order_assignments/where-scheduling.f90
index dc7af2af6fb75f..0f79058a6ae97b 100644
--- a/flang/test/HLFIR/order_assignments/where-scheduling.f90
+++ b/flang/test/HLFIR/order_assignments/where-scheduling.f90
@@ -139,12 +139,9 @@ end function f
 !CHECK-NEXT: run 2 evaluate: where/region_assign1
 !CHECK-NEXT: run 3 evaluate: where/region_assign2
 !CHECK-LABEL: ------------ scheduling where in _QPrhs_lhs_conflict ------------
-!CHECK-NEXT: unknown effect: %{{.*}} = hlfir.transpose %{{.*}} : (!fir.box<!fir.array<?x?xf32>>) -> !hlfir.expr<?x?xf32>
-!CHECK-NEXT: conflict: R/W: %6 = hlfir.designate %{{.*}} (%{{.*}}, %{{.*}})  : (!fir.box<!fir.array<?x?xf32>>, index, index) -> !fir.ref<f32> W:<unknown>
-!CHECK-NEXT: run 1 save    : where/mask
-!CHECK-NEXT: unknown effect: %{{.*}} = hlfir.transpose %{{.*}} : (!fir.box<!fir.array<?x?xf32>>) -> !hlfir.expr<?x?xf32>
-!CHECK-NEXT: run 2 save  (w): where/region_assign1/rhs
-!CHECK-NEXT: run 3 evaluate: where/region_assign1
+!CHECK-NEXT: conflict: R/W: <block argument> of type '!fir.box<!fir.array<?x?xf32>>' at index: 0 W:<block argument> of type '!fir.box<!fir.array<?x?xf32>>' at index: 0
+!CHECK-NEXT: run 1 save    : where/region_assign1/rhs
+!CHECK-NEXT: run 2 evaluate: where/region_assign1
 !CHECK-LABEL: ------------ scheduling where in _QPwhere_construct_no_conflict ------------
 !CHECK-NEXT: run 1 evaluate: where/region_assign1
 !CHECK-NEXT: run 2 evaluate: where/elsewhere1/region_assign1

diff  --git a/flang/tools/fir-opt/CMakeLists.txt b/flang/tools/fir-opt/CMakeLists.txt
index cd959a571f6476..43b0c74696f57e 100644
--- a/flang/tools/fir-opt/CMakeLists.txt
+++ b/flang/tools/fir-opt/CMakeLists.txt
@@ -6,6 +6,7 @@ get_property(extension_libs GLOBAL PROPERTY MLIR_EXTENSION_LIBS)
 if(FLANG_INCLUDE_TESTS)
   set(test_libs
     FIRTestAnalysis
+    MLIRTestIR
     )
 endif()
 
@@ -35,5 +36,4 @@ target_link_libraries(fir-opt PRIVATE
   MLIRSupport
   MLIRVectorToLLVM
   MLIROptLib
-
 )

diff  --git a/flang/tools/fir-opt/fir-opt.cpp b/flang/tools/fir-opt/fir-opt.cpp
index d4457c57a04118..92af79e50fa4e1 100644
--- a/flang/tools/fir-opt/fir-opt.cpp
+++ b/flang/tools/fir-opt/fir-opt.cpp
@@ -24,6 +24,11 @@ void registerTestFIRAliasAnalysisPass();
 } // namespace test
 } // namespace fir
 
+// Defined in mlir/test, no pulic header.
+namespace mlir {
+void registerSideEffectTestPasses();
+}
+
 int main(int argc, char **argv) {
   fir::support::registerMLIRPassesForFortranTools();
   fir::registerOptCodeGenPasses();
@@ -31,6 +36,7 @@ int main(int argc, char **argv) {
   hlfir::registerHLFIRPasses();
 #ifdef FLANG_INCLUDE_TESTS
   fir::test::registerTestFIRAliasAnalysisPass();
+  mlir::registerSideEffectTestPasses();
 #endif
   DialectRegistry registry;
   fir::support::registerDialects(registry);


        


More information about the flang-commits mailing list