diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -319,7 +319,8 @@ let hasVerifier = 1; } -def hlfir_ConcatOp : hlfir_Op<"concat", []> { +def hlfir_ConcatOp : hlfir_Op<"concat", + [DeclareOpInterfaceMethods]> { let summary = "concatenate characters"; let description = [{ Concatenate two or more character strings of a same character kind. @@ -340,7 +341,7 @@ let hasVerifier = 1; } -def hlfir_AllOp : hlfir_Op<"all", []> { +def hlfir_AllOp : hlfir_Op<"all", [DeclareOpInterfaceMethods]> { let summary = "ALL transformational intrinsic"; let description = [{ Takes a logical array MASK as argument, optionally along a particular dimension, @@ -361,7 +362,7 @@ let hasVerifier = 1; } -def hlfir_AnyOp : hlfir_Op<"any", []> { +def hlfir_AnyOp : hlfir_Op<"any", [DeclareOpInterfaceMethods]> { let summary = "ANY transformational intrinsic"; let description = [{ Takes a logical array MASK as argument, optionally along a particular dimension, @@ -382,7 +383,7 @@ let hasVerifier = 1; } -def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments]> { +def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments, DeclareOpInterfaceMethods]> { let summary = "COUNT transformational intrinsic"; let description = [{ Takes a logical and counts the number of true values. @@ -403,9 +404,9 @@ let hasVerifier = 1; } - def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments, - DeclareOpInterfaceMethods]> { + DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods]> { let summary = "PRODUCT transformational intrinsic"; let description = [{ Multiplies the elements of an array, optionally along a particular dimension, @@ -429,7 +430,8 @@ let hasVerifier = 1; } -def hlfir_SetLengthOp : hlfir_Op<"set_length", []> { +def hlfir_SetLengthOp : hlfir_Op<"set_length", + [DeclareOpInterfaceMethods]> { 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_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments, - DeclareOpInterfaceMethods]> { + DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods]> { let summary = "SUM transformational intrinsic"; let description = [{ Sums the elements of an array, optionally along a particular dimension, @@ -493,7 +496,8 @@ } def hlfir_DotProductOp : hlfir_Op<"dot_product", - [DeclareOpInterfaceMethods]> { + [DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods]> { let summary = "DOT_PRODUCT transformational intrinsic"; let description = [{ Dot product of two vectors @@ -516,7 +520,8 @@ } def hlfir_MatmulOp : hlfir_Op<"matmul", - [DeclareOpInterfaceMethods]> { + [DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods]> { let summary = "MATMUL transformational intrinsic"; let description = [{ Matrix multiplication @@ -541,7 +546,8 @@ let hasVerifier = 1; } -def hlfir_TransposeOp : hlfir_Op<"transpose", []> { +def hlfir_TransposeOp : hlfir_Op<"transpose", + [DeclareOpInterfaceMethods]> { let summary = "TRANSPOSE transformational intrinsic"; let description = [{ Transpose a rank 2 array @@ -559,7 +565,8 @@ } def hlfir_MatmulTransposeOp : hlfir_Op<"matmul_transpose", - [DeclareOpInterfaceMethods]> { + [DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods]> { let summary = "Optimized MATMUL(TRANSPOSE(...), ...)"; let description = [{ Matrix multiplication where the left hand side is transposed @@ -581,8 +588,12 @@ 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]> { + DeclareOpInterfaceMethods, + 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_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 @@ let builders = [OpBuilder<(ins "hlfir::AssociateOp":$associate)>]; } -def hlfir_AsExprOp : hlfir_Op<"as_expr", []> { +def hlfir_AsExprOp : hlfir_Op<"as_expr", + [DeclareOpInterfaceMethods]> { let summary = "Take the value of an array, character or derived variable"; let description = [{ @@ -934,7 +946,7 @@ 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 @@ is true and, when it is false, the original value will be returned instead. }]; - let arguments = (ins fir_BaseBoxType:$var, + let arguments = (ins Arg:$var, Optional:$var_is_present); let results = (outs fir_BaseBoxType, I1); @@ -981,7 +993,7 @@ }]; } -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 @@ The deallocation of $temp is done if $was_copied is true. }]; - let arguments = (ins fir_BaseBoxType:$temp, + let arguments = (ins Arg:$temp, I1:$was_copied, - Optional:$var); + Arg, "", [MemWrite]>:$var); let assemblyFormat = [{ $temp `,` $was_copied (`to` $var^)? @@ -1546,7 +1558,8 @@ let hasCanonicalizeMethod = 1; } -def hlfir_CharExtremumOp : hlfir_Op<"char_extremum", []> { +def hlfir_CharExtremumOp : hlfir_Op<"char_extremum", + [DeclareOpInterfaceMethods]> { 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 --- 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 +#include #include #include +/// generic implementation of the memory side effects interface for hlfir +/// transformational intrinsic operations +static void +getIntrinsicEffects(mlir::Operation *self, + llvm::SmallVectorImpl> &effects) { + // allocation effect if we return an expr + assert(self->getNumResults() == 1 && + "hlfir intrinsic ops only produce 1 result"); + if (mlir::isa(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>) -> + // !hlfir.expr hlfir.yield %2 : !hlfir.expr cleanup { + // hlfir.destroy %2 : !hlfir.expr + // } + // } to { + // hlfir.yield %0#0 : !fir.box> + // } + 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 @@ return verifyLogicalReductionOp(this); } +void hlfir::AllOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // AnyOp //===----------------------------------------------------------------------===// @@ -509,6 +550,13 @@ return verifyLogicalReductionOp(this); } +void hlfir::AnyOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // CountOp //===----------------------------------------------------------------------===// @@ -546,6 +594,13 @@ return mlir::success(); } +void hlfir::CountOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // ConcatOp //===----------------------------------------------------------------------===// @@ -593,6 +648,13 @@ build(builder, result, resultType, strings, len); } +void hlfir::ConcatOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // NumericalReductionOp //===----------------------------------------------------------------------===// @@ -680,6 +742,13 @@ return verifyNumericalReductionOp(this); } +void hlfir::ProductOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // SetLengthOp //===----------------------------------------------------------------------===// @@ -698,6 +767,13 @@ build(builder, result, resultType, string, len); } +void hlfir::SetLengthOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // SumOp //===----------------------------------------------------------------------===// @@ -706,6 +782,13 @@ return verifyNumericalReductionOp(this); } +void hlfir::SumOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // DotProductOp //===----------------------------------------------------------------------===// @@ -755,6 +838,13 @@ return mlir::success(); } +void hlfir::DotProductOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // MatmulOp //===----------------------------------------------------------------------===// @@ -873,6 +963,13 @@ return mlir::failure(); } +void hlfir::MatmulOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // TransposeOp //===----------------------------------------------------------------------===// @@ -906,6 +1003,13 @@ return mlir::success(); } +void hlfir::TransposeOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // MatmulTransposeOp //===----------------------------------------------------------------------===// @@ -971,6 +1075,13 @@ return mlir::success(); } +void hlfir::MatmulTransposeOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &effects) { + getIntrinsicEffects(getOperation(), effects); +} + //===----------------------------------------------------------------------===// // AssociateOp //===----------------------------------------------------------------------===// @@ -1029,6 +1140,17 @@ return build(builder, result, resultType, var, mustFree); } +void hlfir::AsExprOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &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 @@ build(builder, result, resultType, predicate, strings); } +void hlfir::CharExtremumOp::getEffects( + llvm::SmallVectorImpl< + mlir::SideEffects::EffectInstance> + &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 --- /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>, %arg1: !fir.ref>) { +// expected-remark@+1 {{operation has no memory effects}} + %c30 = arith.constant 30 : index +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.concat %arg0, %arg1 len %c30 : (!fir.ref>, !fir.ref>, index) -> (!hlfir.expr>) +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @all_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) { +// expected-remark@+1 {{operation has no memory effects}} + %all = hlfir.all %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> !fir.logical<4> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @all_effects(%arg0: !fir.ref>>, %arg1: i32) { +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %all = hlfir.all %arg0 dim %arg1 : (!fir.ref>>, i32) -> !hlfir.expr> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @any_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) { +// expected-remark@+1 {{operation has no memory effects}} + %all = hlfir.any %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> !fir.logical<4> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @any_effects(%arg0: !fir.ref>>, %arg1: i32) { +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %all = hlfir.any %arg0 dim %arg1 : (!fir.ref>>, i32) -> !hlfir.expr> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @count_no_effects(%arg0: !hlfir.expr<2x!fir.logical<4>>) { +// expected-remark@+1 {{operation has no memory effects}} + %all = hlfir.count %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> i32 +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @count_effects(%arg0: !fir.ref>>, %arg1: i32) { +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %all = hlfir.count %arg0 dim %arg1 : (!fir.ref>>, i32) -> i32 +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @product_no_effects(%arg0: !hlfir.expr) { +// expected-remark@+1 {{operation has no memory effects}} + %product = hlfir.product %arg0 : (!hlfir.expr) -> f32 +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @product_effects(%arg0: !fir.ref>, %arg1: i32) { +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %product = hlfir.product %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xf32> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @set_length_read(%arg0: !fir.ref>, %arg1: index) { +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.set_length %arg0 len %arg1 : (!fir.ref>, index) -> !hlfir.expr> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @sum_no_effects(%arg0: !hlfir.expr) { +// expected-remark@+1 {{operation has no memory effects}} + %sum = hlfir.sum %arg0 : (!hlfir.expr) -> f32 +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @sum_effects(%arg0: !fir.ref>, %arg1: i32) { +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %sum = hlfir.sum %arg0 dim %arg1 : (!fir.ref>, i32) -> !hlfir.expr<2xf32> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @dot_product_no_effects(%arg0: !hlfir.expr, %arg1: !hlfir.expr) { +// expected-remark@+1 {{operation has no memory effects}} + %0 = hlfir.dot_product %arg0 %arg1 : (!hlfir.expr, !hlfir.expr) -> f32 +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @dot_product_effects(%arg0: !fir.ref>, %arg1: !fir.ref>) { +// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.dot_product %arg0 %arg1 : (!fir.ref>, !fir.ref>) -> f32 +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @matmul_no_reads(%arg0: !hlfir.expr, %arg1: !hlfir.expr) { +// expected-remark@+1 {{found an instance of 'allocate' on a value, on resource ''}} + %0 = hlfir.matmul %arg0 %arg1 : (!hlfir.expr, !hlfir.expr) -> !hlfir.expr +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @matmul_reads(%arg0: !fir.ref>, %arg1: !fir.ref>) { +// expected-remark@+3 {{found an instance of 'allocate' on a value, on resource ''}} +// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.matmul %arg0 %arg1 : (!fir.ref>, !fir.ref>) -> !hlfir.expr<10x10xf32> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @transpose_no_reads(%arg0: !hlfir.expr) { +// expected-remark@+1 {{found an instance of 'allocate' on a value, on resource ''}} + %0 = hlfir.transpose %arg0 : (!hlfir.expr) -> !hlfir.expr +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @transpose_read(%arg0: !fir.ref>) { +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.transpose %arg0 : (!fir.ref>) -> !hlfir.expr<5x10xf32> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @matmul_transpose_no_reads(%arg0: !hlfir.expr, %arg1: !hlfir.expr) { +// expected-remark@+1 {{found an instance of 'allocate' on a value, on resource ''}} + %0 = hlfir.matmul_transpose %arg0 %arg1 : (!hlfir.expr, !hlfir.expr) -> !hlfir.expr +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @matmul_transpose_reads(%arg0: !fir.ref>, %arg1: !fir.ref>) { +// expected-remark@+3 {{found an instance of 'allocate' on a value, on resource ''}} +// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.matmul_transpose %arg0 %arg1 : (!fir.ref>, !fir.ref>) -> !hlfir.expr<10x10xf32> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @associate(%arg0: i32) { +// expected-remark@+1 {{found an instance of 'allocate' on resource ''}} + %0:3 = hlfir.associate %arg0 {uniq_name = "x"} : (i32) -> (!fir.ref, !fir.ref, i1) +// expected-remark@+1 {{found an instance of 'free' on resource ''}} + hlfir.end_associate %0#1, %0#2 : !fir.ref, i1 +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @as_expr_read(%arg0: !fir.ref>) { +// expected-remark@+2 {{found an instance of 'allocate' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.as_expr %arg0 : (!fir.ref>) -> !hlfir.expr +// expected-remark@+1 {{found an instance of 'free' on resource ''}} + hlfir.destroy %0 : !hlfir.expr +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @char_extremum(%arg0: !fir.ref>, %arg1: !fir.ref>) { +// expected-remark@+3 {{found an instance of 'allocate' on a value, on resource ''}} +// there are read effects on both arguments - the diagnostic verification just doesn't register duplicate identical diagnostics +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0 = hlfir.char_extremum min, %arg0, %arg1 : (!fir.ref>, !fir.ref>) -> !hlfir.expr> +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @copy_in(%box: !fir.box>, %is_present: i1) { +// expected-remark@+2 {{found an instance of 'allocate' on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + %0:2 = hlfir.copy_in %box : (!fir.box>) -> (!fir.box>, i1) +// expected-remark@+1 {{operation has no memory effects}} + return +} + +func.func @copy_out(%box: !fir.box>, %temp: !fir.box>, %was_copied: i1) { +// expected-remark@+2 {{found an instance of 'free' on resource ''}} +// expected-remark@+1 {{found an instance of 'read' on a value, on resource ''}} + hlfir.copy_out %temp, %was_copied : (!fir.box>, i1) -> () +// expected-remark@+3 {{found an instance of 'free' on resource ''}} +// expected-remark@+2 {{found an instance of 'read' on a value, on resource ''}} +// expected-remark@+1 {{found an instance of 'write' on a value, on resource ''}} + hlfir.copy_out %temp, %was_copied to %box : (!fir.box>, i1, !fir.box>) -> () +// expected-remark@+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 --- a/flang/test/HLFIR/order_assignments/where-scheduling.f90 +++ b/flang/test/HLFIR/order_assignments/where-scheduling.f90 @@ -139,12 +139,9 @@ !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>) -> !hlfir.expr -!CHECK-NEXT: conflict: R/W: %6 = hlfir.designate %{{.*}} (%{{.*}}, %{{.*}}) : (!fir.box>, index, index) -> !fir.ref W: -!CHECK-NEXT: run 1 save : where/mask -!CHECK-NEXT: unknown effect: %{{.*}} = hlfir.transpose %{{.*}} : (!fir.box>) -> !hlfir.expr -!CHECK-NEXT: run 2 save (w): where/region_assign1/rhs -!CHECK-NEXT: run 3 evaluate: where/region_assign1 +!CHECK-NEXT: conflict: R/W: of type '!fir.box>' at index: 0 W: of type '!fir.box>' 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 --- a/flang/tools/fir-opt/CMakeLists.txt +++ b/flang/tools/fir-opt/CMakeLists.txt @@ -6,6 +6,7 @@ if(FLANG_INCLUDE_TESTS) set(test_libs FIRTestAnalysis + MLIRTestIR ) endif() @@ -35,5 +36,4 @@ MLIRSupport MLIRVectorToLLVM MLIROptLib - ) diff --git a/flang/tools/fir-opt/fir-opt.cpp b/flang/tools/fir-opt/fir-opt.cpp --- a/flang/tools/fir-opt/fir-opt.cpp +++ b/flang/tools/fir-opt/fir-opt.cpp @@ -24,6 +24,11 @@ } // 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 @@ hlfir::registerHLFIRPasses(); #ifdef FLANG_INCLUDE_TESTS fir::test::registerTestFIRAliasAnalysisPass(); + mlir::registerSideEffectTestPasses(); #endif DialectRegistry registry; fir::support::registerDialects(registry);