diff --git a/flang/include/flang/Optimizer/Transforms/CMakeLists.txt b/flang/include/flang/Optimizer/Transforms/CMakeLists.txt --- a/flang/include/flang/Optimizer/Transforms/CMakeLists.txt +++ b/flang/include/flang/Optimizer/Transforms/CMakeLists.txt @@ -1,5 +1,8 @@ +set(LLVM_TARGET_DEFINITIONS RewritePatterns.td) +mlir_tablegen(RewritePatterns.inc -gen-rewriters) +add_public_tablegen_target(RewritePatternsIncGen) + set(LLVM_TARGET_DEFINITIONS Passes.td) mlir_tablegen(Passes.h.inc -gen-pass-decls -name OptTransform) add_public_tablegen_target(FIROptTransformsPassIncGen) - diff --git a/flang/include/flang/Optimizer/Transforms/RewritePatterns.td b/flang/include/flang/Optimizer/Transforms/RewritePatterns.td new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Transforms/RewritePatterns.td @@ -0,0 +1,59 @@ +//===-- RewritePatterns.td - FIR Rewrite Patterns -----------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines pattern rewrites for fir optimizations +/// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_FIR_REWRITE_PATTERNS +#define FORTRAN_FIR_REWRITE_PATTERNS + +include "mlir/IR/OpBase.td" +include "mlir/Dialect/StandardOps/IR/Ops.td" +include "flang/Optimizer/Dialect/FIROps.td" + +def IdenticalTypePred : Constraint>; +def IntegerTypePred : Constraint>; +def IndexTypePred : Constraint()">>; + +def SmallerWidthPred + : Constraint>; + +def ConvertConvertOptPattern + : Pat<(fir_ConvertOp (fir_ConvertOp $arg)), + (fir_ConvertOp $arg), + [(IntegerTypePred $arg)]>; + +def RedundantConvertOptPattern + : Pat<(fir_ConvertOp:$res $arg), + (replaceWithValue $arg), + [(IdenticalTypePred $res, $arg) + ,(IntegerTypePred $arg)]>; + +def CombineConvertOptPattern + : Pat<(fir_ConvertOp:$res(fir_ConvertOp:$irm $arg)), + (replaceWithValue $arg), + [(IdenticalTypePred $res, $arg) + ,(IntegerTypePred $arg) + ,(IntegerTypePred $irm) + ,(SmallerWidthPred $arg, $irm)]>; + +def createConstantOp + : NativeCodeCall<"$_builder.create" + "($_loc, $_builder.getIndexType(), " + "rewriter.getIndexAttr($1.dyn_cast().getInt()))">; + +def ForwardConstantConvertPattern + : Pat<(fir_ConvertOp:$res (ConstantOp:$cnt $attr)), + (createConstantOp $res, $attr), + [(IndexTypePred $res) + ,(IntegerTypePred $cnt)]>; + +#endif // FORTRAN_FIR_REWRITE_PATTERNS diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -24,6 +24,9 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/TypeSwitch.h" +namespace { +#include "flang/Optimizer/Transforms/RewritePatterns.inc" +} // namespace using namespace fir; /// Return true if a sequence type is of some incomplete size or a record type @@ -772,7 +775,11 @@ //===----------------------------------------------------------------------===// void fir::ConvertOp::getCanonicalizationPatterns( - OwningRewritePatternList &results, MLIRContext *context) {} + OwningRewritePatternList &results, MLIRContext *context) { + results.insert( + context); +} mlir::OpFoldResult fir::ConvertOp::fold(llvm::ArrayRef opnds) { if (value().getType() == getType()) diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt --- a/flang/lib/Optimizer/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt @@ -9,6 +9,7 @@ FIRDialect FIRSupport FIROptTransformsPassIncGen + RewritePatternsIncGen LINK_LIBS FIRDialect diff --git a/flang/test/Fir/convert-fold.fir b/flang/test/Fir/convert-fold.fir new file mode 100644 --- /dev/null +++ b/flang/test/Fir/convert-fold.fir @@ -0,0 +1,37 @@ +// RUN: fir-opt --canonicalize %s | FileCheck %s + +// CHECK-LABEL: @ftest +func @ftest(%x : i1) -> i1 { + // this pair of converts should be folded and DCEd + %1 = fir.convert %x : (i1) -> !fir.logical<1> + %2 = fir.convert %1 : (!fir.logical<1>) -> i1 + // CHECK-NEXT: return %{{.*}} : i1 + return %2 : i1 +} + +// CHECK-LABEL: @gtest +func @gtest(%x : !fir.logical<2>) -> !fir.logical<2> { + // this pair of converts should be folded and DCEd + %1 = fir.convert %x : (!fir.logical<2>) -> i1 + %2 = fir.convert %1 : (i1) -> !fir.logical<2> + // CHECK-NEXT: return %{{.*}} : !fir.logical<2> + return %2 : !fir.logical<2> +} + +// CHECK-LABEL: @htest +func @htest(%x : !fir.int<4>) -> !fir.int<4> { + // these converts are NOPs and should be folded away + %1 = fir.convert %x : (!fir.int<4>) -> !fir.int<4> + %2 = fir.convert %1 : (!fir.int<4>) -> !fir.int<4> + // CHECK-NEXT: return %{{.*}} : !fir.int<4> + return %2 : !fir.int<4> +} + +// CHECK-LABEL: @ctest +func @ctest() -> index { + %1 = constant 10 : i32 + %2 = fir.convert %1 : (i32) -> index + // CHECK-NEXT: %{{.*}} = constant : index + // CHECK-NEXT: return %{{.*}} : index + return %2 : index +}