diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -9,8 +9,11 @@ #ifndef FORTRAN_OPTIMIZER_TRANSFORMS_PASSES_H #define FORTRAN_OPTIMIZER_TRANSFORMS_PASSES_H +#include "flang/Optimizer/Dialect/FIROps.h" + #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassRegistry.h" + #include namespace mlir { @@ -27,6 +30,7 @@ //===----------------------------------------------------------------------===// std::unique_ptr createAbstractResultOnFuncOptPass(); +std::unique_ptr createAbstractResultOnGlobalOptPass(); std::unique_ptr createAffineDemotionPass(); std::unique_ptr createArrayValueCopyPass(); std::unique_ptr createFirToCfgPass(); diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -39,6 +39,10 @@ let constructor = "::fir::createAbstractResultOnFuncOptPass()"; } +def AbstractResultOnGlobalOpt : AbstractResultOptBase<"global", "fir::GlobalOp"> { + let constructor = "::fir::createAbstractResultOnGlobalOptPass()"; +} + def AffineDialectPromotion : Pass<"promote-to-affine", "::mlir::func::FuncOp"> { let summary = "Promotes `fir.{do_loop,if}` to `affine.{for,if}`."; let description = [{ diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -192,6 +192,8 @@ fir::addBoxedProcedurePass(pm); pm.addNestedPass( fir::createAbstractResultOnFuncOptPass()); + pm.addNestedPass( + fir::createAbstractResultOnGlobalOptPass()); fir::addCodeGenRewritePass(pm); fir::addTargetRewritePass(pm); fir::addExternalNameConversionPass(pm); diff --git a/flang/lib/Optimizer/Transforms/AbstractResult.cpp b/flang/lib/Optimizer/Transforms/AbstractResult.cpp --- a/flang/lib/Optimizer/Transforms/AbstractResult.cpp +++ b/flang/lib/Optimizer/Transforms/AbstractResult.cpp @@ -277,9 +277,23 @@ } } }; + +class AbstractResultOnGlobalOpt + : public AbstractResultOptTemplate { +public: + void runOnSpecificOperation(fir::GlobalOp, bool, mlir::RewritePatternSet &, + mlir::ConversionTarget &) { + // nothing to do + } +}; } // end anonymous namespace } // namespace fir std::unique_ptr fir::createAbstractResultOnFuncOptPass() { return std::make_unique(); } + +std::unique_ptr fir::createAbstractResultOnGlobalOptPass() { + return std::make_unique(); +} diff --git a/flang/lib/Optimizer/Transforms/PassDetail.h b/flang/lib/Optimizer/Transforms/PassDetail.h --- a/flang/lib/Optimizer/Transforms/PassDetail.h +++ b/flang/lib/Optimizer/Transforms/PassDetail.h @@ -9,6 +9,8 @@ #define FORTRAN_OPTMIZER_TRANSFORMS_PASSDETAIL_H #include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Dialect/FIROps.h" + #include "mlir/Dialect/Affine/IR/AffineOps.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" diff --git a/flang/test/Driver/mlir-pass-pipeline.f90 b/flang/test/Driver/mlir-pass-pipeline.f90 --- a/flang/test/Driver/mlir-pass-pipeline.f90 +++ b/flang/test/Driver/mlir-pass-pipeline.f90 @@ -50,8 +50,11 @@ ! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd ! ALL-NEXT: BoxedProcedurePass -! ALL-NEXT: 'func.func' Pipeline -! ALL-NEXT: AbstractResultOnFuncOpt +! ALL-NEXT: Pipeline Collection : ['fir.global', 'func.func'] +! ALL-NEXT: 'fir.global' Pipeline +! ALL-NEXT: AbstractResultOnGlobalOpt +! ALL-NEXT: 'func.func' Pipeline +! ALL-NEXT: AbstractResultOnFuncOpt ! ALL-NEXT: CodeGenRewrite ! ALL-NEXT: (S) 0 num-dce'd - Number of operations eliminated diff --git a/flang/test/Fir/abstract-results.fir b/flang/test/Fir/abstract-results.fir --- a/flang/test/Fir/abstract-results.fir +++ b/flang/test/Fir/abstract-results.fir @@ -3,6 +3,8 @@ // RUN: fir-opt %s --abstract-result-on-func-opt | FileCheck %s --check-prefix=FUNC-REF // RUN: fir-opt %s --abstract-result-on-func-opt=abstract-result-as-box | FileCheck %s --check-prefix=FUNC-BOX +// RUN: fir-opt %s --abstract-result-on-global-opt | FileCheck %s --check-prefix=GLOBAL-REF +// RUN: fir-opt %s --abstract-result-on-global-opt=abstract-result-as-box | FileCheck %s --check-prefix=GLOBAL-BOX // ----------------------- Test declaration rewrite ---------------------------- @@ -253,3 +255,122 @@ // FUNC-BOX: fir.call %[[conv]](%[[box]], %c100) : (!fir.box>, index) -> () // FUNC-BOX-NOT: fir.save_result } + +// ----------------------- Test GlobalOp rewrite ------------------------ + +// This is needed to separate GlobalOp tests from FuncOp tests for FileCheck +// FUNC-REF-LABEL: fir.global {{.*}} : {{.*}} { +// FUNC-BOX-LABEL: fir.global {{.*}} : {{.*}} { + +// GLOBAL-REF-LABEL: fir.global @global_call_arrayfunc : i32 { +// GLOBAL-BOX-LABEL: fir.global @global_call_arrayfunc : i32 { +fir.global @global_call_arrayfunc : i32 { + %c100 = arith.constant 100 : index + %buffer = fir.alloca !fir.array, %c100 + %shape = fir.shape %c100 : (index) -> !fir.shape<1> + %res = fir.call @arrayfunc_callee(%c100) : (index) -> !fir.array + fir.save_result %res to %buffer(%shape) : !fir.array, !fir.ref>, !fir.shape<1> + + // GLOBAL-REF: %[[c100:.*]] = arith.constant 100 : index + // GLOBAL-REF: %[[buffer:.*]] = fir.alloca !fir.array, %[[c100]] + // GLOBAL-REF: fir.call @arrayfunc_callee(%[[buffer]], %[[c100]]) : (!fir.ref>, index) -> () + // GLOBAL-REF-NOT: fir.save_result + + // GLOBAL-BOX: %[[c100:.*]] = arith.constant 100 : index + // GLOBAL-BOX: %[[buffer:.*]] = fir.alloca !fir.array, %[[c100]] + // GLOBAL-BOX: %[[shape:.*]] = fir.shape %[[c100]] : (index) -> !fir.shape<1> + // GLOBAL-BOX: %[[box:.*]] = fir.embox %[[buffer]](%[[shape]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> + // GLOBAL-BOX: fir.call @arrayfunc_callee(%[[box]], %[[c100]]) : (!fir.box>, index) -> () + // GLOBAL-BOX-NOT: fir.save_result + + %c42 = arith.constant 42 : i32 + fir.has_value %c42 : i32 +} + +// GLOBAL-REF-LABEL: fir.global @global_call_derivedfunc : i32 { +// GLOBAL-BOX-LABEL: fir.global @global_call_derivedfunc : i32 { +fir.global @global_call_derivedfunc : i32 { + %buffer = fir.alloca !fir.type + %cst = arith.constant 4.200000e+01 : f32 + %res = fir.call @derivedfunc_callee(%cst) : (f32) -> !fir.type + fir.save_result %res to %buffer : !fir.type, !fir.ref> + + // GLOBAL-REF: %[[buffer:.*]] = fir.alloca !fir.type + // GLOBAL-REF: %[[cst:.*]] = arith.constant {{.*}} : f32 + // GLOBAL-REF: fir.call @derivedfunc_callee(%[[buffer]], %[[cst]]) : (!fir.ref>, f32) -> () + // GLOBAL-REF-NOT: fir.save_result + + // GLOBAL-BOX: %[[buffer:.*]] = fir.alloca !fir.type + // GLOBAL-BOX: %[[cst:.*]] = arith.constant {{.*}} : f32 + // GLOBAL-BOX: %[[box:.*]] = fir.embox %[[buffer]] : (!fir.ref>) -> !fir.box> + // GLOBAL-BOX: fir.call @derivedfunc_callee(%[[box]], %[[cst]]) : (!fir.box>, f32) -> () + // GLOBAL-BOX-NOT: fir.save_result + + %c42 = arith.constant 42 : i32 + fir.has_value %c42 : i32 +} + +// GLOBAL-REF-LABEL: fir.global @global_call_boxfunc : i32 { +// GLOBAL-BOX-LABEL: fir.global @global_call_boxfunc : i32 { +fir.global @global_call_boxfunc : i32 { + %buffer = fir.alloca !fir.box> + %res = fir.call @boxfunc_callee() : () -> !fir.box> + fir.save_result %res to %buffer: !fir.box>, !fir.ref>> + + // GLOBAL-REF: %[[buffer:.*]] = fir.alloca !fir.box> + // GLOBAL-REF: fir.call @boxfunc_callee(%[[buffer]]) : (!fir.ref>>) -> () + // GLOBAL-REF-NOT: fir.save_result + + // GLOBAL-BOX: %[[buffer:.*]] = fir.alloca !fir.box> + // GLOBAL-BOX: fir.call @boxfunc_callee(%[[buffer]]) : (!fir.ref>>) -> () + // GLOBAL-BOX-NOT: fir.save_result + + %c42 = arith.constant 42 : i32 + fir.has_value %c42 : i32 +} + +// GLOBAL-REF-LABEL: fir.global @global_call_chararrayfunc : i32 { +// GLOBAL-BOX-LABEL: fir.global @global_call_chararrayfunc : i32 { +fir.global @global_call_chararrayfunc : i32 { + %c100 = arith.constant 100 : index + %c50 = arith.constant 50 : index + %buffer = fir.alloca !fir.array>(%c100 : index), %c50 + %shape = fir.shape %c100 : (index) -> !fir.shape<1> + %res = fir.call @chararrayfunc(%c100, %c50) : (index, index) -> !fir.array> + fir.save_result %res to %buffer(%shape) typeparams %c50 : !fir.array>, !fir.ref>>, !fir.shape<1>, index + + // GLOBAL-REF: %[[c100:.*]] = arith.constant 100 : index + // GLOBAL-REF: %[[c50:.*]] = arith.constant 50 : index + // GLOBAL-REF: %[[buffer:.*]] = fir.alloca !fir.array>(%[[c100]] : index), %[[c50]] + // GLOBAL-REF: fir.call @chararrayfunc(%[[buffer]], %[[c100]], %[[c50]]) : (!fir.ref>>, index, index) -> () + // GLOBAL-REF-NOT: fir.save_result + + // GLOBAL-BOX: %[[c100:.*]] = arith.constant 100 : index + // GLOBAL-BOX: %[[c50:.*]] = arith.constant 50 : index + // GLOBAL-BOX: %[[buffer:.*]] = fir.alloca !fir.array>(%[[c100]] : index), %[[c50]] + // GLOBAL-BOX: %[[shape:.*]] = fir.shape %[[c100]] : (index) -> !fir.shape<1> + // GLOBAL-BOX: %[[box:.*]] = fir.embox %[[buffer]](%[[shape]]) typeparams %[[c50]] : (!fir.ref>>, !fir.shape<1>, index) -> !fir.box>> + // GLOBAL-BOX: fir.call @chararrayfunc(%[[box]], %[[c100]], %[[c50]]) : (!fir.box>>, index, index) -> () + // GLOBAL-BOX-NOT: fir.save_result + + %c42 = arith.constant 42 : i32 + fir.has_value %c42 : i32 +} + +// GLOBAL-REF-LABEL: fir.global @global_test_address_of : i32 { +// GLOBAL-BOX-LABEL: fir.global @global_test_address_of : i32 { +fir.global @global_test_address_of : i32 { + %0 = fir.address_of(@arrayfunc) : (i32) -> !fir.array + fir.call @takesfuncarray(%0) : ((i32) -> !fir.array) -> () + + // GLOBAL-REF: %[[addrOf:.*]] = fir.address_of(@arrayfunc) : (!fir.ref>, i32) -> () + // GLOBAL-REF: %[[conv:.*]] = fir.convert %[[addrOf]] : ((!fir.ref>, i32) -> ()) -> ((i32) -> !fir.array) + // GLOBAL-REF: fir.call @takesfuncarray(%[[conv]]) : ((i32) -> !fir.array) -> () + + // GLOBAL-BOX: %[[addrOf:.*]] = fir.address_of(@arrayfunc) : (!fir.box>, i32) -> () + // GLOBAL-BOX: %[[conv:.*]] = fir.convert %[[addrOf]] : ((!fir.box>, i32) -> ()) -> ((i32) -> !fir.array) + // GLOBAL-BOX: fir.call @takesfuncarray(%[[conv]]) : ((i32) -> !fir.array) -> () + + %c42 = arith.constant 42 : i32 + fir.has_value %c42 : i32 +} diff --git a/flang/test/Fir/basic-program.fir b/flang/test/Fir/basic-program.fir --- a/flang/test/Fir/basic-program.fir +++ b/flang/test/Fir/basic-program.fir @@ -50,8 +50,11 @@ // PASSES-NEXT: (S) 0 num-dce'd - Number of operations DCE'd // PASSES-NEXT: BoxedProcedurePass -// PASSES-NEXT: 'func.func' Pipeline -// PASSES-NEXT: AbstractResultOnFuncOpt +// PASSES-NEXT: Pipeline Collection : ['fir.global', 'func.func'] +// PASSES-NEXT: 'fir.global' Pipeline +// PASSES-NEXT: AbstractResultOnGlobalOpt +// PASSES-NEXT: 'func.func' Pipeline +// PASSES-NEXT: AbstractResultOnFuncOpt // PASSES-NEXT: CodeGenRewrite // PASSES-NEXT: (S) 0 num-dce'd - Number of operations eliminated