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
23namespace 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
30namespace {
31class PropagateFortranVariableAttributes
32 : public hlfir::impl::PropagateFortranVariableAttributesBase<
33 PropagateFortranVariableAttributes> {
34public:
35 using PropagateFortranVariableAttributesBase<
36 PropagateFortranVariableAttributes>::
37 PropagateFortranVariableAttributesBase;
38 void runOnOperation() override;
39};
40
41class Propagator {
42public:
43 void process(mlir::Operation *op);
44
45private:
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
64void 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
72void 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
117void 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}
127

source code of flang/lib/Optimizer/HLFIR/Transforms/PropagateFortranVariableAttributes.cpp