Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2d12d31

Browse filesBrowse files
authored
[flang] Propagate contiguous attribute through HLFIR. (#138797)
This change allows marking more designators producing an opaque box with 'contiguous' attribute, e.g. like in test1 case in flang/test/HLFIR/propagate-contiguous-attribute.fir. This would make isSimplyContiguous() return true for such designators allowing merging hlfir.eval_in_mem with hlfir.assign where the LHS is a contiguous array section. Depends on #139003
1 parent 3aad7d7 commit 2d12d31
Copy full SHA for 2d12d31

File tree

14 files changed

+551
-72
lines changed
Filter options

14 files changed

+551
-72
lines changed

‎flang/include/flang/Optimizer/Builder/HLFIRTools.h

Copy file name to clipboardExpand all lines: flang/include/flang/Optimizer/Builder/HLFIRTools.h
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "flang/Optimizer/Dialect/FIROps.h"
1818
#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
1919
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
20+
#include "flang/Optimizer/HLFIR/HLFIROps.h"
2021
#include <optional>
2122

2223
namespace fir {
@@ -533,6 +534,12 @@ Entity gen1DSection(mlir::Location loc, fir::FirOpBuilder &builder,
533534
mlir::ArrayRef<mlir::Value> extents,
534535
mlir::ValueRange oneBasedIndices,
535536
mlir::ArrayRef<mlir::Value> typeParams);
537+
538+
/// Return true iff the given hlfir.designate produces
539+
/// a contiguous part of the memref object given that it is
540+
/// contiguous.
541+
bool designatePreservesContinuity(hlfir::DesignateOp op);
542+
536543
} // namespace hlfir
537544

538545
#endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H

‎flang/include/flang/Optimizer/Dialect/FIROpsSupport.h

Copy file name to clipboardExpand all lines: flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ inline bool hasBindcAttr(mlir::Operation *op) {
221221
return hasProcedureAttr<fir::FortranProcedureFlagsEnum::bind_c>(op);
222222
}
223223

224+
/// Return true, if \p rebox operation keeps the input array
225+
/// continuous if it is initially continuous.
226+
/// When \p checkWhole is false, then the checking is only done
227+
/// for continuity in the innermost dimension, otherwise,
228+
/// the checking is done for continuity of the whole result of rebox.
229+
bool reboxPreservesContinuity(fir::ReboxOp rebox, bool checkWhole = true);
230+
224231
} // namespace fir
225232

226233
#endif // FORTRAN_OPTIMIZER_DIALECT_FIROPSSUPPORT_H

‎flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td

Copy file name to clipboardExpand all lines: flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
+43-37Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,51 +22,57 @@ def fir_FortranVariableOpInterface : OpInterface<"FortranVariableOpInterface"> {
2222
query about all their Fortran properties.
2323
}];
2424

25-
let methods = [
26-
InterfaceMethod<
27-
/*desc=*/"Get the address produced by the definition",
28-
/*retTy=*/"mlir::Value",
29-
/*methodName=*/"getBase",
30-
/*args=*/(ins),
31-
/*methodBody=*/[{}],
32-
/*defaultImplementation=*/[{
25+
let methods =
26+
[InterfaceMethod<
27+
/*desc=*/"Get the address produced by the definition",
28+
/*retTy=*/"mlir::Value",
29+
/*methodName=*/"getBase",
30+
/*args=*/(ins),
31+
/*methodBody=*/[{}],
32+
/*defaultImplementation=*/[{
3333
ConcreteOp op = mlir::cast<ConcreteOp>(this->getOperation());
3434
return op.getResult();
35-
}]
36-
>,
37-
InterfaceMethod<
38-
/*desc=*/"Get Fortran attributes",
39-
/*retTy=*/"std::optional<fir::FortranVariableFlagsEnum>",
40-
/*methodName=*/"getFortranAttrs",
41-
/*args=*/(ins),
42-
/*methodBody=*/[{}],
43-
/*defaultImplementation=*/[{
35+
}]>,
36+
InterfaceMethod<
37+
/*desc=*/"Get Fortran attributes",
38+
/*retTy=*/"std::optional<fir::FortranVariableFlagsEnum>",
39+
/*methodName=*/"getFortranAttrs",
40+
/*args=*/(ins),
41+
/*methodBody=*/[{}],
42+
/*defaultImplementation=*/[{
4443
ConcreteOp op = mlir::cast<ConcreteOp>(this->getOperation());
4544
return op.getFortran_attrs();
46-
}]
47-
>,
48-
InterfaceMethod<
49-
/*desc=*/"Get the shape of the variable. May be a null value.",
50-
/*retTy=*/"mlir::Value",
51-
/*methodName=*/"getShape",
52-
/*args=*/(ins),
53-
/*methodBody=*/[{}],
54-
/*defaultImplementation=*/[{
45+
}]>,
46+
InterfaceMethod<
47+
/*desc=*/"Get the shape of the variable. May be a null value.",
48+
/*retTy=*/"mlir::Value",
49+
/*methodName=*/"getShape",
50+
/*args=*/(ins),
51+
/*methodBody=*/[{}],
52+
/*defaultImplementation=*/[{
5553
ConcreteOp op = mlir::cast<ConcreteOp>(this->getOperation());
5654
return op.getShape();
57-
}]
58-
>,
59-
InterfaceMethod<
60-
/*desc=*/"Get explicit type parameters of the variable",
61-
/*retTy=*/"mlir::OperandRange",
62-
/*methodName=*/"getExplicitTypeParams",
63-
/*args=*/(ins),
64-
/*methodBody=*/[{}],
65-
/*defaultImplementation=*/[{
55+
}]>,
56+
InterfaceMethod<
57+
/*desc=*/"Get explicit type parameters of the variable",
58+
/*retTy=*/"mlir::OperandRange",
59+
/*methodName=*/"getExplicitTypeParams",
60+
/*args=*/(ins),
61+
/*methodBody=*/[{}],
62+
/*defaultImplementation=*/[{
6663
ConcreteOp op = mlir::cast<ConcreteOp>(this->getOperation());
6764
return op.getTypeparams();
68-
}]
69-
>,
65+
}]>,
66+
InterfaceMethod<
67+
/*desc=*/"Set Fortran attributes",
68+
/*retTy=*/"void",
69+
/*methodName=*/"setFortranAttrs",
70+
/*args=*/(ins "fir::FortranVariableFlagsEnum":$flags),
71+
/*methodBody=*/[{}],
72+
/*defaultImplementation=*/[{
73+
ConcreteOp op = mlir::cast<ConcreteOp>(this->getOperation());
74+
op.setFortran_attrs(fir::FortranVariableFlagsAttr::get(op->getContext(), flags));
75+
}]>,
7076
];
7177

7278
let extraClassDeclaration = [{

‎flang/include/flang/Optimizer/HLFIR/HLFIROps.td

Copy file name to clipboardExpand all lines: flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ def hlfir_ParentComponentOp : hlfir_Op<"parent_comp", [AttrSizedOperandSegments,
313313
std::optional<fir::FortranVariableFlagsEnum> getFortranAttrs() const {
314314
return std::nullopt;
315315
}
316+
void setFortranAttrs(fir::FortranVariableFlagsEnum flags) {}
316317
}];
317318

318319
let results = (outs AnyFortranVariable);
@@ -1078,6 +1079,7 @@ def hlfir_NullOp : hlfir_Op<"null", [NoMemoryEffect, fir_FortranVariableOpInterf
10781079
std::optional<fir::FortranVariableFlagsEnum> getFortranAttrs() const {
10791080
return std::nullopt;
10801081
}
1082+
void setFortranAttrs(fir::FortranVariableFlagsEnum flags) {}
10811083
mlir::Value getShape() const {return mlir::Value{};}
10821084
mlir::OperandRange getExplicitTypeParams() const {
10831085
// Return an empty range.
@@ -1766,6 +1768,7 @@ def hlfir_ForallIndexOp : hlfir_Op<"forall_index", [fir_FortranVariableOpInterfa
17661768
std::optional<fir::FortranVariableFlagsEnum> getFortranAttrs() const {
17671769
return std::nullopt;
17681770
}
1771+
void setFortranAttrs(fir::FortranVariableFlagsEnum flags) {}
17691772
mlir::Value getShape() const {return mlir::Value{};}
17701773
mlir::OperandRange getExplicitTypeParams() const {
17711774
// Return an empty range.

‎flang/include/flang/Optimizer/HLFIR/Passes.td

Copy file name to clipboardExpand all lines: flang/include/flang/Optimizer/HLFIR/Passes.td
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,8 @@ def InlineHLFIRAssign : Pass<"inline-hlfir-assign"> {
6969
let summary = "Inline hlfir.assign operations";
7070
}
7171

72+
def PropagateFortranVariableAttributes : Pass<"propagate-fortran-attrs"> {
73+
let summary = "Propagate FortranVariableFlagsAttr attributes through HLFIR";
74+
}
75+
7276
#endif //FORTRAN_DIALECT_HLFIR_PASSES

‎flang/lib/Optimizer/Builder/HLFIRTools.cpp

Copy file name to clipboardExpand all lines: flang/lib/Optimizer/Builder/HLFIRTools.cpp
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,3 +1633,32 @@ hlfir::Entity hlfir::gen1DSection(mlir::Location loc,
16331633
sectionShape, typeParams);
16341634
return hlfir::Entity{designate.getResult()};
16351635
}
1636+
1637+
bool hlfir::designatePreservesContinuity(hlfir::DesignateOp op) {
1638+
if (op.getComponent() || op.getComplexPart() || !op.getSubstring().empty())
1639+
return false;
1640+
auto subscripts = op.getIndices();
1641+
unsigned i = 0;
1642+
for (auto isTriplet : llvm::enumerate(op.getIsTriplet())) {
1643+
// TODO: we should allow any number of leading triplets
1644+
// that describe a whole dimension slice, then one optional
1645+
// triplet describing potentially partial dimension slice,
1646+
// then any number of non-triplet subscripts.
1647+
// For the time being just allow a single leading
1648+
// triplet and then any number of non-triplet subscripts.
1649+
if (isTriplet.value()) {
1650+
if (isTriplet.index() != 0) {
1651+
return false;
1652+
} else {
1653+
i += 2;
1654+
mlir::Value step = subscripts[i++];
1655+
auto constantStep = fir::getIntIfConstant(step);
1656+
if (!constantStep || *constantStep != 1)
1657+
return false;
1658+
}
1659+
} else {
1660+
++i;
1661+
}
1662+
}
1663+
return true;
1664+
}

‎flang/lib/Optimizer/Dialect/FIROps.cpp

Copy file name to clipboardExpand all lines: flang/lib/Optimizer/Dialect/FIROps.cpp
+42Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4721,6 +4721,48 @@ mlir::Type fir::applyPathToType(mlir::Type eleTy, mlir::ValueRange path) {
47214721
return eleTy;
47224722
}
47234723

4724+
bool fir::reboxPreservesContinuity(fir::ReboxOp rebox, bool checkWhole) {
4725+
// If slicing is not involved, then the rebox does not affect
4726+
// the continuity of the array.
4727+
auto sliceArg = rebox.getSlice();
4728+
if (!sliceArg)
4729+
return true;
4730+
4731+
if (auto sliceOp =
4732+
mlir::dyn_cast_or_null<fir::SliceOp>(sliceArg.getDefiningOp())) {
4733+
if (sliceOp.getFields().empty() && sliceOp.getSubstr().empty()) {
4734+
// TODO: generalize code for the triples analysis with
4735+
// hlfir::designatePreservesContinuity, especially when
4736+
// recognition of the whole dimension slices is added.
4737+
auto triples = sliceOp.getTriples();
4738+
assert((triples.size() % 3) == 0 && "invalid triples size");
4739+
4740+
// A slice with step=1 in the innermost dimension preserves
4741+
// the continuity of the array in the innermost dimension.
4742+
// If checkWhole is false, then check only the innermost slice triples.
4743+
std::size_t checkUpTo = checkWhole ? triples.size() : 3;
4744+
checkUpTo = std::min(checkUpTo, triples.size());
4745+
for (std::size_t i = 0; i < checkUpTo; i += 3) {
4746+
if (triples[i] != triples[i + 1]) {
4747+
// This is a section of the dimension. Only allow it
4748+
// to be the first triple.
4749+
if (i != 0)
4750+
return false;
4751+
auto constantStep = fir::getIntIfConstant(triples[i + 2]);
4752+
if (!constantStep || *constantStep != 1)
4753+
return false;
4754+
}
4755+
}
4756+
return true;
4757+
}
4758+
}
4759+
return false;
4760+
}
4761+
4762+
//===----------------------------------------------------------------------===//
4763+
// DeclareOp
4764+
//===----------------------------------------------------------------------===//
4765+
47244766
llvm::LogicalResult fir::DeclareOp::verify() {
47254767
auto fortranVar =
47264768
mlir::cast<fir::FortranVariableOpInterface>(this->getOperation());

‎flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt

Copy file name to clipboardExpand all lines: flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_flang_library(HLFIRTransforms
1010
ScheduleOrderedAssignments.cpp
1111
SimplifyHLFIRIntrinsics.cpp
1212
OptimizedBufferization.cpp
13+
PropagateFortranVariableAttributes.cpp
1314

1415
DEPENDS
1516
CUFAttrsIncGen
+126Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//===- PropagateFortranVariableAttributes.cpp -----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
/// \file
9+
/// This file defines a pass that propagates FortranVariableFlagsAttr
10+
/// attributes through HLFIR. For example, it can set contiguous attribute
11+
/// on hlfir.designate that produces a contiguous slice of a contiguous
12+
/// Fortran array. This pass can be applied multiple times to expose
13+
/// more Fortran attributes, e.g. after inlining and constant propagation.
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "flang/Optimizer/Builder/HLFIRTools.h"
17+
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
18+
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
19+
#include "flang/Optimizer/HLFIR/HLFIROps.h"
20+
#include "flang/Optimizer/HLFIR/Passes.h"
21+
#include "llvm/ADT/TypeSwitch.h"
22+
23+
namespace hlfir {
24+
#define GEN_PASS_DEF_PROPAGATEFORTRANVARIABLEATTRIBUTES
25+
#include "flang/Optimizer/HLFIR/Passes.h.inc"
26+
} // namespace hlfir
27+
28+
#define DEBUG_TYPE "propagate-fortran-attrs"
29+
30+
namespace {
31+
class PropagateFortranVariableAttributes
32+
: public hlfir::impl::PropagateFortranVariableAttributesBase<
33+
PropagateFortranVariableAttributes> {
34+
public:
35+
using PropagateFortranVariableAttributesBase<
36+
PropagateFortranVariableAttributes>::
37+
PropagateFortranVariableAttributesBase;
38+
void runOnOperation() override;
39+
};
40+
41+
class Propagator {
42+
public:
43+
void process(mlir::Operation *op);
44+
45+
private:
46+
static bool isContiguous(mlir::Operation *op) {
47+
// Treat data allocations as contiguous, so that we can propagate
48+
// the continuity from them. Allocations of fir.box must not be treated
49+
// as contiguous.
50+
if (mlir::isa<fir::AllocaOp, fir::AllocMemOp>(op) &&
51+
!mlir::isa<fir::BaseBoxType>(
52+
fir::unwrapRefType(op->getResult(0).getType())))
53+
return true;
54+
auto varOp = mlir::dyn_cast<fir::FortranVariableOpInterface>(op);
55+
if (!varOp)
56+
return false;
57+
return hlfir::Entity{varOp}.isSimplyContiguous();
58+
}
59+
60+
static void setContiguousAttr(fir::FortranVariableOpInterface op);
61+
};
62+
} // namespace
63+
64+
void Propagator::setContiguousAttr(fir::FortranVariableOpInterface op) {
65+
LLVM_DEBUG(llvm::dbgs() << "Setting continuity for:\n" << op << "\n");
66+
fir::FortranVariableFlagsEnum attrs =
67+
op.getFortranAttrs().value_or(fir::FortranVariableFlagsEnum::None);
68+
attrs = attrs | fir::FortranVariableFlagsEnum::contiguous;
69+
op.setFortranAttrs(attrs);
70+
}
71+
72+
void Propagator::process(mlir::Operation *op) {
73+
if (!isContiguous(op))
74+
return;
75+
llvm::SmallVector<mlir::Operation *> workList{op};
76+
while (!workList.empty()) {
77+
mlir::Operation *current = workList.pop_back_val();
78+
LLVM_DEBUG(llvm::dbgs() << "Propagating continuity from operation:\n"
79+
<< *current << "\n");
80+
81+
for (mlir::OpOperand &use : current->getUses()) {
82+
mlir::Operation *useOp = use.getOwner();
83+
if (auto varOp = mlir::dyn_cast<fir::FortranVariableOpInterface>(useOp)) {
84+
// If the user is not currently contiguous, set the contiguous
85+
// attribute and skip it. The propagation will pick it up later.
86+
mlir::Value memref;
87+
mlir::TypeSwitch<mlir::Operation *, void>(useOp)
88+
.Case<hlfir::DeclareOp, hlfir::DesignateOp>(
89+
[&](auto op) { memref = op.getMemref(); })
90+
.Default([&](auto op) {});
91+
92+
if (memref == use.get() && !isContiguous(varOp)) {
93+
// Make additional checks for hlfir.designate.
94+
if (auto designateOp = mlir::dyn_cast<hlfir::DesignateOp>(useOp))
95+
if (!hlfir::designatePreservesContinuity(designateOp))
96+
continue;
97+
98+
setContiguousAttr(varOp);
99+
}
100+
continue;
101+
}
102+
mlir::TypeSwitch<mlir::Operation *, void>(useOp)
103+
.Case(
104+
[&](fir::ConvertOp op) { workList.push_back(op.getOperation()); })
105+
.Case([&](fir::EmboxOp op) {
106+
if (op.getMemref() == use.get())
107+
workList.push_back(op.getOperation());
108+
})
109+
.Case([&](fir::ReboxOp op) {
110+
if (op.getBox() == use.get() && fir::reboxPreservesContinuity(op))
111+
workList.push_back(op.getOperation());
112+
});
113+
}
114+
}
115+
}
116+
117+
void PropagateFortranVariableAttributes::runOnOperation() {
118+
mlir::Operation *rootOp = getOperation();
119+
mlir::MLIRContext *context = &getContext();
120+
mlir::RewritePatternSet patterns(context);
121+
Propagator propagator;
122+
rootOp->walk<mlir::WalkOrder::PreOrder>([&](mlir::Operation *op) {
123+
propagator.process(op);
124+
return mlir::WalkResult::advance();
125+
});
126+
}

‎flang/lib/Optimizer/Passes/Pipelines.cpp

Copy file name to clipboardExpand all lines: flang/lib/Optimizer/Passes/Pipelines.cpp
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ void createHLFIRToFIRPassPipeline(mlir::PassManager &pm, bool enableOpenMP,
249249
return hlfir::createSimplifyHLFIRIntrinsics(
250250
{/*allowNewSideEffects=*/true});
251251
});
252+
addNestedPassToAllTopLevelOperations<PassConstructor>(
253+
pm, hlfir::createPropagateFortranVariableAttributes);
252254
addNestedPassToAllTopLevelOperations<PassConstructor>(
253255
pm, hlfir::createOptimizedBufferization);
254256
addNestedPassToAllTopLevelOperations<PassConstructor>(

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.