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 @@ -30,6 +30,9 @@ std::unique_ptr createAffineDemotionPass(); std::unique_ptr createArrayValueCopyPass(); std::unique_ptr createFirToCfgPass(); +std::unique_ptr createFirToCfgPass(bool transformDoLoop, + bool transformIf, + bool transformIterateWhile); std::unique_ptr createCharacterConversionPass(); std::unique_ptr createExternalNameConversionPass(); std::unique_ptr createMemDataFlowOptPass(); 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 @@ -127,7 +127,16 @@ let options = [ Option<"forceLoopToExecuteOnce", "always-execute-loop-body", "bool", /*default=*/"false", - "force the body of a loop to execute at least once"> + "force the body of a loop to execute at least once">, + Option<"transformDoLoop", "transform-do-loop", "bool", + /*default=*/"true", + "apply the transformation the do loops">, + Option<"transformIf", "transform-if", "bool", + /*default=*/"true", + "apply transformation on if statments">, + Option<"transformIterateWhile", "transform-iterate-while", "bool", + /*default=*/"true", + "apply transformation on iterate while"> ]; } 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 @@ -79,7 +79,7 @@ inline void addCfgConversionPass(mlir::PassManager &pm) { addNestedPassConditionally( - pm, disableCfgConversion, fir::createFirToCfgPass); + pm, disableCfgConversion, []() {return fir::createFirToCfgPass();}); } inline void addAVC(mlir::PassManager &pm) { diff --git a/flang/lib/Optimizer/Transforms/RewriteLoop.cpp b/flang/lib/Optimizer/Transforms/RewriteLoop.cpp --- a/flang/lib/Optimizer/Transforms/RewriteLoop.cpp +++ b/flang/lib/Optimizer/Transforms/RewriteLoop.cpp @@ -294,17 +294,38 @@ /// Convert FIR structured control flow ops to CFG ops. class CfgConversion : public CFGConversionBase { public: + CfgConversion() = default; + CfgConversion(bool transformDoLoop, bool transformIf, + bool transformIterateWhile) { + this->transformDoLoop = transformDoLoop; + this->transformIf = transformIf; + this->transformIterateWhile = transformIterateWhile; + } + void runOnOperation() override { auto *context = &getContext(); mlir::RewritePatternSet patterns(context); - patterns.insert( - context, forceLoopToExecuteOnce); mlir::ConversionTarget target(*context); target.addLegalDialect(); // apply the patterns - target.addIllegalOp(); + if (transformIterateWhile) { + patterns.insert(context, forceLoopToExecuteOnce); + target.addIllegalOp(); + } + if (transformDoLoop) { + patterns.insert(context, forceLoopToExecuteOnce); + target.addIllegalOp(); + } + if (transformIf) { + patterns.insert(context, forceLoopToExecuteOnce); + target.addIllegalOp(); + } + bool transformAll = transformIterateWhile && transformDoLoop && transformIf; + if (transformAll) { + target.addIllegalOp(); + } target.markUnknownOpDynamicallyLegal([](Operation *) { return true; }); if (mlir::failed(mlir::applyPartialConversion(getOperation(), target, std::move(patterns)))) { @@ -319,6 +340,13 @@ /// Convert FIR's structured control flow ops to CFG ops. This /// conversion enables the `createLowerToCFGPass` to transform these to CFG /// form. +std::unique_ptr +fir::createFirToCfgPass(bool transformDoLoop, bool transformIf, + bool transformIterateWhile) { + return std::make_unique(transformDoLoop, transformIf, + transformIterateWhile); +} +/// Overload utilizing pass options for initialization. std::unique_ptr fir::createFirToCfgPass() { return std::make_unique(); } diff --git a/flang/test/Fir/cfg-options1.fir b/flang/test/Fir/cfg-options1.fir new file mode 100644 --- /dev/null +++ b/flang/test/Fir/cfg-options1.fir @@ -0,0 +1,27 @@ +// RUN: fir-opt %s --cfg-conversion | FileCheck %s + +// CHECK-LABEL: @x +// CHECK-NOT: fir.if +// CHECK-NOT: fir.do_loop +func @x(%lb : index, %ub : index, %step : index, %b : i1, %addr : !fir.ref) { + fir.do_loop %iv = %lb to %ub step %step unordered { + fir.if %b { + fir.store %iv to %addr : !fir.ref + } else { + %zero = arith.constant 0 : index + fir.store %zero to %addr : !fir.ref + } + } + return +} + +// CHECK-LABEL: @x2 +// CHECK-NOT: fir.iterate_while +func @x2(%lo : index, %up : index, %ok : i1) { + %c1 = arith.constant 1 : index + %unused = fir.iterate_while (%i = %lo to %up step %c1) and (%ok1 = %ok) { + %ok2 = fir.call @f2() : () -> i1 + fir.result %ok2 : i1 + } + return +} diff --git a/flang/test/Fir/cfg-options2.fir b/flang/test/Fir/cfg-options2.fir new file mode 100644 --- /dev/null +++ b/flang/test/Fir/cfg-options2.fir @@ -0,0 +1,27 @@ +// RUN: fir-opt %s --cfg-conversion="transform-if=0 transform-iterate-while=0" | FileCheck %s + +// CHECK-LABEL: @x +// CHECK: fir.if +// CHECK-NOT: fir.do_loop +func @x(%lb : index, %ub : index, %step : index, %b : i1, %addr : !fir.ref) { + fir.do_loop %iv = %lb to %ub step %step unordered { + fir.if %b { + fir.store %iv to %addr : !fir.ref + } else { + %zero = arith.constant 0 : index + fir.store %zero to %addr : !fir.ref + } + } + return +} + +// CHECK-LABEL: @x2 +// CHECK: fir.iterate_while +func @x2(%lo : index, %up : index, %ok : i1) { + %c1 = arith.constant 1 : index + %unused = fir.iterate_while (%i = %lo to %up step %c1) and (%ok1 = %ok) { + %ok2 = fir.call @f2() : () -> i1 + fir.result %ok2 : i1 + } + return +} diff --git a/flang/test/Fir/cfg-options3.fir b/flang/test/Fir/cfg-options3.fir new file mode 100644 --- /dev/null +++ b/flang/test/Fir/cfg-options3.fir @@ -0,0 +1,28 @@ +// RUN: fir-opt %s --cfg-conversion="transform-iterate-while=0" | FileCheck %s + + +// CHECK-LABEL: @x +// CHECK-NOT: fir.if +// CHECK-NOT: fir.do_loop +func @x(%lb : index, %ub : index, %step : index, %b : i1, %addr : !fir.ref) { + fir.do_loop %iv = %lb to %ub step %step unordered { + fir.if %b { + fir.store %iv to %addr : !fir.ref + } else { + %zero = arith.constant 0 : index + fir.store %zero to %addr : !fir.ref + } + } + return +} + +// CHECK-LABEL: @x2 +// CHECK: fir.iterate_while +func @x2(%lo : index, %up : index, %ok : i1) { + %c1 = arith.constant 1 : index + %unused = fir.iterate_while (%i = %lo to %up step %c1) and (%ok1 = %ok) { + %ok2 = fir.call @f2() : () -> i1 + fir.result %ok2 : i1 + } + return +} diff --git a/flang/test/Fir/cfg-options4.fir b/flang/test/Fir/cfg-options4.fir new file mode 100644 --- /dev/null +++ b/flang/test/Fir/cfg-options4.fir @@ -0,0 +1,27 @@ +// RUN: fir-opt %s --cfg-conversion="transform-do-loop=0 transform-if=0" | FileCheck %s + +// CHECK-LABEL: @x +// CHECK: fir.do_loop +// CHECK: fir.if +func @x(%lb : index, %ub : index, %step : index, %b : i1, %addr : !fir.ref) { + fir.do_loop %iv = %lb to %ub step %step unordered { + fir.if %b { + fir.store %iv to %addr : !fir.ref + } else { + %zero = arith.constant 0 : index + fir.store %zero to %addr : !fir.ref + } + } + return +} + +// CHECK-LABEL: @x2 +// CHECK-NOT: fir.iterate_while +func @x2(%lo : index, %up : index, %ok : i1) { + %c1 = arith.constant 1 : index + %unused = fir.iterate_while (%i = %lo to %up step %c1) and (%ok1 = %ok) { + %ok2 = fir.call @f2() : () -> i1 + fir.result %ok2 : i1 + } + return +} diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py deleted file mode 100644 --- a/flang/test/lit.cfg.py +++ /dev/null @@ -1,116 +0,0 @@ -# -*- Python -*- - -import os -import platform -import re -import subprocess -import sys - -import lit.formats -import lit.util - -from lit.llvm import llvm_config -from lit.llvm.subst import ToolSubst -from lit.llvm.subst import FindTool - -# Configuration file for the 'lit' test runner. - -# name: The name of this test suite. -config.name = 'Flang' - -# testFormat: The test format to use to interpret tests. -# -# For now we require '&&' between commands, until they get globally killed and -# the test runner updated. -config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) - -# suffixes: A list of file extensions to treat as test files. -config.suffixes = ['.c', '.cpp', '.f', '.F', '.ff', '.FOR', '.for', '.f77', '.f90', '.F90', - '.ff90', '.f95', '.F95', '.ff95', '.fpp', '.FPP', '.cuf' - '.CUF', '.f18', '.F18', '.fir', '.f03', '.F03', '.f08', '.F08'] - -config.substitutions.append(('%PATH%', config.environment['PATH'])) -config.substitutions.append(('%llvmshlibdir', config.llvm_shlib_dir)) -config.substitutions.append(('%pluginext', config.llvm_plugin_ext)) - -llvm_config.use_default_substitutions() - -# ask llvm-config about asserts -llvm_config.feature_config( - [('--assertion-mode', {'ON': 'asserts'})]) - -# excludes: A list of directories to exclude from the testsuite. The 'Inputs' -# subdirectories contain auxiliary inputs for various tests in their parent -# directories. -config.excludes = ['Inputs', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt'] - -# If the flang examples are built, add examples to the config -if config.flang_examples: - config.available_features.add('examples') - -# Plugins (loadable modules) -if config.has_plugins: - config.available_features.add('plugins') - -# test_source_root: The root path where tests are located. -config.test_source_root = os.path.dirname(__file__) - -# test_exec_root: The root path where tests should be run. -config.test_exec_root = os.path.join(config.flang_obj_root, 'test') - -# Tweak the PATH to include the tools dir. -llvm_config.with_environment('PATH', config.flang_tools_dir, append_path=True) -llvm_config.with_environment('PATH', config.llvm_tools_dir, append_path=True) - -if config.flang_standalone_build: - # For builds with FIR, set path for tco and enable related tests - if config.flang_llvm_tools_dir != "": - config.available_features.add('fir') - if config.llvm_tools_dir != config.flang_llvm_tools_dir: - llvm_config.with_environment('PATH', config.flang_llvm_tools_dir, append_path=True) - -# For each occurrence of a flang tool name, replace it with the full path to -# the build directory holding that tool. -tools = [ - ToolSubst('%flang', command=FindTool('flang-new'), unresolved='fatal'), - ToolSubst('%flang_fc1', command=FindTool('flang-new'), extra_args=['-fc1'], - unresolved='fatal')] - -# Flang has several unimplemented features. TODO messages are used to mark and fail if these -# features are exercised. TODOs exit with an error in non-assert builds but in assert builds -# it aborts. To catch aborts, the `--crash` option for the `not` command has to be used. -if 'asserts' in config.available_features: - tools.append(ToolSubst('%not_todo_cmd', command=FindTool('not'), extra_args=['--crash'], - unresolved='fatal')) -else: - tools.append(ToolSubst('%not_todo_cmd', command=FindTool('not'), unresolved='fatal')) - -# Define some variables to help us test that the flang runtime doesn't depend on -# the C++ runtime libraries. For this we need a C compiler. If for some reason -# we don't have one, we can just disable the test. -if config.cc: - libruntime = os.path.join(config.flang_lib_dir, 'libFortranRuntime.a') - libdecimal = os.path.join(config.flang_lib_dir, 'libFortranDecimal.a') - include = os.path.join(config.flang_src_dir, 'include') - - if os.path.isfile(libruntime) and os.path.isfile(libdecimal) and os.path.isdir(include): - config.available_features.add('c-compiler') - tools.append(ToolSubst('%cc', command=config.cc, unresolved='fatal')) - tools.append(ToolSubst('%libruntime', command=libruntime, - unresolved='fatal')) - tools.append(ToolSubst('%libdecimal', command=libdecimal, - unresolved='fatal')) - tools.append(ToolSubst('%include', command=include, - unresolved='fatal')) - -# Add all the tools and their substitutions (if applicable). Use the search paths provided for -# finding the tools. -if config.flang_standalone_build: - llvm_config.add_tool_substitutions(tools, [config.flang_llvm_tools_dir, config.llvm_tools_dir]) -else: - llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir) - -# Enable libpgmath testing -result = lit_config.params.get("LIBPGMATH") -if result: - config.environment["LIBPGMATH"] = True