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"
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
#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"
#include "mlir/Pass/PassManager.h"
#include "mlir/Transforms/DialectConversion.h"
#include <mlir/Support/LogicalResult.h>
-#include <optional>
namespace hlfir {
#define GEN_PASS_DEF_BUFFERIZEHLFIR
}
};
-/// 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 {
.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,
add_flang_library(HLFIRTransforms
BufferizeHLFIR.cpp
ConvertToFIR.cpp
+ LowerHLFIRIntrinsics.cpp
DEPENDS
FIRDialect
--- /dev/null
+//===- 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>();
+}
// 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>>)
// 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: }
// 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"}) {
// 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: }
// 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
// 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: }