[flang][hlfir] move intrinsic lowering out of BufferizeHLFIR
authorTom Eccles <tom.eccles@arm.com>
Fri, 17 Mar 2023 09:25:52 +0000 (09:25 +0000)
committerTom Eccles <tom.eccles@arm.com>
Fri, 17 Mar 2023 09:30:04 +0000 (09:30 +0000)
This move is useful for a few reasons:
  - It is easier to see what the intrinsic lowering is doing when the
    operations it creates are not immediately lowered
  - When lowering a HLFIR intrinsic generates an operation which needs
    to be lowered by another pattern matcher in the same pass, MLIR will
    run that other substitution before validating and finalizing the
    original changes. This means that the erasure of operations is not
    yet visible to subsequent matchers, which hugely complicates
    transformations (in this case, hlfir.exprs cannot be rewritten
    because they are still used by the now-erased HLFIR intrinsic op.

Reviewed By: jeanPerier

Differential Revision: https://reviews.llvm.org/D145502

flang/include/flang/Optimizer/HLFIR/Passes.h
flang/include/flang/Optimizer/HLFIR/Passes.td
flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt
flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp [new file with mode: 0644]
flang/test/HLFIR/matmul-lowering.fir [moved from flang/test/HLFIR/matmul-bufferization.fir with 87% similarity]
flang/test/HLFIR/sum-lowering.fir [moved from flang/test/HLFIR/sum-bufferization.fir with 96% similarity]
flang/test/HLFIR/transpose-lowering.fir [moved from flang/test/HLFIR/transpose-bufferization.fir with 86% similarity]

index 53d2186..2d9ac0c 100644 (file)
@@ -23,6 +23,7 @@ namespace hlfir {
 
 std::unique_ptr<mlir::Pass> createConvertHLFIRtoFIRPass();
 std::unique_ptr<mlir::Pass> createBufferizeHLFIRPass();
+std::unique_ptr<mlir::Pass> createLowerHLFIRIntrinsicsPass();
 
 #define GEN_PASS_REGISTRATION
 #include "flang/Optimizer/HLFIR/Passes.h.inc"
index 3fac0b2..faf5cd9 100644 (file)
@@ -20,4 +20,9 @@ def BufferizeHLFIR : Pass<"bufferize-hlfir", "::mlir::ModuleOp"> {
   let constructor = "hlfir::createBufferizeHLFIRPass()";
 }
 
+def LowerHLFIRIntrinsics : Pass<"lower-hlfir-intrinsics", "::mlir::ModuleOp"> {
+  let summary = "Lower HLFIR transformational intrinsic operations";
+  let constructor = "hlfir::createLowerHLFIRIntrinsicsPass()";
+}
+
 #endif //FORTRAN_DIALECT_HLFIR_PASSES
index cc44e0e..44a61f0 100644 (file)
@@ -15,8 +15,6 @@
 #include "flang/Optimizer/Builder/Character.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/HLFIRTools.h"
-#include "flang/Optimizer/Builder/IntrinsicCall.h"
-#include "flang/Optimizer/Builder/MutableBox.h"
 #include "flang/Optimizer/Builder/Runtime/Assign.h"
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
@@ -31,7 +29,6 @@
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Transforms/DialectConversion.h"
 #include <mlir/Support/LogicalResult.h>
-#include <optional>
 
 namespace hlfir {
 #define GEN_PASS_DEF_BUFFERIZEHLFIR
@@ -510,219 +507,6 @@ struct ElementalOpConversion
   }
 };
 
-/// Base class for passes converting transformational intrinsic operations into
-/// runtime calls
-template <class OP>
-class HlfirIntrinsicConversion : public mlir::OpConversionPattern<OP> {
-  using mlir::OpConversionPattern<OP>::OpConversionPattern;
-
-protected:
-  struct IntrinsicArgument {
-    mlir::Value val; // allowed to be null if the argument is absent
-    mlir::Type desiredType;
-  };
-
-  /// Lower the arguments to the intrinsic: adding nesecarry boxing and
-  /// conversion to match the signature of the intrinsic in the runtime library.
-  llvm::SmallVector<fir::ExtendedValue, 3>
-  lowerArguments(mlir::Operation *op,
-                 const llvm::ArrayRef<IntrinsicArgument> &args,
-                 mlir::ConversionPatternRewriter &rewriter,
-                 const fir::IntrinsicArgumentLoweringRules *argLowering) const {
-    mlir::Location loc = op->getLoc();
-    fir::KindMapping kindMapping{rewriter.getContext()};
-    fir::FirOpBuilder builder{rewriter, kindMapping};
-
-    llvm::SmallVector<fir::ExtendedValue, 3> ret;
-
-    for (size_t i = 0; i < args.size(); ++i) {
-      mlir::Value arg = args[i].val;
-      mlir::Type desiredType = args[i].desiredType;
-      if (!arg) {
-        ret.emplace_back(fir::getAbsentIntrinsicArgument());
-        continue;
-      }
-      hlfir::Entity entity{arg};
-
-      fir::ArgLoweringRule argRules =
-          fir::lowerIntrinsicArgumentAs(*argLowering, i);
-      switch (argRules.lowerAs) {
-      case fir::LowerIntrinsicArgAs::Value: {
-        if (args[i].desiredType != arg.getType()) {
-          arg = builder.createConvert(loc, desiredType, arg);
-          entity = hlfir::Entity{arg};
-        }
-        auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
-        if (cleanup)
-          TODO(loc, "extended value cleanup");
-        ret.emplace_back(exv);
-      } break;
-      case fir::LowerIntrinsicArgAs::Addr: {
-        auto [exv, cleanup] =
-            hlfir::convertToAddress(loc, builder, entity, desiredType);
-        if (cleanup)
-          TODO(loc, "extended value cleanup");
-        ret.emplace_back(exv);
-      } break;
-      case fir::LowerIntrinsicArgAs::Box: {
-        auto [box, cleanup] =
-            hlfir::convertToBox(loc, builder, entity, desiredType);
-        if (cleanup)
-          TODO(loc, "extended value cleanup");
-        ret.emplace_back(box);
-      } break;
-      case fir::LowerIntrinsicArgAs::Inquired: {
-        if (args[i].desiredType != arg.getType()) {
-          arg = builder.createConvert(loc, desiredType, arg);
-          entity = hlfir::Entity{arg};
-        }
-        // Place hlfir.expr in memory, and unbox fir.boxchar. Other entities
-        // are translated to fir::ExtendedValue without transofrmation (notably,
-        // pointers/allocatable are not dereferenced).
-        // TODO: once lowering to FIR retires, UBOUND and LBOUND can be
-        // simplified since the fir.box lowered here are now guarenteed to
-        // contain the local lower bounds thanks to the hlfir.declare (the extra
-        // rebox can be removed).
-        auto [exv, cleanup] =
-            hlfir::translateToExtendedValue(loc, builder, entity);
-        if (cleanup)
-          TODO(loc, "extended value cleanup");
-        ret.emplace_back(exv);
-      } break;
-      }
-    }
-
-    return ret;
-  }
-
-  void processReturnValue(mlir::Operation *op,
-                          const fir::ExtendedValue &resultExv, bool mustBeFreed,
-                          fir::FirOpBuilder &builder,
-                          mlir::PatternRewriter &rewriter) const {
-    mlir::Location loc = op->getLoc();
-
-    mlir::Value firBase = fir::getBase(resultExv);
-    mlir::Type firBaseTy = firBase.getType();
-
-    std::optional<hlfir::EntityWithAttributes> resultEntity;
-    if (fir::isa_trivial(firBaseTy)) {
-      resultEntity = hlfir::EntityWithAttributes{firBase};
-    } else {
-      resultEntity =
-          hlfir::genDeclare(loc, builder, resultExv, ".tmp.intrinsic_result",
-                            fir::FortranVariableFlagsAttr{});
-    }
-
-    if (resultEntity->isVariable()) {
-      hlfir::AsExprOp asExpr = builder.create<hlfir::AsExprOp>(
-          loc, *resultEntity, builder.createBool(loc, mustBeFreed));
-      resultEntity = hlfir::EntityWithAttributes{asExpr.getResult()};
-    }
-
-    rewriter.replaceOp(op, resultEntity->getBase());
-  }
-};
-
-struct SumOpConversion : public HlfirIntrinsicConversion<hlfir::SumOp> {
-  using HlfirIntrinsicConversion<hlfir::SumOp>::HlfirIntrinsicConversion;
-
-  mlir::LogicalResult
-  matchAndRewrite(hlfir::SumOp sum, OpAdaptor adaptor,
-                  mlir::ConversionPatternRewriter &rewriter) const override {
-    fir::KindMapping kindMapping{rewriter.getContext()};
-    fir::FirOpBuilder builder{rewriter, kindMapping};
-    const mlir::Location &loc = sum->getLoc();
-    HLFIRListener listener{builder, rewriter};
-    builder.setListener(&listener);
-
-    mlir::Type i32 = builder.getI32Type();
-    mlir::Type logicalType = fir::LogicalType::get(
-        builder.getContext(), builder.getKindMap().defaultLogicalKind());
-
-    llvm::SmallVector<IntrinsicArgument, 3> inArgs;
-    inArgs.push_back({sum.getArray(), sum.getArray().getType()});
-    inArgs.push_back({sum.getDim(), i32});
-    inArgs.push_back({sum.getMask(), logicalType});
-
-    auto *argLowering = fir::getIntrinsicArgumentLowering("sum");
-    llvm::SmallVector<fir::ExtendedValue, 3> args =
-        lowerArguments(sum, inArgs, rewriter, argLowering);
-
-    mlir::Type scalarResultType = hlfir::getFortranElementType(sum.getType());
-
-    auto [resultExv, mustBeFreed] =
-        fir::genIntrinsicCall(builder, loc, "sum", scalarResultType, args);
-
-    processReturnValue(sum, resultExv, mustBeFreed, builder, rewriter);
-    return mlir::success();
-  }
-};
-
-struct MatmulOpConversion : public HlfirIntrinsicConversion<hlfir::MatmulOp> {
-  using HlfirIntrinsicConversion<hlfir::MatmulOp>::HlfirIntrinsicConversion;
-
-  mlir::LogicalResult
-  matchAndRewrite(hlfir::MatmulOp matmul, OpAdaptor adaptor,
-                  mlir::ConversionPatternRewriter &rewriter) const override {
-    fir::KindMapping kindMapping{rewriter.getContext()};
-    fir::FirOpBuilder builder{rewriter, kindMapping};
-    const mlir::Location &loc = matmul->getLoc();
-    HLFIRListener listener{builder, rewriter};
-    builder.setListener(&listener);
-
-    mlir::Value lhs = matmul.getLhs();
-    mlir::Value rhs = matmul.getRhs();
-    llvm::SmallVector<IntrinsicArgument, 2> inArgs;
-    inArgs.push_back({lhs, lhs.getType()});
-    inArgs.push_back({rhs, rhs.getType()});
-
-    auto *argLowering = fir::getIntrinsicArgumentLowering("matmul");
-    llvm::SmallVector<fir::ExtendedValue, 2> args =
-        lowerArguments(matmul, inArgs, rewriter, argLowering);
-
-    mlir::Type scalarResultType =
-        hlfir::getFortranElementType(matmul.getType());
-
-    auto [resultExv, mustBeFreed] =
-        fir::genIntrinsicCall(builder, loc, "matmul", scalarResultType, args);
-
-    processReturnValue(matmul, resultExv, mustBeFreed, builder, rewriter);
-    return mlir::success();
-  }
-};
-
-class TransposeOpConversion
-    : public HlfirIntrinsicConversion<hlfir::TransposeOp> {
-  using HlfirIntrinsicConversion<hlfir::TransposeOp>::HlfirIntrinsicConversion;
-
-  mlir::LogicalResult
-  matchAndRewrite(hlfir::TransposeOp transpose, OpAdaptor adaptor,
-                  mlir::ConversionPatternRewriter &rewriter) const override {
-    fir::KindMapping kindMapping{rewriter.getContext()};
-    fir::FirOpBuilder builder{rewriter, kindMapping};
-    const mlir::Location &loc = transpose->getLoc();
-    HLFIRListener listener{builder, rewriter};
-    builder.setListener(&listener);
-
-    mlir::Value arg = transpose.getArray();
-    llvm::SmallVector<IntrinsicArgument, 1> inArgs;
-    inArgs.push_back({arg, arg.getType()});
-
-    auto *argLowering = fir::getIntrinsicArgumentLowering("transpose");
-    llvm::SmallVector<fir::ExtendedValue, 1> args =
-        lowerArguments(transpose, inArgs, rewriter, argLowering);
-
-    mlir::Type scalarResultType =
-        hlfir::getFortranElementType(transpose.getType());
-
-    auto [resultExv, mustBeFreed] = fir::genIntrinsicCall(
-        builder, loc, "transpose", scalarResultType, args);
-
-    processReturnValue(transpose, resultExv, mustBeFreed, builder, rewriter);
-    return mlir::success();
-  }
-};
-
 class BufferizeHLFIR : public hlfir::impl::BufferizeHLFIRBase<BufferizeHLFIR> {
 public:
   void runOnOperation() override {
@@ -740,9 +524,7 @@ public:
         .insert<ApplyOpConversion, AsExprOpConversion, AssignOpConversion,
                 AssociateOpConversion, ConcatOpConversion, DestroyOpConversion,
                 ElementalOpConversion, EndAssociateOpConversion,
-                MatmulOpConversion, NoReassocOpConversion,
-                SetLengthOpConversion, SumOpConversion, TransposeOpConversion>(
-            context);
+                NoReassocOpConversion, SetLengthOpConversion>(context);
     mlir::ConversionTarget target(*context);
     target.addIllegalOp<hlfir::ApplyOp, hlfir::AssociateOp, hlfir::ElementalOp,
                         hlfir::EndAssociateOp, hlfir::SetLengthOp,
index b89d6b7..0323dce 100644 (file)
@@ -3,6 +3,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
 add_flang_library(HLFIRTransforms
   BufferizeHLFIR.cpp
   ConvertToFIR.cpp
+  LowerHLFIRIntrinsics.cpp
 
   DEPENDS
   FIRDialect
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp
new file mode 100644 (file)
index 0000000..eac0621
--- /dev/null
@@ -0,0 +1,286 @@
+//===- LowerHLFIRIntrinsics.cpp - Bufferize HLFIR  ------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Builder/IntrinsicCall.h"
+#include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
+#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "flang/Optimizer/HLFIR/Passes.h"
+#include "mlir/IR/BuiltinDialect.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Pass/PassManager.h"
+#include "mlir/Support/LogicalResult.h"
+#include "mlir/Transforms/DialectConversion.h"
+#include <mlir/IR/MLIRContext.h>
+#include <optional>
+
+namespace hlfir {
+#define GEN_PASS_DEF_LOWERHLFIRINTRINSICS
+#include "flang/Optimizer/HLFIR/Passes.h.inc"
+} // namespace hlfir
+
+namespace {
+
+/// Base class for passes converting transformational intrinsic operations into
+/// runtime calls
+template <class OP>
+class HlfirIntrinsicConversion : public mlir::OpRewritePattern<OP> {
+  using mlir::OpRewritePattern<OP>::OpRewritePattern;
+
+protected:
+  struct IntrinsicArgument {
+    mlir::Value val; // allowed to be null if the argument is absent
+    mlir::Type desiredType;
+  };
+
+  /// Lower the arguments to the intrinsic: adding nesecarry boxing and
+  /// conversion to match the signature of the intrinsic in the runtime library.
+  llvm::SmallVector<fir::ExtendedValue, 3>
+  lowerArguments(mlir::Operation *op,
+                 const llvm::ArrayRef<IntrinsicArgument> &args,
+                 mlir::PatternRewriter &rewriter,
+                 const fir::IntrinsicArgumentLoweringRules *argLowering) const {
+    mlir::Location loc = op->getLoc();
+    fir::KindMapping kindMapping{rewriter.getContext()};
+    fir::FirOpBuilder builder{rewriter, kindMapping};
+
+    llvm::SmallVector<fir::ExtendedValue, 3> ret;
+
+    for (size_t i = 0; i < args.size(); ++i) {
+      mlir::Value arg = args[i].val;
+      mlir::Type desiredType = args[i].desiredType;
+      if (!arg) {
+        ret.emplace_back(fir::getAbsentIntrinsicArgument());
+        continue;
+      }
+      hlfir::Entity entity{arg};
+
+      fir::ArgLoweringRule argRules =
+          fir::lowerIntrinsicArgumentAs(*argLowering, i);
+      switch (argRules.lowerAs) {
+      case fir::LowerIntrinsicArgAs::Value: {
+        if (args[i].desiredType != arg.getType()) {
+          arg = builder.createConvert(loc, desiredType, arg);
+          entity = hlfir::Entity{arg};
+        }
+        auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
+        if (cleanup)
+          TODO(loc, "extended value cleanup");
+        ret.emplace_back(exv);
+      } break;
+      case fir::LowerIntrinsicArgAs::Addr: {
+        auto [exv, cleanup] =
+            hlfir::convertToAddress(loc, builder, entity, desiredType);
+        if (cleanup)
+          TODO(loc, "extended value cleanup");
+        ret.emplace_back(exv);
+      } break;
+      case fir::LowerIntrinsicArgAs::Box: {
+        auto [box, cleanup] =
+            hlfir::convertToBox(loc, builder, entity, desiredType);
+        if (cleanup)
+          TODO(loc, "extended value cleanup");
+        ret.emplace_back(box);
+      } break;
+      case fir::LowerIntrinsicArgAs::Inquired: {
+        if (args[i].desiredType != arg.getType()) {
+          arg = builder.createConvert(loc, desiredType, arg);
+          entity = hlfir::Entity{arg};
+        }
+        // Place hlfir.expr in memory, and unbox fir.boxchar. Other entities
+        // are translated to fir::ExtendedValue without transofrmation (notably,
+        // pointers/allocatable are not dereferenced).
+        // TODO: once lowering to FIR retires, UBOUND and LBOUND can be
+        // simplified since the fir.box lowered here are now guarenteed to
+        // contain the local lower bounds thanks to the hlfir.declare (the extra
+        // rebox can be removed).
+        auto [exv, cleanup] =
+            hlfir::translateToExtendedValue(loc, builder, entity);
+        if (cleanup)
+          TODO(loc, "extended value cleanup");
+        ret.emplace_back(exv);
+      } break;
+      }
+    }
+
+    return ret;
+  }
+
+  void processReturnValue(mlir::Operation *op,
+                          const fir::ExtendedValue &resultExv, bool mustBeFreed,
+                          fir::FirOpBuilder &builder,
+                          mlir::PatternRewriter &rewriter) const {
+    mlir::Location loc = op->getLoc();
+
+    mlir::Value firBase = fir::getBase(resultExv);
+    mlir::Type firBaseTy = firBase.getType();
+
+    std::optional<hlfir::EntityWithAttributes> resultEntity;
+    if (fir::isa_trivial(firBaseTy)) {
+      resultEntity = hlfir::EntityWithAttributes{firBase};
+    } else {
+      resultEntity =
+          hlfir::genDeclare(loc, builder, resultExv, ".tmp.intrinsic_result",
+                            fir::FortranVariableFlagsAttr{});
+    }
+
+    if (resultEntity->isVariable()) {
+      hlfir::AsExprOp asExpr = builder.create<hlfir::AsExprOp>(
+          loc, *resultEntity, builder.createBool(loc, mustBeFreed));
+      resultEntity = hlfir::EntityWithAttributes{asExpr.getResult()};
+    }
+
+    mlir::Value base = resultEntity->getBase();
+    if (!mlir::isa<hlfir::ExprType>(base.getType())) {
+      for (mlir::Operation *use : op->getResult(0).getUsers()) {
+        if (mlir::isa<hlfir::DestroyOp>(use))
+          rewriter.eraseOp(use);
+      }
+    }
+    rewriter.replaceAllUsesWith(op->getResults(), {base});
+    rewriter.replaceOp(op, base);
+  }
+};
+
+struct SumOpConversion : public HlfirIntrinsicConversion<hlfir::SumOp> {
+  using HlfirIntrinsicConversion<hlfir::SumOp>::HlfirIntrinsicConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(hlfir::SumOp sum,
+                  mlir::PatternRewriter &rewriter) const override {
+    fir::KindMapping kindMapping{rewriter.getContext()};
+    fir::FirOpBuilder builder{rewriter, kindMapping};
+    const mlir::Location &loc = sum->getLoc();
+
+    mlir::Type i32 = builder.getI32Type();
+    mlir::Type logicalType = fir::LogicalType::get(
+        builder.getContext(), builder.getKindMap().defaultLogicalKind());
+
+    llvm::SmallVector<IntrinsicArgument, 3> inArgs;
+    inArgs.push_back({sum.getArray(), sum.getArray().getType()});
+    inArgs.push_back({sum.getDim(), i32});
+    inArgs.push_back({sum.getMask(), logicalType});
+
+    auto *argLowering = fir::getIntrinsicArgumentLowering("sum");
+    llvm::SmallVector<fir::ExtendedValue, 3> args =
+        lowerArguments(sum, inArgs, rewriter, argLowering);
+
+    mlir::Type scalarResultType = hlfir::getFortranElementType(sum.getType());
+
+    auto [resultExv, mustBeFreed] =
+        fir::genIntrinsicCall(builder, loc, "sum", scalarResultType, args);
+
+    processReturnValue(sum, resultExv, mustBeFreed, builder, rewriter);
+    return mlir::success();
+  }
+};
+
+struct MatmulOpConversion : public HlfirIntrinsicConversion<hlfir::MatmulOp> {
+  using HlfirIntrinsicConversion<hlfir::MatmulOp>::HlfirIntrinsicConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(hlfir::MatmulOp matmul,
+                  mlir::PatternRewriter &rewriter) const override {
+    fir::KindMapping kindMapping{rewriter.getContext()};
+    fir::FirOpBuilder builder{rewriter, kindMapping};
+    const mlir::Location &loc = matmul->getLoc();
+
+    mlir::Value lhs = matmul.getLhs();
+    mlir::Value rhs = matmul.getRhs();
+    llvm::SmallVector<IntrinsicArgument, 2> inArgs;
+    inArgs.push_back({lhs, lhs.getType()});
+    inArgs.push_back({rhs, rhs.getType()});
+
+    auto *argLowering = fir::getIntrinsicArgumentLowering("matmul");
+    llvm::SmallVector<fir::ExtendedValue, 2> args =
+        lowerArguments(matmul, inArgs, rewriter, argLowering);
+
+    mlir::Type scalarResultType =
+        hlfir::getFortranElementType(matmul.getType());
+
+    auto [resultExv, mustBeFreed] =
+        fir::genIntrinsicCall(builder, loc, "matmul", scalarResultType, args);
+
+    processReturnValue(matmul, resultExv, mustBeFreed, builder, rewriter);
+    return mlir::success();
+  }
+};
+
+class TransposeOpConversion
+    : public HlfirIntrinsicConversion<hlfir::TransposeOp> {
+  using HlfirIntrinsicConversion<hlfir::TransposeOp>::HlfirIntrinsicConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(hlfir::TransposeOp transpose,
+                  mlir::PatternRewriter &rewriter) const override {
+    fir::KindMapping kindMapping{rewriter.getContext()};
+    fir::FirOpBuilder builder{rewriter, kindMapping};
+    const mlir::Location &loc = transpose->getLoc();
+
+    mlir::Value arg = transpose.getArray();
+    llvm::SmallVector<IntrinsicArgument, 1> inArgs;
+    inArgs.push_back({arg, arg.getType()});
+
+    auto *argLowering = fir::getIntrinsicArgumentLowering("transpose");
+    llvm::SmallVector<fir::ExtendedValue, 1> args =
+        lowerArguments(transpose, inArgs, rewriter, argLowering);
+
+    mlir::Type scalarResultType =
+        hlfir::getFortranElementType(transpose.getType());
+
+    auto [resultExv, mustBeFreed] = fir::genIntrinsicCall(
+        builder, loc, "transpose", scalarResultType, args);
+
+    processReturnValue(transpose, resultExv, mustBeFreed, builder, rewriter);
+    return mlir::success();
+  }
+};
+
+class LowerHLFIRIntrinsics
+    : public hlfir::impl::LowerHLFIRIntrinsicsBase<LowerHLFIRIntrinsics> {
+public:
+  void runOnOperation() override {
+    // TODO: make this a pass operating on FuncOp. The issue is that
+    // FirOpBuilder helpers may generate new FuncOp because of runtime/llvm
+    // intrinsics calls creation. This may create race conflict if the pass is
+    // scheduled on FuncOp. A solution could be to provide an optional mutex
+    // when building a FirOpBuilder and locking around FuncOp and GlobalOp
+    // creation, but this needs a bit more thinking, so at this point the pass
+    // is scheduled on the moduleOp.
+    mlir::ModuleOp module = this->getOperation();
+    mlir::MLIRContext *context = &getContext();
+    mlir::RewritePatternSet patterns(context);
+    patterns.insert<MatmulOpConversion, SumOpConversion, TransposeOpConversion>(
+        context);
+    mlir::ConversionTarget target(*context);
+    target.addLegalDialect<mlir::BuiltinDialect, mlir::arith::ArithDialect,
+                           mlir::func::FuncDialect, fir::FIROpsDialect,
+                           hlfir::hlfirDialect>();
+    target.addIllegalOp<hlfir::MatmulOp, hlfir::SumOp, hlfir::TransposeOp>();
+    target.markUnknownOpDynamicallyLegal(
+        [](mlir::Operation *) { return true; });
+    if (mlir::failed(
+            mlir::applyFullConversion(module, target, std::move(patterns)))) {
+      mlir::emitError(mlir::UnknownLoc::get(context),
+                      "failure in HLFIR intrinsic lowering");
+      signalPassFailure();
+    }
+  }
+};
+} // namespace
+
+std::unique_ptr<mlir::Pass> hlfir::createLowerHLFIRIntrinsicsPass() {
+  return std::make_unique<LowerHLFIRIntrinsics>();
+}
similarity index 87%
rename from flang/test/HLFIR/matmul-bufferization.fir
rename to flang/test/HLFIR/matmul-lowering.fir
index 54da40c..d4819f1 100644 (file)
@@ -1,5 +1,5 @@
 // Test hlfir.matmul operation lowering to fir runtime call
-// RUN: fir-opt %s -bufferize-hlfir | FileCheck %s
+// RUN: fir-opt %s -lower-hlfir-intrinsics | FileCheck %s
 
 func.func @_QPmatmul1(%arg0: !fir.box<!fir.array<?x?xi32>> {fir.bindc_name = "lhs"}, %arg1: !fir.box<!fir.array<?x?xi32>> {fir.bindc_name = "rhs"}, %arg2: !fir.box<!fir.array<?x?xi32>> {fir.bindc_name = "res"}) {
   %0:2 = hlfir.declare %arg0 {uniq_name = "_QFmatmul1Elhs"} : (!fir.box<!fir.array<?x?xi32>>) -> (!fir.box<!fir.array<?x?xi32>>, !fir.box<!fir.array<?x?xi32>>)
@@ -36,10 +36,10 @@ func.func @_QPmatmul1(%arg0: !fir.box<!fir.array<?x?xi32>> {fir.bindc_name = "lh
 // CHECK-NEXT:    %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1
 // TODO: fix alias analysis in hlfir.assign bufferization
 // CHECK-NEXT:    %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"}
-// CHECK:         %[[TUPLE0:.*]] = fir.undefined tuple<!fir.box<!fir.array<?x?xi32>>, i1>
-// CHECK:         %[[TUPLE1:.*]] = fir.insert_value %[[TUPLE0]], %[[TRUE:.*]], [1 : index]
-// CHECK:         %[[TUPLE2:.*]] = fir.insert_value %[[TUPLE1]], %[[TMP]]#0, [0 : index]
-// CHECK:         hlfir.assign %[[TMP]]#0 to %[[RES_VAR]]#0
-// CHECK:         fir.freemem %[[TMP]]#1
+// TODO: add shape information from original intrinsic op
+// CHECK:         %[[TRUE:.*]] = arith.constant true
+// CHECK:         %[[ASEXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box<!fir.array<?x?xi32>>, i1) -> !hlfir.expr<?x?xi32>
+// CHECK:         hlfir.assign %[[ASEXPR]] to %[[RES_VAR]]#0
+// CHECK:         hlfir.destroy %[[ASEXPR]]
 // CHECK-NEXT:    return
 // CHECK-NEXT:  }
similarity index 96%
rename from flang/test/HLFIR/sum-bufferization.fir
rename to flang/test/HLFIR/sum-lowering.fir
index d1bdd9f..c031f6d 100644 (file)
@@ -1,5 +1,5 @@
 // Test hlfir.sum operation lowering to fir runtime call
-// RUN: fir-opt %s -bufferize-hlfir | FileCheck %s
+// RUN: fir-opt %s -lower-hlfir-intrinsics | FileCheck %s
 
 // simple one argument sum
 func.func @_QPsum1(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}, %arg1: !fir.ref<i32> {fir.bindc_name = "s"}) {
@@ -64,11 +64,10 @@ func.func @_QPsum2(%arg0: !fir.box<!fir.array<?x?xi32>> {fir.bindc_name = "a"},
 // CHECK-NEXT:    %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1
 // TODO: fix alias analysis in hlfir.assign bufferization
 // CHECK-NEXT:    %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"}
-// CHECK:         %[[TUPLE0:.*]] = fir.undefined tuple<!fir.box<!fir.array<?xi32>>, i1>
-// CHECK:         %[[TUPLE1:.*]] = fir.insert_value %[[TUPLE0]], %[[TRUE:.*]], [1 : index]
-// CHECK:         %[[TUPLE2:.*]] fir.insert_value %[[TUPLE1]], %[[TMP]]#0, [0 : index]
-// CHECK:         hlfir.assign %[[TMP]]#0 to %[[RES]]#0
-// CHECK:         fir.freemem %[[TMP]]#1
+// CHECK:         %[[TRUE:.*]] = arith.constant true
+// CHECK:         %[[ASEXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box<!fir.array<?xi32>>, i1) -> !hlfir.expr<?xi32>
+// CHECK:         hlfir.assign %[[ASEXPR]] to %[[RES]]#0
+// CHECK:         hlfir.destroy %[[ASEXPR]]
 // CHECK-NEXT:    return
 // CHECK-NEXT:  }
 
similarity index 86%
rename from flang/test/HLFIR/transpose-bufferization.fir
rename to flang/test/HLFIR/transpose-lowering.fir
index 0db359a..733e6f1 100644 (file)
@@ -1,5 +1,5 @@
 // Test hlfir.transpose operation lowering to fir runtime call
-// RUN: fir-opt %s -bufferize-hlfir | FileCheck %s
+// RUN: fir-opt %s -lower-hlfir-intrinsics | FileCheck %s
 
 func.func @_QPtranspose1(%arg0: !fir.ref<!fir.array<1x2xi32>> {fir.bindc_name = "m"}, %arg1: !fir.ref<!fir.array<2x1xi32>> {fir.bindc_name = "res"}) {
   %c1 = arith.constant 1 : index
@@ -40,10 +40,9 @@ func.func @_QPtranspose1(%arg0: !fir.ref<!fir.array<1x2xi32>> {fir.bindc_name =
 // CHECK-NEXT:    %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1
 // TODO: fix alias analysis in hlfir.assign bufferization
 // CHECK-NEXT:    %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"}
-// CHECK:         %[[TUPLE0:.*]] = fir.undefined tuple<!fir.box<!fir.array<?x?xi32>>, i1>
-// CHECK:         %[[TUPLE1:.*]] = fir.insert_value %[[TUPLE0]], %[[TRUE:.*]], [1 : index]
-// CHECK:         %[[TUPLE2:.*]] = fir.insert_value %[[TUPLE1]], %[[TMP]]#0, [0 : index]
-// CHECK:         hlfir.assign %[[TMP]]#0 to %[[RES_VAR]]#0
-// CHECK:         fir.freemem %[[TMP]]#1
+// CHECK:         %[[TRUE:.*]] = arith.constant true
+// CHECK:         %[[ASEXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box<!fir.array<?x?xi32>>, i1) -> !hlfir.expr<?x?xi32>
+// CHECK:         hlfir.assign %[[ASEXPR]] to %[[RES_VAR]]#0
+// CHECK:         hlfir.destroy %[[ASEXPR]]
 // CHECK-NEXT:    return
 // CHECK-NEXT:  }