diff --git a/flang/include/flang/Optimizer/HLFIR/Passes.h b/flang/include/flang/Optimizer/HLFIR/Passes.h index a82caeb61e3c3..a5aa35b92ae59 100644 --- a/flang/include/flang/Optimizer/HLFIR/Passes.h +++ b/flang/include/flang/Optimizer/HLFIR/Passes.h @@ -26,6 +26,7 @@ std::unique_ptr createConvertHLFIRtoFIRPass(); std::unique_ptr createBufferizeHLFIRPass(); std::unique_ptr createLowerHLFIRIntrinsicsPass(); std::unique_ptr createSimplifyHLFIRIntrinsicsPass(); +std::unique_ptr createLowerHLFIROrderedAssignmentsPass(); #define GEN_PASS_REGISTRATION #include "flang/Optimizer/HLFIR/Passes.h.inc" diff --git a/flang/include/flang/Optimizer/HLFIR/Passes.td b/flang/include/flang/Optimizer/HLFIR/Passes.td index a249a59ff442d..e2cf8447dff47 100644 --- a/flang/include/flang/Optimizer/HLFIR/Passes.td +++ b/flang/include/flang/Optimizer/HLFIR/Passes.td @@ -25,6 +25,11 @@ def LowerHLFIRIntrinsics : Pass<"lower-hlfir-intrinsics", "::mlir::ModuleOp"> { let constructor = "hlfir::createLowerHLFIRIntrinsicsPass()"; } +def LowerHLFIROrderedAssignments : Pass<"lower-hlfir-ordered-assignments", "::mlir::ModuleOp"> { + let summary = "Lower HLFIR ordered assignments like forall and where operations"; + let constructor = "hlfir::createLowerHLFIROrderedAssignmentsPass()"; +} + def SimplifyHLFIRIntrinsics : Pass<"simplify-hlfir-intrinsics", "::mlir::func::FuncOp"> { let summary = "Simplify HLFIR intrinsic operations that don't need to result in runtime calls"; let constructor = "hlfir::createSimplifyHLFIRIntrinsicsPass()"; diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc index 93285bb4c258d..a799427f023e4 100644 --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -242,6 +242,7 @@ inline void createHLFIRToFIRPassPipeline( addCanonicalizerPassWithoutRegionSimplification(pm); pm.addPass(hlfir::createSimplifyHLFIRIntrinsicsPass()); } + pm.addPass(hlfir::createLowerHLFIROrderedAssignmentsPass()); pm.addPass(hlfir::createLowerHLFIRIntrinsicsPass()); pm.addPass(hlfir::createBufferizeHLFIRPass()); pm.addPass(hlfir::createConvertHLFIRtoFIRPass()); diff --git a/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt b/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt index 03b135c345ef5..df2e2bd68f4ed 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt @@ -4,6 +4,7 @@ add_flang_library(HLFIRTransforms BufferizeHLFIR.cpp ConvertToFIR.cpp LowerHLFIRIntrinsics.cpp + LowerHLFIROrderedAssignments.cpp SimplifyHLFIRIntrinsics.cpp DEPENDS diff --git a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp new file mode 100644 index 0000000000000..85e32ffa0ec2d --- /dev/null +++ b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp @@ -0,0 +1,106 @@ +//===- LowerHLFIROrderedAssignments.cpp - Lower HLFIR ordered assignments -===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// This file defines a pass to lower HLFIR ordered assignments. +// Ordered assignments are all the operations with the +// OrderedAssignmentTreeOpInterface that implements user defined assignments, +// assignment to vector subscripted entities, and assignments inside forall and +// where. +// The pass lowers these operations to regular hlfir.assign, loops and, if +// needed, introduces temporary storage to fulfill Fortran semantics. +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" +#include "flang/Optimizer/HLFIR/Passes.h" +#include "mlir/Transforms/DialectConversion.h" + +namespace hlfir { +#define GEN_PASS_DEF_LOWERHLFIRORDEREDASSIGNMENTS +#include "flang/Optimizer/HLFIR/Passes.h.inc" +} // namespace hlfir + +using namespace mlir; + +namespace { + +class ForallOpConversion : public mlir::OpRewritePattern { +public: + explicit ForallOpConversion(mlir::MLIRContext *ctx) : OpRewritePattern{ctx} {} + + mlir::LogicalResult + matchAndRewrite(hlfir::ForallOp forallOp, + mlir::PatternRewriter &rewriter) const override { + TODO(forallOp.getLoc(), "FORALL construct or statement in HLFIR"); + return mlir::failure(); + } +}; + +class WhereOpConversion : public mlir::OpRewritePattern { +public: + explicit WhereOpConversion(mlir::MLIRContext *ctx) : OpRewritePattern{ctx} {} + + mlir::LogicalResult + matchAndRewrite(hlfir::WhereOp whereOp, + mlir::PatternRewriter &rewriter) const override { + TODO(whereOp.getLoc(), "WHERE construct or statement in HLFIR"); + return mlir::failure(); + } +}; + +class RegionAssignConversion + : public mlir::OpRewritePattern { +public: + explicit RegionAssignConversion(mlir::MLIRContext *ctx) + : OpRewritePattern{ctx} {} + + mlir::LogicalResult + matchAndRewrite(hlfir::RegionAssignOp regionAssignOp, + mlir::PatternRewriter &rewriter) const override { + if (!regionAssignOp.getUserDefinedAssignment().empty()) + TODO(regionAssignOp.getLoc(), "user defined assignment in HLFIR"); + else + TODO(regionAssignOp.getLoc(), + "assignments to vector subscripted entity in HLFIR"); + return mlir::failure(); + } +}; + +class LowerHLFIROrderedAssignments + : public hlfir::impl::LowerHLFIROrderedAssignmentsBase< + LowerHLFIROrderedAssignments> { +public: + void runOnOperation() override { + // Running on a ModuleOp because this pass may generate FuncOp declaration + // for runtime calls. This could be a FuncOp pass otherwise. + auto module = this->getOperation(); + auto *context = &getContext(); + mlir::RewritePatternSet patterns(context); + // Patterns are only defined for the OrderedAssignmentTreeOpInterface + // operations that can be the root of ordered assignments. The other + // operations will be taken care of while rewriting these trees (they + // cannot exist outside of these operations given their verifiers/traits). + patterns + .insert( + context); + mlir::ConversionTarget target(*context); + target.markUnknownOpDynamicallyLegal([](mlir::Operation *op) { + return !mlir::isa(op); + }); + if (mlir::failed(mlir::applyPartialConversion(module, target, + std::move(patterns)))) { + mlir::emitError(mlir::UnknownLoc::get(context), + "failure in HLFIR ordered assignments lowering pass"); + signalPassFailure(); + } + } +}; +} // namespace + +std::unique_ptr hlfir::createLowerHLFIROrderedAssignmentsPass() { + return std::make_unique(); +} diff --git a/flang/test/Driver/mlir-debug-pass-pipeline.f90 b/flang/test/Driver/mlir-debug-pass-pipeline.f90 index d397b29bb56b2..320f06a854b34 100644 --- a/flang/test/Driver/mlir-debug-pass-pipeline.f90 +++ b/flang/test/Driver/mlir-debug-pass-pipeline.f90 @@ -25,6 +25,7 @@ ! ALL: Pass statistics report ! ALL: Fortran::lower::VerifierPass +! ALL-NEXT: LowerHLFIROrderedAssignments ! ALL-NEXT: LowerHLFIRIntrinsics ! ALL-NEXT: BufferizeHLFIR ! ALL-NEXT: ConvertHLFIRtoFIR diff --git a/flang/test/Driver/mlir-pass-pipeline.f90 b/flang/test/Driver/mlir-pass-pipeline.f90 index 9b0fa1ad5107e..44d253a467bb4 100644 --- a/flang/test/Driver/mlir-pass-pipeline.f90 +++ b/flang/test/Driver/mlir-pass-pipeline.f90 @@ -15,6 +15,7 @@ ! O2-NEXT: Canonicalizer ! O2-NEXT: 'func.func' Pipeline ! O2-NEXT: SimplifyHLFIRIntrinsics +! ALL-NEXT: LowerHLFIROrderedAssignments ! ALL-NEXT: LowerHLFIRIntrinsics ! ALL-NEXT: BufferizeHLFIR ! ALL-NEXT: ConvertHLFIRtoFIR diff --git a/flang/test/Fir/basic-program.fir b/flang/test/Fir/basic-program.fir index a4f79e347b089..e6d849c2f4659 100644 --- a/flang/test/Fir/basic-program.fir +++ b/flang/test/Fir/basic-program.fir @@ -19,6 +19,7 @@ func.func @_QQmain() { // PASSES: Canonicalizer // PASSES-NEXT: 'func.func' Pipeline // PASSES-NEXT: SimplifyHLFIRIntrinsics +// PASSES-NEXT: LowerHLFIROrderedAssignments // PASSES-NEXT: LowerHLFIRIntrinsics // PASSES-NEXT: BufferizeHLFIR // PASSES-NEXT: ConvertHLFIRtoFIR diff --git a/flang/test/HLFIR/ordered-assignments-codegen-todo.fir b/flang/test/HLFIR/ordered-assignments-codegen-todo.fir new file mode 100644 index 0000000000000..ccbd97ce5caba --- /dev/null +++ b/flang/test/HLFIR/ordered-assignments-codegen-todo.fir @@ -0,0 +1,24 @@ +// Just test that Ordered assignment pass TODOs are properly reported. +// RUN: %not_todo_cmd fir-opt --lower-hlfir-ordered-assignments %s 2>&1 | FileCheck %s + + +// CHECK: not yet implemented: FORALL construct or statement in HLFIR + +func.func @forall_todo(%arg0: !fir.ref>, %arg1: !fir.ref>) { + %c1 = arith.constant 1 : index + %c10 = arith.constant 10 : index + hlfir.forall lb { + hlfir.yield %c1 : index + } ub { + hlfir.yield %c10 : index + } (%arg2: i64) { + hlfir.region_assign { + %1 = hlfir.designate %arg1 (%arg2) : (!fir.ref>, i64) -> !fir.ref + hlfir.yield %1 : !fir.ref + } to { + %1 = hlfir.designate %arg0 (%arg2) : (!fir.ref>, i64) -> !fir.ref + hlfir.yield %1 : !fir.ref + } + } + return +}