[flang-commits] [flang] [flang] Added fir.dummy_scope operation to preserve dummy arguments association. (PR #90642)
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Tue Apr 30 13:31:33 PDT 2024
https://github.com/vzakhari updated https://github.com/llvm/llvm-project/pull/90642
>From 4432577b44a98d489cbfb53e29331c8be5d63994 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Tue, 30 Apr 2024 09:55:50 -0700
Subject: [PATCH 1/4] [flang] Added fir.dummy_scope operation to preserve dummy
arguments association.
The new operation is just an abstract attribute that is attached to
[hl]fir.declare operations of dummy arguments of a subroutine.
Dummy arguments of the same subroutine refer to the same fir.dummy_scope,
so they can be recognized as such during FIR AliasAnalysis.
Note that the fir.dummy_scope must be specific to the runtime instantiation
of a subroutine, so any MLIR inlining/cloning should duplicate and unique it
vs using the same fir.dummy_scope for different runtime instantiations.
This is why I made it an operation rather than an attribute.
The new operation uses a write effect on DebuggingResource, same as
[hl]fir.declare, to avoid optimizing it away.
---
.../include/flang/Optimizer/Dialect/FIROps.td | 84 ++++++++++++++++++-
.../include/flang/Optimizer/HLFIR/HLFIROps.td | 4 +-
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp | 3 +-
.../HLFIR/Transforms/ConvertToFIR.cpp | 4 +-
flang/test/Fir/dummy_scope.fir | 34 ++++++++
flang/test/HLFIR/dummy_scope.fir | 34 ++++++++
.../Optimizer/FortranVariableTest.cpp | 9 +-
7 files changed, 163 insertions(+), 9 deletions(-)
create mode 100644 flang/test/Fir/dummy_scope.fir
create mode 100644 flang/test/HLFIR/dummy_scope.fir
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 496193e25cab61..95cce67137890f 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -3074,6 +3074,7 @@ def fir_DeclareOp : fir_Op<"declare", [AttrSizedOperandSegments,
AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
+ Optional<I1>:$dummy_scope,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<fir_CUDADataAttributeAttr>:$cuda_attr
@@ -3083,7 +3084,8 @@ def fir_DeclareOp : fir_Op<"declare", [AttrSizedOperandSegments,
let assemblyFormat = [{
$memref (`(` $shape^ `)`)? (`typeparams` $typeparams^)?
- attr-dict `:` functional-type(operands, results)
+ (`dummy_scope` $dummy_scope^)?
+ attr-dict `:` functional-type(operands, results)
}];
let hasVerifier = 1;
@@ -3247,4 +3249,84 @@ def fir_CUDADeallocateOp : fir_Op<"cuda_deallocate",
let hasVerifier = 1;
}
+def fir_DummyScopeOp : fir_Op<"dummy_scope",
+ [MemoryEffects<[MemWrite<DebuggingResource>]>]> {
+ let summary = "Define a scope for dummy arguments";
+
+ let description = [{
+ An abstract handle to be used to associate dummy arguments of the same
+ subroutine between each other. By lowering, all [hl]fir.declare
+ operations representing declarations of dummy arguments of a subroutine
+ use the result of this operation. This allows recognizing the references
+ of these dummy arguments as belonging to the same runtime instance
+ of the subroutine even after MLIR inlining. Thus, the Fortran aliasing
+ rules might be applied to those references based on the original
+ declarations of the dummy arguments.
+ For example:
+ ```
+ subroutine test(x, y)
+ real, target :: x, y
+ x = y ! may alias
+ call inner(x, y)
+ contains
+ subroutine inner(x, y)
+ real :: x, y
+ x = y ! may not alias
+ end subroutine inner
+ end subroutine test
+ ```
+ After MLIR inlining this may look like this:
+ ```
+ func.func @_QPtest(
+ %arg0: !fir.ref<f32> {fir.target},
+ %arg1: !fir.ref<f32> {fir.target}) {
+ %0 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs<target>} :
+ (!fir.ref<f32>) -> !fir.ref<f32>
+ %1 = fir.declare %arg1 {fortran_attrs = #fir.var_attrs<target>} :
+ (!fir.ref<f32>) -> !fir.ref<f32>
+ %2 = fir.load %1 : !fir.ref<f32>
+ fir.store %2 to %0 : !fir.ref<f32>
+ %3 = fir.declare %0 : (!fir.ref<f32>) -> !fir.ref<f32>
+ %4 = fir.declare %1 : (!fir.ref<f32>) -> !fir.ref<f32>
+ %5 = fir.load %4 : !fir.ref<f32>
+ fir.store %5 to %3 : !fir.ref<f32>
+ return
+ }
+ ```
+ Without marking %3 and %4 as declaring the dummy arguments
+ of the same runtime instance of `inner` subroutine the FIR
+ AliasAnalysis cannot deduce non-aliasing for the second load/store pair.
+ This information may be preserved by using fir.dummy_scope operation:
+ ```
+ func.func @_QPtest(
+ %arg0: !fir.ref<f32> {fir.target},
+ %arg1: !fir.ref<f32> {fir.target}) {
+ %h1 = fir.dummy_scope : i1
+ %0 = fir.declare %arg0 dummy_scope(%h1)
+ {fortran_attrs = #fir.var_attrs<target>} :
+ (!fir.ref<f32>) -> !fir.ref<f32>
+ %1 = fir.declare %arg1 dummy_scope(%h1)
+ {fortran_attrs = #fir.var_attrs<target>} :
+ (!fir.ref<f32>) -> !fir.ref<f32>
+ %2 = fir.load %1 : !fir.ref<f32>
+ fir.store %2 to %0 : !fir.ref<f32>
+ %h2 = fir.dummy_scope : i1
+ %3 = fir.declare %0 dummy_scope(%h2) : (!fir.ref<f32>) -> !fir.ref<f32>
+ %4 = fir.declare %1 dummy_scope(%h2) : (!fir.ref<f32>) -> !fir.ref<f32>
+ %5 = fir.load %4 : !fir.ref<f32>
+ fir.store %5 to %3 : !fir.ref<f32>
+ return
+ }
+ ```
+ Note that even if `inner` is called and inlined twice inside
+ `test`, the two inlined instances of `inner` must use two different
+ fir.dummy_scope operations for their fir.declare ops. This
+ two distinct fir.dummy_scope must remain distinct during the optimizations.
+ This is guaranteed by the write memory effect on the DebuggingResource.
+ }];
+
+ let results = (outs I1);
+ let assemblyFormat = "attr-dict `:` type(results)";
+}
+
#endif
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index 743a6c98ec1a03..be0bb770a3e171 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -87,6 +87,7 @@ def hlfir_DeclareOp : hlfir_Op<"declare", [AttrSizedOperandSegments,
AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
+ Optional<I1>:$dummy_scope,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<fir_CUDADataAttributeAttr>:$cuda_attr
@@ -96,7 +97,8 @@ def hlfir_DeclareOp : hlfir_Op<"declare", [AttrSizedOperandSegments,
let assemblyFormat = [{
$memref (`(` $shape^ `)`)? (`typeparams` $typeparams^)?
- attr-dict `:` functional-type(operands, results)
+ (`dummy_scope` $dummy_scope^)?
+ attr-dict `:` functional-type(operands, results)
}];
let builders = [
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 0d62ca4954e6bf..4b586ad1d3a4af 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -133,7 +133,8 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
mlir::Type hlfirVariableType =
getHLFIRVariableType(inputType, hasExplicitLbs);
build(builder, result, {hlfirVariableType, inputType}, memref, shape,
- typeparams, nameAttr, fortran_attrs, cuda_attr);
+ typeparams, /*dummy_scope=*/nullptr, nameAttr, fortran_attrs,
+ cuda_attr);
}
mlir::LogicalResult hlfir::DeclareOp::verify() {
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 517285dce133de..08869bcd00e42f 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -328,8 +328,8 @@ class DeclareOpConversion : public mlir::OpRewritePattern<hlfir::DeclareOp> {
cudaAttr = fir::CUDADataAttributeAttr::get(rewriter.getContext(), *attr);
auto firDeclareOp = rewriter.create<fir::DeclareOp>(
loc, memref.getType(), memref, declareOp.getShape(),
- declareOp.getTypeparams(), declareOp.getUniqName(), fortranAttrs,
- cudaAttr);
+ declareOp.getTypeparams(), /*dummy_scope=*/nullptr,
+ declareOp.getUniqName(), fortranAttrs, cudaAttr);
// Propagate other attributes from hlfir.declare to fir.declare.
// OpenACC's acc.declare is one example. Right now, the propagation
diff --git a/flang/test/Fir/dummy_scope.fir b/flang/test/Fir/dummy_scope.fir
new file mode 100644
index 00000000000000..8def2759fb77d6
--- /dev/null
+++ b/flang/test/Fir/dummy_scope.fir
@@ -0,0 +1,34 @@
+// RUN: fir-opt %s | fir-opt | FileCheck %s
+// RUN: fir-opt %s | fir-opt -cse | FileCheck %s
+
+// CHECK-LABEL: func.func @dummy_scope(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+// CHECK: return
+// CHECK: }
+func.func @dummy_scope(%arg0: !fir.ref<f32>) {
+ %scope = fir.dummy_scope : i1
+ %0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ return
+}
+
+// CHECK-LABEL: func.func @dummy_scopes(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_3]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_5]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+// CHECK: return
+// CHECK: }
+func.func @dummy_scopes(%arg0: !fir.ref<f32>) {
+ %scope_out = fir.dummy_scope : i1
+ %0 = fir.declare %arg0 dummy_scope %scope_out {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ %scope_in1 = fir.dummy_scope : i1
+ %1 = fir.declare %arg0 dummy_scope %scope_in1 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ %scope_in2 = fir.dummy_scope : i1
+ %2 = fir.declare %arg0 dummy_scope %scope_in2 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ return
+}
diff --git a/flang/test/HLFIR/dummy_scope.fir b/flang/test/HLFIR/dummy_scope.fir
new file mode 100644
index 00000000000000..304ebccfbe3197
--- /dev/null
+++ b/flang/test/HLFIR/dummy_scope.fir
@@ -0,0 +1,34 @@
+// RUN: fir-opt %s | fir-opt | FileCheck %s
+// RUN: fir-opt %s | fir-opt -cse | FileCheck %s
+
+// CHECK-LABEL: func.func @dummy_scope(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: return
+// CHECK: }
+func.func @dummy_scope(%arg0: !fir.ref<f32>) {
+ %scope = fir.dummy_scope : i1
+ %0:2 = hlfir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ return
+}
+
+// CHECK-LABEL: func.func @dummy_scopes(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_3]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_5]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: return
+// CHECK: }
+func.func @dummy_scopes(%arg0: !fir.ref<f32>) {
+ %scope_out = fir.dummy_scope : i1
+ %0:2 = hlfir.declare %arg0 dummy_scope %scope_out {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %scope_in1 = fir.dummy_scope : i1
+ %1:2 = hlfir.declare %arg0 dummy_scope %scope_in1 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %scope_in2 = fir.dummy_scope : i1
+ %2:2 = hlfir.declare %arg0 dummy_scope %scope_in2 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ return
+}
diff --git a/flang/unittests/Optimizer/FortranVariableTest.cpp b/flang/unittests/Optimizer/FortranVariableTest.cpp
index 790f735a6cf29e..f5f559ef887c85 100644
--- a/flang/unittests/Optimizer/FortranVariableTest.cpp
+++ b/flang/unittests/Optimizer/FortranVariableTest.cpp
@@ -48,7 +48,8 @@ TEST_F(FortranVariableTest, SimpleScalar) {
mlir::Value addr = builder->create<fir::AllocaOp>(loc, eleType);
auto name = mlir::StringAttr::get(&context, "x");
auto declare = builder->create<fir::DeclareOp>(loc, addr.getType(), addr,
- /*shape=*/mlir::Value{}, /*typeParams=*/std::nullopt, name,
+ /*shape=*/mlir::Value{}, /*typeParams=*/std::nullopt,
+ /*dummy_scope=*/nullptr, name,
/*fortran_attrs=*/fir::FortranVariableFlagsAttr{},
/*cuda_attr=*/fir::CUDADataAttributeAttr{});
@@ -74,7 +75,7 @@ TEST_F(FortranVariableTest, CharacterScalar) {
loc, eleType, /*pinned=*/false, typeParams);
auto name = mlir::StringAttr::get(&context, "x");
auto declare = builder->create<fir::DeclareOp>(loc, addr.getType(), addr,
- /*shape=*/mlir::Value{}, typeParams, name,
+ /*shape=*/mlir::Value{}, typeParams, /*dummy_scope=*/nullptr, name,
/*fortran_attrs=*/fir::FortranVariableFlagsAttr{},
/*cuda_attr=*/fir::CUDADataAttributeAttr{});
@@ -105,7 +106,7 @@ TEST_F(FortranVariableTest, SimpleArray) {
mlir::Value shape = createShape(extents);
auto name = mlir::StringAttr::get(&context, "x");
auto declare = builder->create<fir::DeclareOp>(loc, addr.getType(), addr,
- shape, /*typeParams*/ std::nullopt, name,
+ shape, /*typeParams*/ std::nullopt, /*dummy_scope=*/nullptr, name,
/*fortran_attrs=*/fir::FortranVariableFlagsAttr{},
/*cuda_attr=*/fir::CUDADataAttributeAttr{});
@@ -136,7 +137,7 @@ TEST_F(FortranVariableTest, CharacterArray) {
mlir::Value shape = createShape(extents);
auto name = mlir::StringAttr::get(&context, "x");
auto declare = builder->create<fir::DeclareOp>(loc, addr.getType(), addr,
- shape, typeParams, name,
+ shape, typeParams, /*dummy_scope=*/nullptr, name,
/*fortran_attrs=*/fir::FortranVariableFlagsAttr{},
/*cuda_attr=*/fir::CUDADataAttributeAttr{});
>From 33d03b4af57e25e7cf298d2d1513ce929de0a1a3 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Tue, 30 Apr 2024 09:56:00 -0700
Subject: [PATCH 2/4] [flang] Conversion of dummy_scope operand of
hlfir.declare to fir.declare.
---
flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp | 2 +-
flang/test/HLFIR/declare-codegen.fir | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 08869bcd00e42f..3570e0011ca7e6 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -328,7 +328,7 @@ class DeclareOpConversion : public mlir::OpRewritePattern<hlfir::DeclareOp> {
cudaAttr = fir::CUDADataAttributeAttr::get(rewriter.getContext(), *attr);
auto firDeclareOp = rewriter.create<fir::DeclareOp>(
loc, memref.getType(), memref, declareOp.getShape(),
- declareOp.getTypeparams(), /*dummy_scope=*/nullptr,
+ declareOp.getTypeparams(), declareOp.getDummyScope(),
declareOp.getUniqName(), fortranAttrs, cudaAttr);
// Propagate other attributes from hlfir.declare to fir.declare.
diff --git a/flang/test/HLFIR/declare-codegen.fir b/flang/test/HLFIR/declare-codegen.fir
index 3e80a52be45248..d079aa776a3a9c 100644
--- a/flang/test/HLFIR/declare-codegen.fir
+++ b/flang/test/HLFIR/declare-codegen.fir
@@ -200,3 +200,13 @@ func.func @test_optional_declare(%arg0: !fir.box<!fir.array<?xi32>>) {
// CHECK: %[[VAL_7:.*]] = fir.absent !fir.box<!fir.array<?xi32>>
// CHECK: fir.result %[[VAL_7]] : !fir.box<!fir.array<?xi32>>
// CHECK: }
+
+func.func @dummy_scope(%arg0: !fir.ref<f32>) {
+ %scope = fir.dummy_scope : i1
+ %0:2 = hlfir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ return
+}
+// CHECK-LABEL: func.func @dummy_scope(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
+// CHECK: %[[SCOPE:.*]] = fir.dummy_scope : i1
+// CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[SCOPE]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
>From efba91f7a6f1ffce22d15277c7f586b8f03c2b00 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Tue, 30 Apr 2024 09:56:04 -0700
Subject: [PATCH 3/4] [flang] PreCGRewrite for fir.dummy_scope.
---
flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp | 18 +++++++++++++++++-
flang/test/Fir/dummy-scope-codegen.fir | 9 +++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Fir/dummy-scope-codegen.fir
diff --git a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
index ce7ee22d5d7744..5bd3ec8d18450e 100644
--- a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp
@@ -281,6 +281,20 @@ class DeclareOpConversion : public mlir::OpRewritePattern<fir::DeclareOp> {
}
};
+class DummyScopeOpConversion
+ : public mlir::OpRewritePattern<fir::DummyScopeOp> {
+public:
+ using OpRewritePattern::OpRewritePattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(fir::DummyScopeOp dummyScopeOp,
+ mlir::PatternRewriter &rewriter) const override {
+ rewriter.replaceOpWithNewOp<fir::UndefOp>(dummyScopeOp,
+ dummyScopeOp.getType());
+ return mlir::success();
+ }
+};
+
class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
public:
void runOnOperation() override final {
@@ -293,6 +307,7 @@ class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
target.addIllegalOp<fir::ArrayCoorOp>();
target.addIllegalOp<fir::ReboxOp>();
target.addIllegalOp<fir::DeclareOp>();
+ target.addIllegalOp<fir::DummyScopeOp>();
target.addDynamicallyLegalOp<fir::EmboxOp>([](fir::EmboxOp embox) {
return !(embox.getShape() ||
mlir::isa<fir::SequenceType>(
@@ -321,5 +336,6 @@ std::unique_ptr<mlir::Pass> fir::createFirCodeGenRewritePass() {
void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns) {
patterns.insert<EmboxConversion, ArrayCoorConversion, ReboxConversion,
- DeclareOpConversion>(patterns.getContext());
+ DeclareOpConversion, DummyScopeOpConversion>(
+ patterns.getContext());
}
diff --git a/flang/test/Fir/dummy-scope-codegen.fir b/flang/test/Fir/dummy-scope-codegen.fir
new file mode 100644
index 00000000000000..d8bdd0a822a5f0
--- /dev/null
+++ b/flang/test/Fir/dummy-scope-codegen.fir
@@ -0,0 +1,9 @@
+// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s
+
+func.func @dummy_scope(%arg0: !fir.ref<f32>) {
+ %scope = fir.dummy_scope : i1
+ %0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ return
+}
+// CHECK-LABEL: func.func @dummy_scope(
+// CHECK-NEXT: return
>From d0df3aed57ea4219612fd2fa78dc88815fd6541a Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Tue, 30 Apr 2024 13:30:19 -0700
Subject: [PATCH 4/4] Use fir.dscope type for the result type of
fir.dummy_scope.
---
.../include/flang/Optimizer/Dialect/FIROps.td | 4 +--
.../flang/Optimizer/Dialect/FIRTypes.td | 11 +++++++
.../include/flang/Optimizer/HLFIR/HLFIROps.td | 2 +-
flang/lib/Optimizer/CodeGen/TypeConverter.cpp | 5 +++
flang/lib/Optimizer/Dialect/FIRType.cpp | 2 +-
flang/test/Fir/dummy-scope-codegen.fir | 4 +--
flang/test/Fir/dummy_scope.fir | 32 +++++++++----------
flang/test/HLFIR/declare-codegen.fir | 8 ++---
flang/test/HLFIR/dummy_scope.fir | 32 +++++++++----------
9 files changed, 58 insertions(+), 42 deletions(-)
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index d15063c685fd36..dc38e56d93c664 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -3074,7 +3074,7 @@ def fir_DeclareOp : fir_Op<"declare", [AttrSizedOperandSegments,
AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
- Optional<I1>:$dummy_scope,
+ Optional<fir_DummyScopeType>:$dummy_scope,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<fir_CUDADataAttributeAttr>:$cuda_attr
@@ -3325,7 +3325,7 @@ def fir_DummyScopeOp : fir_Op<"dummy_scope",
This is guaranteed by the write memory effect on the DebuggingResource.
}];
- let results = (outs I1);
+ let results = (outs fir_DummyScopeType);
let assemblyFormat = "attr-dict `:` type(results)";
}
diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
index 7378ed93944c95..ae984de63db428 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td
@@ -576,6 +576,17 @@ def fir_VoidType : FIR_Type<"Void", "void"> {
let genStorageClass = 0;
}
+def fir_DummyScopeType : FIR_Type<"DummyScope", "dscope"> {
+ let summary = "Dummy scope type";
+
+ let description = [{
+ `fir.dscope` is a type returned by fir.dummy_scope operation.
+ It defines a unique identifier for a runtime instance of a subroutine
+ that is used by the [hl]fir.declare operations representing
+ the dummy arguments' declarations.
+ }];
+}
+
// Whether a type is a BaseBoxType
def IsBaseBoxTypePred
: CPred<"mlir::isa<::fir::BaseBoxType>($_self)">;
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index be0bb770a3e171..ee3c26800ae3a9 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -87,7 +87,7 @@ def hlfir_DeclareOp : hlfir_Op<"declare", [AttrSizedOperandSegments,
AnyRefOrBox:$memref,
Optional<AnyShapeOrShiftType>:$shape,
Variadic<AnyIntegerType>:$typeparams,
- Optional<I1>:$dummy_scope,
+ Optional<fir_DummyScopeType>:$dummy_scope,
Builtin_StringAttr:$uniq_name,
OptionalAttr<fir_FortranVariableFlagsAttr>:$fortran_attrs,
OptionalAttr<fir_CUDADataAttributeAttr>:$cuda_attr
diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
index fb2ec3f0b2f5e7..729ece6fc17742 100644
--- a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
+++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
@@ -115,6 +115,11 @@ LLVMTypeConverter::LLVMTypeConverter(mlir::ModuleOp module, bool applyTBAA,
return mlir::LLVM::LLVMStructType::getLiteral(
none.getContext(), std::nullopt, /*isPacked=*/false);
});
+ addConversion([&](fir::DummyScopeType dscope) {
+ // DummyScopeType values must not have any uses after PreCGRewrite.
+ // Convert it here to i1 just in case it survives.
+ return mlir::IntegerType::get(&getContext(), 1);
+ });
// FIXME: https://reviews.llvm.org/D82831 introduced an automatic
// materialization of conversion around function calls that is not working
// well with fir lowering to llvm (incorrect llvm.mlir.cast are inserted).
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index d9c387ad950e82..daa3ac905dad5c 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -1340,7 +1340,7 @@ void FIROpsDialect::registerTypes() {
fir::ComplexType, FieldType, HeapType, fir::IntegerType, LenType,
LogicalType, LLVMPointerType, PointerType, RealType, RecordType,
ReferenceType, SequenceType, ShapeType, ShapeShiftType, ShiftType,
- SliceType, TypeDescType, fir::VectorType>();
+ SliceType, TypeDescType, fir::VectorType, fir::DummyScopeType>();
fir::ReferenceType::attachInterface<
OpenMPPointerLikeModel<fir::ReferenceType>>(*getContext());
fir::ReferenceType::attachInterface<
diff --git a/flang/test/Fir/dummy-scope-codegen.fir b/flang/test/Fir/dummy-scope-codegen.fir
index d8bdd0a822a5f0..caef3c1b257832 100644
--- a/flang/test/Fir/dummy-scope-codegen.fir
+++ b/flang/test/Fir/dummy-scope-codegen.fir
@@ -1,8 +1,8 @@
// RUN: fir-opt --cg-rewrite %s -o - | FileCheck %s
func.func @dummy_scope(%arg0: !fir.ref<f32>) {
- %scope = fir.dummy_scope : i1
- %0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ %scope = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
return
}
// CHECK-LABEL: func.func @dummy_scope(
diff --git a/flang/test/Fir/dummy_scope.fir b/flang/test/Fir/dummy_scope.fir
index 8def2759fb77d6..58985923a8f445 100644
--- a/flang/test/Fir/dummy_scope.fir
+++ b/flang/test/Fir/dummy_scope.fir
@@ -3,32 +3,32 @@
// CHECK-LABEL: func.func @dummy_scope(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
-// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
// CHECK: return
// CHECK: }
func.func @dummy_scope(%arg0: !fir.ref<f32>) {
- %scope = fir.dummy_scope : i1
- %0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ %scope = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
return
}
// CHECK-LABEL: func.func @dummy_scopes(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
-// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
-// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_3]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
-// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_5]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_3]] {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_5]] {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
// CHECK: return
// CHECK: }
func.func @dummy_scopes(%arg0: !fir.ref<f32>) {
- %scope_out = fir.dummy_scope : i1
- %0 = fir.declare %arg0 dummy_scope %scope_out {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
- %scope_in1 = fir.dummy_scope : i1
- %1 = fir.declare %arg0 dummy_scope %scope_in1 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
- %scope_in2 = fir.dummy_scope : i1
- %2 = fir.declare %arg0 dummy_scope %scope_in2 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+ %scope_out = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %scope_out {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %scope_in1 = fir.dummy_scope : !fir.dscope
+ %1 = fir.declare %arg0 dummy_scope %scope_in1 {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %scope_in2 = fir.dummy_scope : !fir.dscope
+ %2 = fir.declare %arg0 dummy_scope %scope_in2 {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
return
}
diff --git a/flang/test/HLFIR/declare-codegen.fir b/flang/test/HLFIR/declare-codegen.fir
index d079aa776a3a9c..9f51d0fbc7afd7 100644
--- a/flang/test/HLFIR/declare-codegen.fir
+++ b/flang/test/HLFIR/declare-codegen.fir
@@ -202,11 +202,11 @@ func.func @test_optional_declare(%arg0: !fir.box<!fir.array<?xi32>>) {
// CHECK: }
func.func @dummy_scope(%arg0: !fir.ref<f32>) {
- %scope = fir.dummy_scope : i1
- %0:2 = hlfir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %scope = fir.dummy_scope : !fir.dscope
+ %0:2 = hlfir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
return
}
// CHECK-LABEL: func.func @dummy_scope(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
-// CHECK: %[[SCOPE:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[SCOPE]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> !fir.ref<f32>
+// CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[SCOPE]] {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
diff --git a/flang/test/HLFIR/dummy_scope.fir b/flang/test/HLFIR/dummy_scope.fir
index 304ebccfbe3197..6b5c61e21f1d1c 100644
--- a/flang/test/HLFIR/dummy_scope.fir
+++ b/flang/test/HLFIR/dummy_scope.fir
@@ -3,32 +3,32 @@
// CHECK-LABEL: func.func @dummy_scope(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
-// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
// CHECK: return
// CHECK: }
func.func @dummy_scope(%arg0: !fir.ref<f32>) {
- %scope = fir.dummy_scope : i1
- %0:2 = hlfir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %scope = fir.dummy_scope : !fir.dscope
+ %0:2 = hlfir.declare %arg0 dummy_scope %scope {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
return
}
// CHECK-LABEL: func.func @dummy_scopes(
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32>) {
-// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
-// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_3]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
-// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : i1
-// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_5]] {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_3]] {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
+// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_5]] {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
// CHECK: return
// CHECK: }
func.func @dummy_scopes(%arg0: !fir.ref<f32>) {
- %scope_out = fir.dummy_scope : i1
- %0:2 = hlfir.declare %arg0 dummy_scope %scope_out {uniq_name = "x"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
- %scope_in1 = fir.dummy_scope : i1
- %1:2 = hlfir.declare %arg0 dummy_scope %scope_in1 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
- %scope_in2 = fir.dummy_scope : i1
- %2:2 = hlfir.declare %arg0 dummy_scope %scope_in2 {uniq_name = "innerEx"} : (!fir.ref<f32>, i1) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %scope_out = fir.dummy_scope : !fir.dscope
+ %0:2 = hlfir.declare %arg0 dummy_scope %scope_out {uniq_name = "x"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %scope_in1 = fir.dummy_scope : !fir.dscope
+ %1:2 = hlfir.declare %arg0 dummy_scope %scope_in1 {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
+ %scope_in2 = fir.dummy_scope : !fir.dscope
+ %2:2 = hlfir.declare %arg0 dummy_scope %scope_in2 {uniq_name = "innerEx"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
return
}
More information about the flang-commits
mailing list