127 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8/// \file9/// This file defines a pass that propagates FortranVariableFlagsAttr10/// attributes through HLFIR. For example, it can set contiguous attribute11/// on hlfir.designate that produces a contiguous slice of a contiguous12/// Fortran array. This pass can be applied multiple times to expose13/// 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_PROPAGATEFORTRANVARIABLEATTRIBUTES25#include "flang/Optimizer/HLFIR/Passes.h.inc"26} // namespace hlfir27 28#define DEBUG_TYPE "propagate-fortran-attrs"29 30namespace {31class PropagateFortranVariableAttributes32 : 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 propagate48 // the continuity from them. Allocations of fir.box must not be treated49 // 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} // namespace63 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 contiguous85 // 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