Delay materialization of branches when building local temporary descriptor for OPTIONAL from hlfir-to-fir until pre-cg-rewrite. This makes the IR easier to analyze with OPTIONAL (for instance alias analysis does not need to handle the branches to find the source). This is done by adding an "optional" attribute to fir.embox, fir.rebox, and fir.rebox_assumed_rank to indicate that their cogeneration must be conditional. The conditional aspect is implemented in pre-cg-rewrite to avoid complexifying codegen and the fir.cg dialect. Assisted by: Claude
480 lines
19 KiB
C++
480 lines
19 KiB
C++
//===-- PreCGRewrite.cpp --------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "flang/Optimizer/CodeGen/CodeGen.h"
|
|
|
|
#include "flang/Optimizer/Builder/Todo.h" // remove when TODO's are done
|
|
#include "flang/Optimizer/Dialect/FIRCG/CGOps.h"
|
|
#include "flang/Optimizer/Dialect/FIRDialect.h"
|
|
#include "flang/Optimizer/Dialect/FIROps.h"
|
|
#include "flang/Optimizer/Dialect/FIRType.h"
|
|
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
|
|
#include "mlir/Dialect/ControlFlow/IR/ControlFlow.h"
|
|
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
|
|
#include "mlir/IR/Iterators.h"
|
|
#include "mlir/Transforms/DialectConversion.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
namespace fir {
|
|
#define GEN_PASS_DEF_CODEGENREWRITE
|
|
#include "flang/Optimizer/CodeGen/CGPasses.h.inc"
|
|
} // namespace fir
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Codegen rewrite: rewriting of subgraphs of ops
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "flang-codegen-rewrite"
|
|
|
|
static void populateShape(llvm::SmallVectorImpl<mlir::Value> &vec,
|
|
fir::ShapeOp shape) {
|
|
vec.append(shape.getExtents().begin(), shape.getExtents().end());
|
|
}
|
|
|
|
// Operands of fir.shape_shift split into two vectors.
|
|
static void populateShapeAndShift(llvm::SmallVectorImpl<mlir::Value> &shapeVec,
|
|
llvm::SmallVectorImpl<mlir::Value> &shiftVec,
|
|
fir::ShapeShiftOp shift) {
|
|
for (auto i = shift.getPairs().begin(), endIter = shift.getPairs().end();
|
|
i != endIter;) {
|
|
shiftVec.push_back(*i++);
|
|
shapeVec.push_back(*i++);
|
|
}
|
|
}
|
|
|
|
static void populateShift(llvm::SmallVectorImpl<mlir::Value> &vec,
|
|
fir::ShiftOp shift) {
|
|
vec.append(shift.getOrigins().begin(), shift.getOrigins().end());
|
|
}
|
|
|
|
// Helper to emit embox/rebox for OPTIONAL input inside a block
|
|
// guarded by a runtime presence check and to return an absent
|
|
// box when the input is not present.
|
|
template <typename OP>
|
|
static mlir::Value
|
|
emitOptionalBoxGuard(mlir::PatternRewriter &rewriter, OP op,
|
|
llvm::function_ref<mlir::Value()> buildPresent) {
|
|
mlir::Location loc = op.getLoc();
|
|
mlir::Type boxType = op.getResult().getType();
|
|
mlir::Value isPresent = fir::IsPresentOp::create(
|
|
rewriter, loc, rewriter.getI1Type(), op->getOperand(0));
|
|
mlir::Block *condBlock = op->getBlock();
|
|
mlir::Block *mergeBlock = rewriter.splitBlock(condBlock, op->getIterator());
|
|
mergeBlock->addArgument(boxType, loc);
|
|
|
|
mlir::Block *thenBlock = rewriter.createBlock(mergeBlock);
|
|
rewriter.setInsertionPointToStart(thenBlock);
|
|
mlir::Value present = buildPresent();
|
|
mlir::cf::BranchOp::create(rewriter, loc, mergeBlock,
|
|
mlir::ValueRange{present});
|
|
|
|
mlir::Block *elseBlock = rewriter.createBlock(mergeBlock);
|
|
rewriter.setInsertionPointToStart(elseBlock);
|
|
mlir::Value absent = fir::AbsentOp::create(rewriter, loc, boxType);
|
|
mlir::cf::BranchOp::create(rewriter, loc, mergeBlock,
|
|
mlir::ValueRange{absent});
|
|
|
|
rewriter.setInsertionPointToEnd(condBlock);
|
|
mlir::cf::CondBranchOp::create(rewriter, loc, isPresent, thenBlock,
|
|
elseBlock);
|
|
rewriter.setInsertionPointToStart(mergeBlock);
|
|
return mergeBlock->getArgument(0);
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// Convert fir.embox to the extended form where necessary.
|
|
///
|
|
/// The embox operation can take arguments that specify multidimensional array
|
|
/// properties at runtime. These properties may be shared between distinct
|
|
/// objects that have the same properties. Before we lower these small DAGs to
|
|
/// LLVM-IR, we gather all the information into a single extended operation. For
|
|
/// example,
|
|
/// ```
|
|
/// %1 = fir.shape_shift %4, %5 : (index, index) -> !fir.shapeshift<1>
|
|
/// %2 = fir.slice %6, %7, %8 : (index, index, index) -> !fir.slice<1>
|
|
/// %3 = fir.embox %0 (%1) [%2] : (!fir.ref<!fir.array<?xi32>>,
|
|
/// !fir.shapeshift<1>, !fir.slice<1>) -> !fir.box<!fir.array<?xi32>>
|
|
/// ```
|
|
/// can be rewritten as
|
|
/// ```
|
|
/// %1 = fircg.ext_embox %0(%5) origin %4[%6, %7, %8] :
|
|
/// (!fir.ref<!fir.array<?xi32>>, index, index, index, index, index) ->
|
|
/// !fir.box<!fir.array<?xi32>>
|
|
/// ```
|
|
class EmboxConversion : public mlir::OpRewritePattern<fir::EmboxOp> {
|
|
public:
|
|
using OpRewritePattern::OpRewritePattern;
|
|
|
|
enum class RewriteKind { Dynamic, Static, DropOptional };
|
|
|
|
static llvm::FailureOr<RewriteKind> getRewriteKind(fir::EmboxOp embox) {
|
|
if (auto shapeVal = embox.getShape())
|
|
return RewriteKind::Dynamic;
|
|
if (auto boxTy = mlir::dyn_cast<fir::BoxType>(embox.getType()))
|
|
if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(boxTy.getEleTy()))
|
|
if (!seqTy.hasDynamicExtents())
|
|
return RewriteKind::Static;
|
|
if (embox.getOptional())
|
|
return RewriteKind::DropOptional;
|
|
return llvm::failure();
|
|
}
|
|
|
|
llvm::LogicalResult
|
|
matchAndRewrite(fir::EmboxOp embox,
|
|
mlir::PatternRewriter &rewriter) const override {
|
|
llvm::FailureOr<RewriteKind> rewriteKind = getRewriteKind(embox);
|
|
if (llvm::failed(rewriteKind))
|
|
return llvm::failure();
|
|
if (embox.getOptional()) {
|
|
mlir::Value newBox = emitOptionalBoxGuard(rewriter, embox, [&] {
|
|
return matchAndRewriteImpl(embox, rewriter, *rewriteKind)->getResult(0);
|
|
});
|
|
rewriter.replaceOp(embox, newBox);
|
|
return mlir::success();
|
|
}
|
|
mlir::Operation *newOp = matchAndRewriteImpl(embox, rewriter, *rewriteKind);
|
|
rewriter.replaceOp(embox, newOp);
|
|
return mlir::success();
|
|
}
|
|
mlir::Operation *matchAndRewriteImpl(fir::EmboxOp embox,
|
|
mlir::PatternRewriter &rewriter,
|
|
RewriteKind rewriteKind) const {
|
|
switch (rewriteKind) {
|
|
case RewriteKind::Dynamic:
|
|
return rewriteDynamicShape(embox, rewriter, embox.getShape());
|
|
case RewriteKind::Static:
|
|
return rewriteStaticShape(embox, rewriter,
|
|
fir::unwrapUntilSeqType(embox.getType()));
|
|
case RewriteKind::DropOptional: {
|
|
auto newEmbox =
|
|
llvm::cast<fir::EmboxOp>(rewriter.clone(*embox.getOperation()));
|
|
newEmbox.setOptional(false);
|
|
return newEmbox.getOperation();
|
|
}
|
|
}
|
|
llvm_unreachable("all cases covered");
|
|
return nullptr;
|
|
}
|
|
|
|
mlir::Operation *rewriteStaticShape(fir::EmboxOp embox,
|
|
mlir::PatternRewriter &rewriter,
|
|
fir::SequenceType seqTy) const {
|
|
auto loc = embox.getLoc();
|
|
llvm::SmallVector<mlir::Value> shapeOpers;
|
|
auto idxTy = rewriter.getIndexType();
|
|
for (auto ext : seqTy.getShape()) {
|
|
auto iAttr = rewriter.getIndexAttr(ext);
|
|
auto extVal =
|
|
mlir::arith::ConstantOp::create(rewriter, loc, idxTy, iAttr);
|
|
shapeOpers.push_back(extVal);
|
|
}
|
|
auto xbox = fir::cg::XEmboxOp::create(
|
|
rewriter, loc, embox.getType(), embox.getMemref(), shapeOpers,
|
|
mlir::ValueRange{}, mlir::ValueRange{}, mlir::ValueRange{},
|
|
mlir::ValueRange{}, embox.getTypeparams(), embox.getSourceBox(),
|
|
embox.getAllocatorIdxAttr());
|
|
LLVM_DEBUG(llvm::dbgs() << "rewriting " << embox << " to " << xbox << '\n');
|
|
return xbox.getOperation();
|
|
}
|
|
|
|
mlir::Operation *rewriteDynamicShape(fir::EmboxOp embox,
|
|
mlir::PatternRewriter &rewriter,
|
|
mlir::Value shapeVal) const {
|
|
auto loc = embox.getLoc();
|
|
llvm::SmallVector<mlir::Value> shapeOpers;
|
|
llvm::SmallVector<mlir::Value> shiftOpers;
|
|
if (auto shapeOp = mlir::dyn_cast<fir::ShapeOp>(shapeVal.getDefiningOp())) {
|
|
populateShape(shapeOpers, shapeOp);
|
|
} else {
|
|
auto shiftOp =
|
|
mlir::dyn_cast<fir::ShapeShiftOp>(shapeVal.getDefiningOp());
|
|
assert(shiftOp && "shape is neither fir.shape nor fir.shape_shift");
|
|
populateShapeAndShift(shapeOpers, shiftOpers, shiftOp);
|
|
}
|
|
llvm::SmallVector<mlir::Value> sliceOpers;
|
|
llvm::SmallVector<mlir::Value> subcompOpers;
|
|
llvm::SmallVector<mlir::Value> substrOpers;
|
|
if (auto s = embox.getSlice())
|
|
if (auto sliceOp =
|
|
mlir::dyn_cast_or_null<fir::SliceOp>(s.getDefiningOp())) {
|
|
sliceOpers.assign(sliceOp.getTriples().begin(),
|
|
sliceOp.getTriples().end());
|
|
subcompOpers.assign(sliceOp.getFields().begin(),
|
|
sliceOp.getFields().end());
|
|
substrOpers.assign(sliceOp.getSubstr().begin(),
|
|
sliceOp.getSubstr().end());
|
|
}
|
|
auto xbox = fir::cg::XEmboxOp::create(
|
|
rewriter, loc, embox.getType(), embox.getMemref(), shapeOpers,
|
|
shiftOpers, sliceOpers, subcompOpers, substrOpers,
|
|
embox.getTypeparams(), embox.getSourceBox(),
|
|
embox.getAllocatorIdxAttr());
|
|
LLVM_DEBUG(llvm::dbgs() << "rewriting " << embox << " to " << xbox << '\n');
|
|
return xbox.getOperation();
|
|
}
|
|
};
|
|
|
|
/// Convert fir.rebox to the extended form where necessary.
|
|
///
|
|
/// For example,
|
|
/// ```
|
|
/// %5 = fir.rebox %3(%1) : (!fir.box<!fir.array<?xi32>>, !fir.shapeshift<1>) ->
|
|
/// !fir.box<!fir.array<?xi32>>
|
|
/// ```
|
|
/// converted to
|
|
/// ```
|
|
/// %5 = fircg.ext_rebox %3(%13) origin %12 : (!fir.box<!fir.array<?xi32>>,
|
|
/// index, index) -> !fir.box<!fir.array<?xi32>>
|
|
/// ```
|
|
class ReboxConversion : public mlir::OpRewritePattern<fir::ReboxOp> {
|
|
public:
|
|
using OpRewritePattern::OpRewritePattern;
|
|
|
|
llvm::LogicalResult
|
|
matchAndRewrite(fir::ReboxOp rebox,
|
|
mlir::PatternRewriter &rewriter) const override {
|
|
if (rebox.getOptional()) {
|
|
mlir::Value newBox = emitOptionalBoxGuard(rewriter, rebox, [&] {
|
|
return matchAndRewriteImpl(rebox, rewriter)->getResult(0);
|
|
});
|
|
rewriter.replaceOp(rebox, newBox);
|
|
return mlir::success();
|
|
}
|
|
mlir::Operation *newOp = matchAndRewriteImpl(rebox, rewriter);
|
|
rewriter.replaceOp(rebox, newOp);
|
|
return mlir::success();
|
|
}
|
|
|
|
mlir::Operation *matchAndRewriteImpl(fir::ReboxOp rebox,
|
|
mlir::PatternRewriter &rewriter) const {
|
|
auto loc = rebox.getLoc();
|
|
llvm::SmallVector<mlir::Value> shapeOpers;
|
|
llvm::SmallVector<mlir::Value> shiftOpers;
|
|
if (auto shapeVal = rebox.getShape()) {
|
|
if (auto shapeOp = mlir::dyn_cast<fir::ShapeOp>(shapeVal.getDefiningOp()))
|
|
populateShape(shapeOpers, shapeOp);
|
|
else if (auto shapeShiftOp =
|
|
mlir::dyn_cast<fir::ShapeShiftOp>(shapeVal.getDefiningOp()))
|
|
populateShapeAndShift(shapeOpers, shiftOpers, shapeShiftOp);
|
|
else {
|
|
auto shiftOp = mlir::dyn_cast<fir::ShiftOp>(shapeVal.getDefiningOp());
|
|
assert(shiftOp && "unexpected shape operand type");
|
|
populateShift(shiftOpers, shiftOp);
|
|
}
|
|
}
|
|
llvm::SmallVector<mlir::Value> sliceOpers;
|
|
llvm::SmallVector<mlir::Value> subcompOpers;
|
|
llvm::SmallVector<mlir::Value> substrOpers;
|
|
if (auto s = rebox.getSlice())
|
|
if (auto sliceOp =
|
|
mlir::dyn_cast_or_null<fir::SliceOp>(s.getDefiningOp())) {
|
|
sliceOpers.append(sliceOp.getTriples().begin(),
|
|
sliceOp.getTriples().end());
|
|
subcompOpers.append(sliceOp.getFields().begin(),
|
|
sliceOp.getFields().end());
|
|
substrOpers.append(sliceOp.getSubstr().begin(),
|
|
sliceOp.getSubstr().end());
|
|
}
|
|
|
|
auto xRebox = fir::cg::XReboxOp::create(
|
|
rewriter, loc, rebox.getType(), rebox.getBox(), shapeOpers, shiftOpers,
|
|
sliceOpers, subcompOpers, substrOpers);
|
|
LLVM_DEBUG(llvm::dbgs()
|
|
<< "rewriting " << rebox << " to " << xRebox << '\n');
|
|
return xRebox.getOperation();
|
|
}
|
|
};
|
|
|
|
/// Convert all fir.array_coor to the extended form.
|
|
///
|
|
/// For example,
|
|
/// ```
|
|
/// %4 = fir.array_coor %addr (%1) [%2] %0 : (!fir.ref<!fir.array<?xi32>>,
|
|
/// !fir.shapeshift<1>, !fir.slice<1>, index) -> !fir.ref<i32>
|
|
/// ```
|
|
/// converted to
|
|
/// ```
|
|
/// %40 = fircg.ext_array_coor %addr(%9) origin %8[%4, %5, %6<%39> :
|
|
/// (!fir.ref<!fir.array<?xi32>>, index, index, index, index, index, index) ->
|
|
/// !fir.ref<i32>
|
|
/// ```
|
|
class ArrayCoorConversion : public mlir::OpRewritePattern<fir::ArrayCoorOp> {
|
|
public:
|
|
using OpRewritePattern::OpRewritePattern;
|
|
|
|
llvm::LogicalResult
|
|
matchAndRewrite(fir::ArrayCoorOp arrCoor,
|
|
mlir::PatternRewriter &rewriter) const override {
|
|
auto loc = arrCoor.getLoc();
|
|
llvm::SmallVector<mlir::Value> shapeOpers;
|
|
llvm::SmallVector<mlir::Value> shiftOpers;
|
|
if (auto shapeVal = arrCoor.getShape()) {
|
|
if (auto shapeOp = mlir::dyn_cast<fir::ShapeOp>(shapeVal.getDefiningOp()))
|
|
populateShape(shapeOpers, shapeOp);
|
|
else if (auto shiftOp =
|
|
mlir::dyn_cast<fir::ShapeShiftOp>(shapeVal.getDefiningOp()))
|
|
populateShapeAndShift(shapeOpers, shiftOpers, shiftOp);
|
|
else if (auto shiftOp =
|
|
mlir::dyn_cast<fir::ShiftOp>(shapeVal.getDefiningOp()))
|
|
populateShift(shiftOpers, shiftOp);
|
|
else
|
|
return mlir::failure();
|
|
}
|
|
llvm::SmallVector<mlir::Value> sliceOpers;
|
|
llvm::SmallVector<mlir::Value> subcompOpers;
|
|
if (auto s = arrCoor.getSlice())
|
|
if (auto sliceOp =
|
|
mlir::dyn_cast_or_null<fir::SliceOp>(s.getDefiningOp())) {
|
|
sliceOpers.append(sliceOp.getTriples().begin(),
|
|
sliceOp.getTriples().end());
|
|
subcompOpers.append(sliceOp.getFields().begin(),
|
|
sliceOp.getFields().end());
|
|
assert(sliceOp.getSubstr().empty() &&
|
|
"Don't allow substring operations on array_coor. This "
|
|
"restriction may be lifted in the future.");
|
|
}
|
|
auto xArrCoor = fir::cg::XArrayCoorOp::create(
|
|
rewriter, loc, arrCoor.getType(), arrCoor.getMemref(), shapeOpers,
|
|
shiftOpers, sliceOpers, subcompOpers, arrCoor.getIndices(),
|
|
arrCoor.getTypeparams());
|
|
LLVM_DEBUG(llvm::dbgs()
|
|
<< "rewriting " << arrCoor << " to " << xArrCoor << '\n');
|
|
rewriter.replaceOp(arrCoor, xArrCoor.getOperation()->getResults());
|
|
return mlir::success();
|
|
}
|
|
};
|
|
|
|
class DeclareOpConversion : public mlir::OpRewritePattern<fir::DeclareOp> {
|
|
bool preserveDeclare;
|
|
|
|
public:
|
|
using OpRewritePattern::OpRewritePattern;
|
|
DeclareOpConversion(mlir::MLIRContext *ctx, bool preserveDecl)
|
|
: OpRewritePattern(ctx), preserveDeclare(preserveDecl) {}
|
|
|
|
llvm::LogicalResult
|
|
matchAndRewrite(fir::DeclareOp declareOp,
|
|
mlir::PatternRewriter &rewriter) const override {
|
|
if (!preserveDeclare) {
|
|
rewriter.replaceOp(declareOp, declareOp.getMemref());
|
|
return mlir::success();
|
|
}
|
|
auto loc = declareOp.getLoc();
|
|
llvm::SmallVector<mlir::Value> shapeOpers;
|
|
llvm::SmallVector<mlir::Value> shiftOpers;
|
|
if (auto shapeVal = declareOp.getShape()) {
|
|
if (auto shapeOp = mlir::dyn_cast<fir::ShapeOp>(shapeVal.getDefiningOp()))
|
|
populateShape(shapeOpers, shapeOp);
|
|
else if (auto shiftOp =
|
|
mlir::dyn_cast<fir::ShapeShiftOp>(shapeVal.getDefiningOp()))
|
|
populateShapeAndShift(shapeOpers, shiftOpers, shiftOp);
|
|
else if (auto shiftOp =
|
|
mlir::dyn_cast<fir::ShiftOp>(shapeVal.getDefiningOp()))
|
|
populateShift(shiftOpers, shiftOp);
|
|
else
|
|
return mlir::failure();
|
|
}
|
|
// Extract dummy_arg_no attribute if present
|
|
mlir::IntegerAttr dummyArgNoAttr;
|
|
if (auto attr = declareOp->getAttrOfType<mlir::IntegerAttr>("dummy_arg_no"))
|
|
dummyArgNoAttr = attr;
|
|
// FIXME: Add FortranAttrs and CudaAttrs
|
|
auto xDeclOp = fir::cg::XDeclareOp::create(
|
|
rewriter, loc, declareOp.getType(), declareOp.getMemref(), shapeOpers,
|
|
shiftOpers, declareOp.getTypeparams(), declareOp.getDummyScope(),
|
|
declareOp.getStorage(), declareOp.getStorageOffset(),
|
|
declareOp.getUniqName(), dummyArgNoAttr);
|
|
LLVM_DEBUG(llvm::dbgs()
|
|
<< "rewriting " << declareOp << " to " << xDeclOp << '\n');
|
|
rewriter.replaceOp(declareOp, xDeclOp.getOperation()->getResults());
|
|
return mlir::success();
|
|
}
|
|
};
|
|
|
|
class DummyScopeOpConversion
|
|
: public mlir::OpRewritePattern<fir::DummyScopeOp> {
|
|
public:
|
|
using OpRewritePattern::OpRewritePattern;
|
|
|
|
llvm::LogicalResult
|
|
matchAndRewrite(fir::DummyScopeOp dummyScopeOp,
|
|
mlir::PatternRewriter &rewriter) const override {
|
|
rewriter.replaceOpWithNewOp<fir::UndefOp>(dummyScopeOp,
|
|
dummyScopeOp.getType());
|
|
return mlir::success();
|
|
}
|
|
};
|
|
|
|
/// Simple DCE to erase fir.shape/shift/slice/unused shape operands after this
|
|
/// pass (fir.shape and like have no codegen).
|
|
/// mlir::RegionDCE is expensive and requires running
|
|
/// mlir::eraseUnreachableBlocks. It does things that are not needed here, like
|
|
/// removing unused block arguments. fir.shape/shift/slice cannot be block
|
|
/// arguments.
|
|
/// This helper does a naive backward walk of the IR. It is not even guaranteed
|
|
/// to walk blocks according to backward dominance, but that is good enough for
|
|
/// what is done here, fir.shape/shift/slice have no usages anymore. The
|
|
/// backward walk allows getting rid of most of the unused operands, it is not a
|
|
/// problem to leave some in the weird cases.
|
|
static void simpleDCE(mlir::RewriterBase &rewriter, mlir::Operation *op) {
|
|
op->walk<mlir::WalkOrder::PostOrder, mlir::ReverseIterator>(
|
|
[&](mlir::Operation *subOp) {
|
|
if (mlir::isOpTriviallyDead(subOp))
|
|
rewriter.eraseOp(subOp);
|
|
});
|
|
}
|
|
|
|
class CodeGenRewrite : public fir::impl::CodeGenRewriteBase<CodeGenRewrite> {
|
|
public:
|
|
using CodeGenRewriteBase<CodeGenRewrite>::CodeGenRewriteBase;
|
|
|
|
void runOnOperation() override final {
|
|
mlir::ModuleOp mod = getOperation();
|
|
|
|
auto &context = getContext();
|
|
mlir::ConversionTarget target(context);
|
|
target.addLegalDialect<mlir::arith::ArithDialect, fir::FIROpsDialect,
|
|
fir::FIRCodeGenDialect, mlir::func::FuncDialect,
|
|
mlir::cf::ControlFlowDialect>();
|
|
target.addIllegalOp<fir::ArrayCoorOp>();
|
|
target.addIllegalOp<fir::ReboxOp>();
|
|
target.addIllegalOp<fir::DeclareOp>();
|
|
target.addIllegalOp<fir::DummyScopeOp>();
|
|
target.addDynamicallyLegalOp<fir::EmboxOp>([](fir::EmboxOp embox) {
|
|
return llvm::failed(EmboxConversion::getRewriteKind(embox));
|
|
});
|
|
mlir::RewritePatternSet patterns(&context);
|
|
fir::populatePreCGRewritePatterns(patterns, preserveDeclare);
|
|
if (mlir::failed(
|
|
mlir::applyPartialConversion(mod, target, std::move(patterns)))) {
|
|
mlir::emitError(mlir::UnknownLoc::get(&context),
|
|
"error in running the pre-codegen conversions");
|
|
signalPassFailure();
|
|
return;
|
|
}
|
|
// Erase any residual (fir.shape, fir.slice...).
|
|
mlir::IRRewriter rewriter(&context);
|
|
simpleDCE(rewriter, mod.getOperation());
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
void fir::populatePreCGRewritePatterns(mlir::RewritePatternSet &patterns,
|
|
bool preserveDeclare) {
|
|
patterns.insert<EmboxConversion, ArrayCoorConversion, ReboxConversion,
|
|
DummyScopeOpConversion>(patterns.getContext());
|
|
patterns.add<DeclareOpConversion>(patterns.getContext(), preserveDeclare);
|
|
}
|