[flang-commits] [flang] 9cbeb97 - [flang][hlfir] move intrinsic lowering out of BufferizeHLFIR

Tom Eccles via flang-commits flang-commits at lists.llvm.org
Fri Mar 17 02:30:53 PDT 2023


Author: Tom Eccles
Date: 2023-03-17T09:30:04Z
New Revision: 9cbeb97024515e6c1fca506623c384b4876ac231

URL: https://github.com/llvm/llvm-project/commit/9cbeb97024515e6c1fca506623c384b4876ac231
DIFF: https://github.com/llvm/llvm-project/commit/9cbeb97024515e6c1fca506623c384b4876ac231.diff

LOG: [flang][hlfir] move intrinsic lowering out of BufferizeHLFIR

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

Added: 
    flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp
    flang/test/HLFIR/matmul-lowering.fir
    flang/test/HLFIR/sum-lowering.fir
    flang/test/HLFIR/transpose-lowering.fir

Modified: 
    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

Removed: 
    flang/test/HLFIR/matmul-bufferization.fir
    flang/test/HLFIR/sum-bufferization.fir
    flang/test/HLFIR/transpose-bufferization.fir


################################################################################
diff  --git a/flang/include/flang/Optimizer/HLFIR/Passes.h b/flang/include/flang/Optimizer/HLFIR/Passes.h
index 53d2186843462..2d9ac0c8e64b6 100644
--- a/flang/include/flang/Optimizer/HLFIR/Passes.h
+++ b/flang/include/flang/Optimizer/HLFIR/Passes.h
@@ -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"

diff  --git a/flang/include/flang/Optimizer/HLFIR/Passes.td b/flang/include/flang/Optimizer/HLFIR/Passes.td
index 3fac0b2a1ea87..faf5cd99d8ac3 100644
--- a/flang/include/flang/Optimizer/HLFIR/Passes.td
+++ b/flang/include/flang/Optimizer/HLFIR/Passes.td
@@ -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

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
index cc44e0eebd4ec..44a61f0d9ef7d 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
@@ -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 @@ class BufferizeHLFIR : public hlfir::impl::BufferizeHLFIRBase<BufferizeHLFIR> {
         .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,

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt b/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt
index b89d6b76bf653..0323dce441640 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt
+++ b/flang/lib/Optimizer/HLFIR/Transforms/CMakeLists.txt
@@ -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
index 0000000000000..eac0621431737
--- /dev/null
+++ b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp
@@ -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>();
+}

diff  --git a/flang/test/HLFIR/matmul-bufferization.fir b/flang/test/HLFIR/matmul-lowering.fir
similarity index 87%
rename from flang/test/HLFIR/matmul-bufferization.fir
rename to flang/test/HLFIR/matmul-lowering.fir
index 54da40cf303f9..d4819f18c62af 100644
--- a/flang/test/HLFIR/matmul-bufferization.fir
+++ b/flang/test/HLFIR/matmul-lowering.fir
@@ -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:  }

diff  --git a/flang/test/HLFIR/sum-bufferization.fir b/flang/test/HLFIR/sum-lowering.fir
similarity index 96%
rename from flang/test/HLFIR/sum-bufferization.fir
rename to flang/test/HLFIR/sum-lowering.fir
index d1bdd9fbd67a1..c031f6dacf27d 100644
--- a/flang/test/HLFIR/sum-bufferization.fir
+++ b/flang/test/HLFIR/sum-lowering.fir
@@ -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:  }
 

diff  --git a/flang/test/HLFIR/transpose-bufferization.fir b/flang/test/HLFIR/transpose-lowering.fir
similarity index 86%
rename from flang/test/HLFIR/transpose-bufferization.fir
rename to flang/test/HLFIR/transpose-lowering.fir
index 0db359adebd32..733e6f1a61090 100644
--- a/flang/test/HLFIR/transpose-bufferization.fir
+++ b/flang/test/HLFIR/transpose-lowering.fir
@@ -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:  }


        


More information about the flang-commits mailing list