diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5080,6 +5080,10 @@ Flags<[FlangOption, FlangOnlyOption, NoXarchOption, HelpHidden]>, HelpText<"Enable support for generating executables (experimental)">; +def flang_experimental_hlfir : Flag<["-"], "flang-experimental-hlfir">, + Flags<[FlangOption, FC1Option, FlangOnlyOption, NoXarchOption, HelpHidden]>, + HelpText<"Use HLFIR lowering (experimental)">; + //===----------------------------------------------------------------------===// // FLangOption + CoreOption + NoXarchOption //===----------------------------------------------------------------------===// diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -65,6 +65,9 @@ if (stackArrays && !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)) CmdArgs.push_back("-fstack-arrays"); + + if (Args.hasArg(options::OPT_flang_experimental_hlfir)) + CmdArgs.push_back("-flang-experimental-hlfir"); } void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 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 @@ -14,6 +14,7 @@ #include "mlir/Transforms/GreedyPatternRewriteDriver.h" #include "mlir/Transforms/Passes.h" #include "flang/Optimizer/CodeGen/CodeGen.h" +#include "flang/Optimizer/HLFIR/Passes.h" #include "flang/Optimizer/Transforms/Passes.h" #include "llvm/Passes/OptimizationLevel.h" #include "llvm/Support/CommandLine.h" @@ -72,7 +73,8 @@ "rewrite boxed procedures"); #endif -DisableOption(ExternalNameConversion, "external-name-interop", "convert names with external convention"); +DisableOption(ExternalNameConversion, "external-name-interop", + "convert names with external convention"); /// Generic for adding a pass to the pass manager if it is not disabled. template @@ -211,6 +213,20 @@ pm.addPass(mlir::createCSEPass()); } +/// Create a pass pipeline for lowering from HLFIR to FIR +/// +/// \param pm - MLIR pass manager that will hold the pipeline definition +/// \param optLevel - optimization level used for creating FIR optimization +/// passes pipeline +inline void createHLFIRToFIRPassPipeline( + mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel) { + if (optLevel.isOptimizingForSpeed()) + pm.addPass(mlir::createCanonicalizerPass()); + pm.addPass(hlfir::createLowerHLFIRIntrinsicsPass()); + pm.addPass(hlfir::createBufferizeHLFIRPass()); + pm.addPass(hlfir::createConvertHLFIRtoFIRPass()); +} + #if !defined(FLANG_EXCLUDE_CODEGEN) inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel, @@ -218,8 +234,7 @@ fir::addBoxedProcedurePass(pm); pm.addNestedPass( fir::createAbstractResultOnFuncOptPass()); - pm.addNestedPass( - fir::createAbstractResultOnGlobalOptPass()); + pm.addNestedPass(fir::createAbstractResultOnGlobalOptPass()); fir::addCodeGenRewritePass(pm); fir::addTargetRewritePass(pm); fir::addExternalNameConversionPass(pm, underscoring); @@ -234,6 +249,8 @@ inline void createMLIRToLLVMPassPipeline(mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel, bool stackArrays = false, bool underscoring = true) { + fir::createHLFIRToFIRPassPipeline(pm, optLevel); + // Add default optimizer pass pipeline. fir::createDefaultFIROptimizerPassPipeline(pm, optLevel, stackArrays); diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -818,6 +818,11 @@ success = false; } + // -flang-experimental-hlfir + if (args.hasArg(clang::driver::options::OPT_flang_experimental_hlfir)) { + res.loweringOpts.setLowerToHighLevelFIR(true); + } + success &= parseFrontendArgs(res.getFrontendOpts(), args, diags); parseTargetArgs(res.getTargetOpts(), args); parsePreprocessorArgs(res.getPreprocessorOpts(), args); diff --git a/flang/test/Driver/driver-help-hidden.f90 b/flang/test/Driver/driver-help-hidden.f90 --- a/flang/test/Driver/driver-help-hidden.f90 +++ b/flang/test/Driver/driver-help-hidden.f90 @@ -41,6 +41,8 @@ ! CHECK-NEXT: Specify where to find the compiled intrinsic modules ! CHECK-NEXT: -flang-experimental-exec ! CHECK-NEXT: Enable support for generating executables (experimental) +! CHECK-NEXT: -flang-experimental-hlfir +! CHECK-NEXT: Use HLFIR lowering (experimental) ! CHECK-NEXT: -flarge-sizes Use INTEGER(KIND=8) for the result type in size-related intrinsics ! CHECK-NEXT: -flogical-abbreviations Enable logical abbreviations ! CHECK-NEXT: -flto= Set LTO mode 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 @@ -12,6 +12,10 @@ ! ALL: Pass statistics report ! ALL: Fortran::lower::VerifierPass +! O2-NEXT: Canonicalizer +! ALL-NEXT: LowerHLFIRIntrinsics +! ALL-NEXT: BufferizeHLFIR +! ALL-NEXT: ConvertHLFIRtoFIR ! ALL-NEXT: CSE ! Ideally, we need an output with only the pass names, but ! there is currently no way to get that, so in order to 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 @@ -16,7 +16,11 @@ // PASSES: Pass statistics report -// PASSES: CSE +// PASSES: Canonicalizer +// PASSES-NEXT: LowerHLFIRIntrinsics +// PASSES-NEXT: BufferizeHLFIR +// PASSES-NEXT: ConvertHLFIRtoFIR +// PASSES-NEXT: CSE // PASSES-NEXT: (S) 0 num-cse'd - Number of operations CSE'd // PASSES-NEXT: (S) 0 num-dce'd - Number of operations DCE'd diff --git a/flang/test/HLFIR/flang-experimental-hlfir-flag.f90 b/flang/test/HLFIR/flang-experimental-hlfir-flag.f90 new file mode 100644 --- /dev/null +++ b/flang/test/HLFIR/flang-experimental-hlfir-flag.f90 @@ -0,0 +1,19 @@ +! Test -flang-experimental-hlfir flag +! RUN: %flang_fc1 -flang-experimental-hlfir -emit-fir -o - %s | FileCheck %s +! RUN: %flang_fc1 -emit-fir -o - %s | FileCheck %s --check-prefix NO-HLFIR + +subroutine test(a, res) + real :: a(:), res + res = SUM(a) +end subroutine +! CHECK-LABEL: func.func @_QPtest +! CHECK: %[[A:.*]]: !fir.box> +! CHECK: %[[RES:.*]]: !fir.ref +! CHECK-DAG: %[[A_VAR:.*]]:2 = hlfir.declare %[[A]] +! CHECK-DAG: %[[RES_VAR:.*]]:2 = hlfir.declare %[[RES]] +! CHECK-NEXT: %[[SUM_RES:.*]] = hlfir.sum %[[A_VAR]]#0 +! CHECK-NEXT: hlfir.assign %[[SUM_RES]] to %[[RES_VAR]]#0 +! CHECK-NEXT: hlfir.destroy %[[SUM_RES]] +! CHECK-NEXT: return +! CHECK-NEXT: } +! NO-HLFIR-NOT: hlfir.