From 94a11063573b4e1a3405d4a73d9928083115a6c1 Mon Sep 17 00:00:00 2001 From: Valentin Clement Date: Tue, 15 Mar 2022 22:18:45 +0100 Subject: [PATCH] [flang] Lower min|max intrinsics This patch adds lowering for the following intrinsics: - `max` - `maxloc` - `maxval` - `minloc` - `minval` This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: PeteSteinfeld Differential Revision: https://reviews.llvm.org/D121701 Co-authored-by: Jean Perier Co-authored-by: Eric Schweitz Co-authored-by: mleair --- flang/lib/Lower/Bridge.cpp | 8 +- flang/lib/Lower/ConvertExpr.cpp | 30 +++ flang/lib/Lower/IntrinsicCall.cpp | 232 +++++++++++++++++++++ flang/lib/Optimizer/Builder/MutableBox.cpp | 12 +- flang/test/Lower/Intrinsics/max.f90 | 139 ++++++++++++ flang/test/Lower/Intrinsics/maxloc.f90 | 89 ++++++++ flang/test/Lower/Intrinsics/maxval.f90 | 69 ++++++ flang/test/Lower/Intrinsics/minloc.f90 | 89 ++++++++ flang/test/Lower/Intrinsics/minval.f90 | 69 ++++++ 9 files changed, 725 insertions(+), 12 deletions(-) create mode 100644 flang/test/Lower/Intrinsics/max.f90 create mode 100644 flang/test/Lower/Intrinsics/maxloc.f90 create mode 100644 flang/test/Lower/Intrinsics/maxval.f90 create mode 100644 flang/test/Lower/Intrinsics/minloc.f90 create mode 100644 flang/test/Lower/Intrinsics/minval.f90 diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index e1f719742b2d..65e45d5f310c 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -249,12 +249,8 @@ public: fir::ExtendedValue genExprBox(const Fortran::lower::SomeExpr &expr, Fortran::lower::StatementContext &context, mlir::Location loc) override final { - if (expr.Rank() > 0 && Fortran::evaluate::IsVariable(expr) && - !Fortran::evaluate::HasVectorSubscript(expr)) - return Fortran::lower::createSomeArrayBox(*this, expr, localSymbols, - context); - return fir::BoxValue( - builder->createBox(loc, genExprAddr(expr, context, &loc))); + return Fortran::lower::createBoxValue(loc, *this, expr, localSymbols, + context); } Fortran::evaluate::FoldingContext &getFoldingContext() override final { diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp index 5a8ba4d1cd79..7ccb68677c6f 100644 --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -2681,6 +2681,36 @@ public: llvm::StringRef name = intrinsic.name; mlir::Location loc = getLoc(); + if (Fortran::lower::intrinsicRequiresCustomOptionalHandling( + procRef, intrinsic, converter)) { + using ExvAndPresence = std::pair>; + llvm::SmallVector operands; + auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) { + ExtValue optionalArg = lowerIntrinsicArgumentAsInquired(expr); + mlir::Value isPresent = + genActualIsPresentTest(builder, loc, optionalArg); + operands.emplace_back(optionalArg, isPresent); + }; + auto prepareOtherArg = [&](const Fortran::lower::SomeExpr &expr) { + operands.emplace_back(genval(expr), llvm::None); + }; + Fortran::lower::prepareCustomIntrinsicArgument( + procRef, intrinsic, resultType, prepareOptionalArg, prepareOtherArg, + converter); + + auto getArgument = [&](std::size_t i) -> ExtValue { + if (fir::conformsWithPassByRef( + fir::getBase(operands[i].first).getType())) + return genLoad(operands[i].first); + return operands[i].first; + }; + auto isPresent = [&](std::size_t i) -> llvm::Optional { + return operands[i].second; + }; + return Fortran::lower::lowerCustomIntrinsic( + builder, loc, name, resultType, isPresent, getArgument, + operands.size(), stmtCtx); + } const Fortran::lower::IntrinsicArgumentLoweringRules *argLowering = Fortran::lower::getIntrinsicArgumentLowering(name); diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp index 531cab96675a..adb4a324e824 100644 --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -228,6 +228,168 @@ genDotProd(FN func, mlir::Type resultType, fir::FirOpBuilder &builder, return func(builder, loc, vectorA, vectorB, resultBox); } +/// Process calls to Maxval, Minval, Product, Sum intrinsic functions +template +static fir::ExtendedValue +genExtremumVal(FN func, FD funcDim, FC funcChar, mlir::Type resultType, + fir::FirOpBuilder &builder, mlir::Location loc, + Fortran::lower::StatementContext *stmtCtx, + llvm::StringRef errMsg, + llvm::ArrayRef args) { + + assert(args.size() == 3); + + // Handle required array argument + fir::BoxValue arryTmp = builder.createBox(loc, args[0]); + mlir::Value array = fir::getBase(arryTmp); + int rank = arryTmp.rank(); + assert(rank >= 1); + bool hasCharacterResult = arryTmp.isCharacter(); + + // Handle optional mask argument + auto mask = isAbsent(args[2]) + ? builder.create( + loc, fir::BoxType::get(builder.getI1Type())) + : builder.createBox(loc, args[2]); + + bool absentDim = isAbsent(args[1]); + + // For Maxval/MinVal, we call the type specific versions of + // Maxval/Minval because the result is scalar in the case below. + if (!hasCharacterResult && (absentDim || rank == 1)) + return func(builder, loc, array, mask); + + if (hasCharacterResult && (absentDim || rank == 1)) { + // Create mutable fir.box to be passed to the runtime for the result. + fir::MutableBoxValue resultMutableBox = + fir::factory::createTempMutableBox(builder, loc, resultType); + mlir::Value resultIrBox = + fir::factory::getMutableIRBox(builder, loc, resultMutableBox); + + funcChar(builder, loc, resultIrBox, array, mask); + + // Handle cleanup of allocatable result descriptor and return + fir::ExtendedValue res = + fir::factory::genMutableBoxRead(builder, loc, resultMutableBox); + return res.match( + [&](const fir::CharBoxValue &box) -> fir::ExtendedValue { + // Add cleanup code + assert(stmtCtx); + fir::FirOpBuilder *bldr = &builder; + mlir::Value temp = box.getAddr(); + stmtCtx->attachCleanup( + [=]() { bldr->create(loc, temp); }); + return box; + }, + [&](const auto &) -> fir::ExtendedValue { + fir::emitFatalError(loc, errMsg); + }); + } + + // Handle Min/Maxval cases that have an array result. + return genFuncDim(funcDim, resultType, builder, loc, stmtCtx, errMsg, array, + args[1], mask, rank); +} + +/// Process calls to Minloc, Maxloc intrinsic functions +template +static fir::ExtendedValue genExtremumloc( + FN func, FD funcDim, mlir::Type resultType, fir::FirOpBuilder &builder, + mlir::Location loc, Fortran::lower::StatementContext *stmtCtx, + llvm::StringRef errMsg, llvm::ArrayRef args) { + + assert(args.size() == 5); + + // Handle required array argument + mlir::Value array = builder.createBox(loc, args[0]); + unsigned rank = fir::BoxValue(array).rank(); + assert(rank >= 1); + + // Handle optional mask argument + auto mask = isAbsent(args[2]) + ? builder.create( + loc, fir::BoxType::get(builder.getI1Type())) + : builder.createBox(loc, args[2]); + + // Handle optional kind argument + auto kind = isAbsent(args[3]) ? builder.createIntegerConstant( + loc, builder.getIndexType(), + builder.getKindMap().defaultIntegerKind()) + : fir::getBase(args[3]); + + // Handle optional back argument + auto back = isAbsent(args[4]) ? builder.createBool(loc, false) + : fir::getBase(args[4]); + + bool absentDim = isAbsent(args[1]); + + if (!absentDim && rank == 1) { + // If dim argument is present and the array is rank 1, then the result is + // a scalar (since the the result is rank-1 or 0). + // Therefore, we use a scalar result descriptor with Min/MaxlocDim(). + mlir::Value dim = fir::getBase(args[1]); + // Create mutable fir.box to be passed to the runtime for the result. + fir::MutableBoxValue resultMutableBox = + fir::factory::createTempMutableBox(builder, loc, resultType); + mlir::Value resultIrBox = + fir::factory::getMutableIRBox(builder, loc, resultMutableBox); + + funcDim(builder, loc, resultIrBox, array, dim, mask, kind, back); + + // Handle cleanup of allocatable result descriptor and return + fir::ExtendedValue res = + fir::factory::genMutableBoxRead(builder, loc, resultMutableBox); + return res.match( + [&](const mlir::Value &tempAddr) -> fir::ExtendedValue { + // Add cleanup code + assert(stmtCtx); + fir::FirOpBuilder *bldr = &builder; + stmtCtx->attachCleanup( + [=]() { bldr->create(loc, tempAddr); }); + return builder.create(loc, resultType, tempAddr); + }, + [&](const auto &) -> fir::ExtendedValue { + fir::emitFatalError(loc, errMsg); + }); + } + + // Note: The Min/Maxloc/val cases below have an array result. + + // Create mutable fir.box to be passed to the runtime for the result. + mlir::Type resultArrayType = + builder.getVarLenSeqTy(resultType, absentDim ? 1 : rank - 1); + fir::MutableBoxValue resultMutableBox = + fir::factory::createTempMutableBox(builder, loc, resultArrayType); + mlir::Value resultIrBox = + fir::factory::getMutableIRBox(builder, loc, resultMutableBox); + + if (absentDim) { + // Handle min/maxloc/val case where there is no dim argument + // (calls Min/Maxloc()/MinMaxval() runtime routine) + func(builder, loc, resultIrBox, array, mask, kind, back); + } else { + // else handle min/maxloc case with dim argument (calls + // Min/Max/loc/val/Dim() runtime routine). + mlir::Value dim = fir::getBase(args[1]); + funcDim(builder, loc, resultIrBox, array, dim, mask, kind, back); + } + + return fir::factory::genMutableBoxRead(builder, loc, resultMutableBox) + .match( + [&](const fir::ArrayBoxValue &box) -> fir::ExtendedValue { + // Add cleanup code + assert(stmtCtx); + fir::FirOpBuilder *bldr = &builder; + mlir::Value temp = box.getAddr(); + stmtCtx->attachCleanup( + [=]() { bldr->create(loc, temp); }); + return box; + }, + [&](const auto &) -> fir::ExtendedValue { + fir::emitFatalError(loc, errMsg); + }); +} + // TODO error handling -> return a code or directly emit messages ? struct IntrinsicLibrary { @@ -289,6 +451,10 @@ struct IntrinsicLibrary { fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLen(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLenTrim(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genMaxloc(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genMaxval(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genMinloc(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genMinval(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genSize(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genSum(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genUbound(mlir::Type, llvm::ArrayRef); @@ -419,6 +585,36 @@ static constexpr IntrinsicHandler handlers[]{ {"llt", &I::genCharacterCompare}, {"min", &I::genExtremum}, {"null", &I::genNull, {{{"mold", asInquired}}}, /*isElemental=*/false}, + {"max", &I::genExtremum}, + {"maxloc", + &I::genMaxloc, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}, + {"kind", asValue}, + {"back", asValue, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"maxval", + &I::genMaxval, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"min", &I::genExtremum}, + {"minloc", + &I::genMinloc, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}, + {"kind", asValue}, + {"back", asValue, handleDynamicOptional}}}, + /*isElemental=*/false}, + {"minval", + &I::genMinval, + {{{"array", asBox}, + {"dim", asValue}, + {"mask", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, {"sum", &I::genSum, {{{"array", asBox}, @@ -1474,6 +1670,42 @@ static mlir::Value createExtremumCompare(mlir::Location loc, return result; } +// MAXLOC +fir::ExtendedValue +IntrinsicLibrary::genMaxloc(mlir::Type resultType, + llvm::ArrayRef args) { + return genExtremumloc(fir::runtime::genMaxloc, fir::runtime::genMaxlocDim, + resultType, builder, loc, stmtCtx, + "unexpected result for Maxloc", args); +} + +// MAXVAL +fir::ExtendedValue +IntrinsicLibrary::genMaxval(mlir::Type resultType, + llvm::ArrayRef args) { + return genExtremumVal(fir::runtime::genMaxval, fir::runtime::genMaxvalDim, + fir::runtime::genMaxvalChar, resultType, builder, loc, + stmtCtx, "unexpected result for Maxval", args); +} + +// MINLOC +fir::ExtendedValue +IntrinsicLibrary::genMinloc(mlir::Type resultType, + llvm::ArrayRef args) { + return genExtremumloc(fir::runtime::genMinloc, fir::runtime::genMinlocDim, + resultType, builder, loc, stmtCtx, + "unexpected result for Minloc", args); +} + +// MINVAL +fir::ExtendedValue +IntrinsicLibrary::genMinval(mlir::Type resultType, + llvm::ArrayRef args) { + return genExtremumVal(fir::runtime::genMinval, fir::runtime::genMinvalDim, + fir::runtime::genMinvalChar, resultType, builder, loc, + stmtCtx, "unexpected result for Minval", args); +} + // MIN and MAX template mlir::Value IntrinsicLibrary::genExtremum(mlir::Type, diff --git a/flang/lib/Optimizer/Builder/MutableBox.cpp b/flang/lib/Optimizer/Builder/MutableBox.cpp index 66bdb99cf9cc..0d9fe18089ef 100644 --- a/flang/lib/Optimizer/Builder/MutableBox.cpp +++ b/flang/lib/Optimizer/Builder/MutableBox.cpp @@ -364,16 +364,16 @@ mlir::Value fir::factory::createUnallocatedBox(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type boxType, mlir::ValueRange nonDeferredParams) { - auto heapType = boxType.dyn_cast().getEleTy(); - auto type = fir::dyn_cast_ptrEleTy(heapType); - auto eleTy = type; - if (auto seqType = eleTy.dyn_cast()) - eleTy = seqType.getEleTy(); + auto baseAddrType = boxType.dyn_cast().getEleTy(); + if (!fir::isa_ref_type(baseAddrType)) + baseAddrType = builder.getRefType(baseAddrType); + auto type = fir::unwrapRefType(baseAddrType); + auto eleTy = fir::unwrapSequenceType(type); if (auto recTy = eleTy.dyn_cast()) if (recTy.getNumLenParams() > 0) TODO(loc, "creating unallocated fir.box of derived type with length " "parameters"); - auto nullAddr = builder.createNullConstant(loc, heapType); + auto nullAddr = builder.createNullConstant(loc, baseAddrType); mlir::Value shape; if (auto seqTy = type.dyn_cast()) { auto zero = builder.createIntegerConstant(loc, builder.getIndexType(), 0); diff --git a/flang/test/Lower/Intrinsics/max.f90 b/flang/test/Lower/Intrinsics/max.f90 new file mode 100644 index 000000000000..3cfea3d3e70a --- /dev/null +++ b/flang/test/Lower/Intrinsics/max.f90 @@ -0,0 +1,139 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +module max_test + contains + ! CHECK-LABEL: func @_QMmax_testPdynamic_optional( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "b"}, + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.box> {fir.bindc_name = "c", fir.optional}) { + subroutine dynamic_optional(a, b, c) + integer :: a(:), b(:) + integer, optional :: c(:) + ! CHECK: %[[VAL_10:.*]] = fir.array_load %[[VAL_0]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_11:.*]] = fir.array_load %[[VAL_1]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.box>) -> i1 + ! CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_12]], %[[VAL_2]], %{{.*}} : !fir.box> + ! CHECK: %[[VAL_18:.*]] = fir.array_load %[[VAL_17]] {fir.optional} : (!fir.box>) -> !fir.array + ! CHECK: fir.do_loop %[[VAL_26:.*]] = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%[[VAL_27:.*]] = %{{.*}}) -> (!fir.array) { + ! CHECK: %[[VAL_28:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_26]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_29:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_26]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_30:.*]] = arith.cmpi sgt, %[[VAL_28]], %[[VAL_29]] : i32 + ! CHECK: %[[VAL_31:.*]] = arith.select %[[VAL_30]], %[[VAL_28]], %[[VAL_29]] : i32 + ! CHECK: %[[VAL_32:.*]] = fir.if %[[VAL_12]] -> (i32) { + ! CHECK: %[[VAL_33:.*]] = fir.array_fetch %[[VAL_18]], %[[VAL_26]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_34:.*]] = arith.cmpi sgt, %[[VAL_31]], %[[VAL_33]] : i32 + ! CHECK: %[[VAL_35:.*]] = arith.select %[[VAL_34]], %[[VAL_31]], %[[VAL_33]] : i32 + ! CHECK: fir.result %[[VAL_35]] : i32 + ! CHECK: } else { + ! CHECK: fir.result %[[VAL_31]] : i32 + ! CHECK: } + ! CHECK: %[[VAL_36:.*]] = fir.array_update %[[VAL_27]], %[[VAL_32]], %[[VAL_26]] : (!fir.array, i32, index) -> !fir.array + ! CHECK: fir.result %[[VAL_36]] : !fir.array + ! CHECK: } + print *, max(a, b, c) + end subroutine + + ! CHECK-LABEL: func @_QMmax_testPdynamic_optional_array_expr_scalar_optional( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "b"}, + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "c", fir.optional}) { + subroutine dynamic_optional_array_expr_scalar_optional(a, b, c) + integer :: a(:), b(:) + integer, optional :: c + print *, max(a, b, c) + ! CHECK: %[[VAL_10:.*]] = fir.array_load %[[VAL_0]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_11:.*]] = fir.array_load %[[VAL_1]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref) -> i1 + ! CHECK: fir.do_loop %[[VAL_20:.*]] = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%[[VAL_21:.*]] = %{{.*}}) -> (!fir.array) { + ! CHECK: %[[VAL_22:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_20]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_23:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_20]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_24:.*]] = arith.cmpi sgt, %[[VAL_22]], %[[VAL_23]] : i32 + ! CHECK: %[[VAL_25:.*]] = arith.select %[[VAL_24]], %[[VAL_22]], %[[VAL_23]] : i32 + ! CHECK: %[[VAL_26:.*]] = fir.if %[[VAL_12]] -> (i32) { + ! CHECK: %[[VAL_27:.*]] = fir.load %[[VAL_2]] : !fir.ref + ! CHECK: %[[VAL_28:.*]] = arith.cmpi sgt, %[[VAL_25]], %[[VAL_27]] : i32 + ! CHECK: %[[VAL_29:.*]] = arith.select %[[VAL_28]], %[[VAL_25]], %[[VAL_27]] : i32 + ! CHECK: fir.result %[[VAL_29]] : i32 + ! CHECK: } else { + ! CHECK: fir.result %[[VAL_25]] : i32 + ! CHECK: } + ! CHECK: %[[VAL_30:.*]] = fir.array_update %[[VAL_21]], %[[VAL_26]], %[[VAL_20]] : (!fir.array, i32, index) -> !fir.array + ! CHECK: fir.result %[[VAL_30]] : !fir.array + ! CHECK: } + end subroutine + + ! CHECK-LABEL: func @_QMmax_testPdynamic_optional_scalar( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "a"}, + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "b"}, + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "c", fir.optional}) { + subroutine dynamic_optional_scalar(a, b, c) + integer :: a, b + integer, optional :: c + print *, max(a, b, c) + ! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_0]] : !fir.ref + ! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_1]] : !fir.ref + ! CHECK: %[[VAL_10:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref) -> i1 + ! CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_9]] : i32 + ! CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_8]], %[[VAL_9]] : i32 + ! CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_10]] -> (i32) { + ! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_2]] : !fir.ref + ! CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_14]] : i32 + ! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_12]], %[[VAL_14]] : i32 + ! CHECK: fir.result %[[VAL_16]] : i32 + ! CHECK: } else { + ! CHECK: fir.result %[[VAL_12]] : i32 + ! CHECK: } + ! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[VAL_13]]) : (!fir.ref, i32) -> i1 + end subroutine + + ! CHECK-LABEL: func @_QMmax_testPdynamic_optional_weird( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "a"}, + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "b"}, + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "c", fir.optional}, + ! CHECK-SAME: %[[VAL_3:.*]]: !fir.ref {fir.bindc_name = "d"}, + ! CHECK-SAME: %[[VAL_4:.*]]: !fir.ref {fir.bindc_name = "e", fir.optional}) { + subroutine dynamic_optional_weird(a, b, c, d, e) + integer :: a, b, d + integer, optional :: c, e + ! a3, a4, a6, a8 statically missing. a5, a9 dynamically optional. + print *, max(a1=a, a2=b, a5=c, a7=d, a9 = e) + ! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_0]] : !fir.ref + ! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_1]] : !fir.ref + ! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref) -> i1 + ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_3]] : !fir.ref + ! CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_4]] : (!fir.ref) -> i1 + ! CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_11]] : i32 + ! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_10]], %[[VAL_11]] : i32 + ! CHECK: %[[VAL_17:.*]] = fir.if %[[VAL_12]] -> (i32) { + ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_2]] : !fir.ref + ! CHECK: %[[VAL_19:.*]] = arith.cmpi sgt, %[[VAL_16]], %[[VAL_18]] : i32 + ! CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_19]], %[[VAL_16]], %[[VAL_18]] : i32 + ! CHECK: fir.result %[[VAL_20]] : i32 + ! CHECK: } else { + ! CHECK: fir.result %[[VAL_16]] : i32 + ! CHECK: } + ! CHECK: %[[VAL_21:.*]] = arith.cmpi sgt, %[[VAL_17]], %[[VAL_13]] : i32 + ! CHECK: %[[VAL_23:.*]] = arith.select %[[VAL_21]], %[[VAL_17]], %[[VAL_13]] : i32 + ! CHECK: %[[VAL_24:.*]] = fir.if %[[VAL_14]] -> (i32) { + ! CHECK: %[[VAL_25:.*]] = fir.load %[[VAL_4]] : !fir.ref + ! CHECK: %[[VAL_26:.*]] = arith.cmpi sgt, %[[VAL_23]], %[[VAL_25]] : i32 + ! CHECK: %[[VAL_27:.*]] = arith.select %[[VAL_26]], %[[VAL_23]], %[[VAL_25]] : i32 + ! CHECK: fir.result %[[VAL_27]] : i32 + ! CHECK: } else { + ! CHECK: fir.result %[[VAL_23]] : i32 + ! CHECK: } + ! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[VAL_24]]) : (!fir.ref, i32) -> i1 + end subroutine + end module + + use :: max_test + integer :: a(4) = [1,12,23, 34] + integer :: b(4) = [31,22,13, 4] + integer :: c(4) = [21,32,3, 14] + call dynamic_optional(a, b) + call dynamic_optional(a, b, c) + call dynamic_optional_array_expr_scalar_optional(a, b) + call dynamic_optional_array_expr_scalar_optional(a, b, c(2)) + call dynamic_optional_scalar(a(2), b(2)) + call dynamic_optional_scalar(a(2), b(2), c(2)) + end diff --git a/flang/test/Lower/Intrinsics/maxloc.f90 b/flang/test/Lower/Intrinsics/maxloc.f90 new file mode 100644 index 000000000000..9fe28f2d86b3 --- /dev/null +++ b/flang/test/Lower/Intrinsics/maxloc.f90 @@ -0,0 +1,89 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: func @_QPmaxloc_test( +! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}, %[[arg1:.*]]: !fir.box>{{.*}}) { +subroutine maxloc_test(arr,res) + integer :: arr(:) + integer :: res(:) + ! CHECK-DAG: %[[c4:.*]] = arith.constant 4 : index + ! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box>> + ! CHECK-DAG: %[[a1:.*]] = fir.absent !fir.box + ! CHECK-DAG: %[[a6:.*]] = fir.convert %[[a0]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK-DAG: %[[a7:.*]] = fir.convert %[[arg0]] : (!fir.box>) -> !fir.box + ! CHECK-DAG: %[[a8:.*]] = fir.convert %[[c4]] : (index) -> i32 + ! CHECK-DAG: %[[a10:.*]] = fir.convert %[[a1]] : (!fir.box) -> !fir.box + res = maxloc(arr) + ! CHECK: %{{.*}} = fir.call @_FortranAMaxloc(%[[a6]], %[[a7]], %[[a8]], %{{.*}}, %{{.*}}, %[[a10]], %false) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box, i1) -> none + ! CHECK-DAG: %[[a12:.*]] = fir.load %[[a0]] : !fir.ref>>> + ! CHECK-DAG: %[[a14:.*]] = fir.box_addr %[[a12]] : (!fir.box>>) -> !fir.heap> + ! CHECK-DAG: fir.freemem %[[a14]] + end subroutine + + ! CHECK-LABEL: func @_QPmaxloc_test2( + ! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}, %[[arg1:.*]]: !fir.box>{{.*}}, %[[arg2:.*]]: !fir.ref{{.*}}) { + subroutine maxloc_test2(arr,res,d) + integer :: arr(:) + integer :: res(:) + integer :: d + ! CHECK-DAG: %[[c4:.*]] = arith.constant 4 : index + ! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box> + ! CHECK-DAG: %[[a1:.*]] = fir.load %arg2 : !fir.ref + ! CHECK-DAG: %[[a2:.*]] = fir.absent !fir.box + ! CHECK-DAG: %[[a6:.*]] = fir.convert %[[a0]] : (!fir.ref>>) -> !fir.ref> + ! CHECK-DAG: %[[a7:.*]] = fir.convert %arg0 : (!fir.box>) -> !fir.box + ! CHECK-DAG: %[[a8:.*]] = fir.convert %[[c4]] : (index) -> i32 + ! CHECK-DAG: %[[a10:.*]] = fir.convert %[[a2]] : (!fir.box) -> !fir.box + res = maxloc(arr, dim=d) + ! CHECK: %{{.*}} = fir.call @_FortranAMaxlocDim(%[[a6]], %[[a7]], %[[a8]], %[[a1]], %{{.*}}, %{{.*}}, %[[a10]], %false) : (!fir.ref>, !fir.box, i32, i32, !fir.ref, i32, !fir.box, i1) -> none + ! CHECK: %[[a12:.*]] = fir.load %0 : !fir.ref>> + ! CHECK: %[[a13:.*]] = fir.box_addr %[[a12]] : (!fir.box>) -> !fir.heap + ! CHECK: fir.freemem %[[a13]] + end subroutine + + ! CHECK-LABEL: func @_QPtest_maxloc_optional_scalar_mask( + ! CHECK-SAME: %[[VAL_0:[^:]+]]: !fir.ref> + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> + subroutine test_maxloc_optional_scalar_mask(mask, back, array) + integer :: array(:) + logical, optional :: mask + logical, optional :: back + print *, maxloc(array, mask=mask, back=back) + ! CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_0]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_10:.*]] = fir.embox %[[VAL_0]] : (!fir.ref>) -> !fir.box> + ! CHECK: %[[VAL_11:.*]] = fir.absent !fir.box> + ! CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_9]], %[[VAL_10]], %[[VAL_11]] : !fir.box> + ! CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.logical<4>) { + ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_1]] : !fir.ref> + ! CHECK: fir.result %[[VAL_15]] : !fir.logical<4> + ! CHECK: } else { + ! CHECK: %[[VAL_16:.*]] = arith.constant false + ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> + ! CHECK: fir.result %[[VAL_17]] : !fir.logical<4> + ! CHECK: } + ! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_12]] : (!fir.box>) -> !fir.box + ! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_14]] : (!fir.logical<4>) -> i1 + ! CHECK: fir.call @_FortranAMaxloc(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_29]], %[[VAL_30]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box, i1) -> none + end subroutine + + ! CHECK-LABEL: func @_QPtest_maxloc_optional_array_mask( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> + subroutine test_maxloc_optional_array_mask(mask, back, array) + integer :: array(:) + logical, optional :: mask(:) + logical, optional :: back + print *, maxloc(array, mask=mask, back=back) + ! CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_10:.*]] = fir.if %[[VAL_9]] -> (!fir.logical<4>) { + ! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_1]] : !fir.ref> + ! CHECK: fir.result %[[VAL_11]] : !fir.logical<4> + ! CHECK: } else { + ! CHECK: %[[VAL_12:.*]] = arith.constant false + ! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i1) -> !fir.logical<4> + ! CHECK: fir.result %[[VAL_13]] : !fir.logical<4> + ! CHECK: } + ! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box + ! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_10]] : (!fir.logical<4>) -> i1 + ! CHECK: fir.call @_FortranAMaxloc(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_25]], %[[VAL_26]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box, i1) -> none + end subroutine diff --git a/flang/test/Lower/Intrinsics/maxval.f90 b/flang/test/Lower/Intrinsics/maxval.f90 new file mode 100644 index 000000000000..55ac7aa8ee93 --- /dev/null +++ b/flang/test/Lower/Intrinsics/maxval.f90 @@ -0,0 +1,69 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: func @_QPmaxval_test( +! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}) -> i32 +integer function maxval_test(a) +integer :: a(:) +! CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index +! CHECK-DAG: %[[a2:.*]] = fir.absent !fir.box +! CHECK-DAG: %[[a4:.*]] = fir.convert %[[arg0]] : (!fir.box>) -> !fir.box +! CHECK: %[[a6:.*]] = fir.convert %[[c0]] : (index) -> i32 +! CHECK: %[[a7:.*]] = fir.convert %[[a2]] : (!fir.box) -> !fir.box +maxval_test = maxval(a) +! CHECK: %{{.*}} = fir.call @_FortranAMaxvalInteger4(%[[a4]], %{{.*}}, %{{.*}}, %[[a6]], %[[a7]]) : (!fir.box, !fir.ref, i32, i32, !fir.box) -> i32 +end function + +! CHECK-LABEL: func @_QPmaxval_test2( +! CHECK-SAME: %[[arg0:.*]]: !fir.ref>, %[[arg1:.*]]: index, %[[arg2:.*]]: !fir.box>> {fir.bindc_name = "a"}) -> !fir.boxchar<1> { +character function maxval_test2(a) +character :: a(:) +! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box>> +! CHECK: %[[a1:.*]] = fir.absent !fir.box +! CHECK-DAG: %[[a5:.*]] = fir.convert %[[a0]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[a6:.*]] = fir.convert %[[arg2]] : (!fir.box>>) -> !fir.box +! CHECK-DAG: %[[a8:.*]] = fir.convert %[[a1]] : (!fir.box) -> !fir.box +maxval_test2 = maxval(a) +! CHECK: %{{.*}} = fir.call @_FortranAMaxvalCharacter(%[[a5]], %[[a6]], %{{.*}}, %{{.*}}, %[[a8]]) : (!fir.ref>, !fir.box, !fir.ref, i32, !fir.box) -> none +end function + +! CHECK-LABEL: func @_QPmaxval_test3( +! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}, %[[arg1:.*]]: !fir.box> +subroutine maxval_test3(a,r) +integer :: a(:,:) +integer :: r(:) +! CHECK-DAG: %[[c2_i32:.*]] = arith.constant 2 : i32 +! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box>> +! CHECK: %[[a1:.*]] = fir.absent !fir.box +! CHECK-DAG: %[[a6:.*]] = fir.convert %[[a0]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[a7:.*]] = fir.convert %[[arg0]] : (!fir.box>) -> !fir.box +! CHECK-DAG: %[[a9:.*]] = fir.convert %[[a1]] : (!fir.box) -> !fir.box +r = maxval(a,dim=2) +! CHECK: %{{.*}} = fir.call @_FortranAMaxvalDim(%[[a6]], %[[a7]], %[[c2_i32]], %{{.*}}, %{{.*}}, %[[a9]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box) -> none +! CHECK: %[[a11:.*]] = fir.load %[[a0]] : !fir.ref>>> +! CHECK-DAG: %[[a13:.*]] = fir.box_addr %[[a11]] : (!fir.box>>) -> !fir.heap> +! CHECK-DAG: fir.freemem %[[a13]] +end subroutine + +! CHECK-LABEL: func @_QPtest_maxval_optional_scalar_mask( +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> +subroutine test_maxval_optional_scalar_mask(mask, array) +integer :: array(:) +logical, optional :: mask +print *, maxval(array, mask) +! CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 +! CHECK: %[[VAL_8:.*]] = fir.embox %[[VAL_1]] : (!fir.ref>) -> !fir.box> +! CHECK: %[[VAL_9:.*]] = fir.absent !fir.box> +! CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_7]], %[[VAL_8]], %[[VAL_9]] : !fir.box> +! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_10]] : (!fir.box>) -> !fir.box +! CHECK: fir.call @_FortranAMaxvalInteger4(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_17]]) : (!fir.box, !fir.ref, i32, i32, !fir.box) -> i32 +end subroutine + +! CHECK-LABEL: func @_QPtest_maxval_optional_array_mask( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> +subroutine test_maxval_optional_array_mask(mask, array) +integer :: array(:) +logical, optional :: mask(:) +print *, maxval(array, mask) +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +! CHECK: fir.call @_FortranAMaxvalInteger4(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_13]]) : (!fir.box, !fir.ref, i32, i32, !fir.box) -> i32 +end subroutine diff --git a/flang/test/Lower/Intrinsics/minloc.f90 b/flang/test/Lower/Intrinsics/minloc.f90 new file mode 100644 index 000000000000..b16edcea4762 --- /dev/null +++ b/flang/test/Lower/Intrinsics/minloc.f90 @@ -0,0 +1,89 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: func @_QPminloc_test( +! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}, %[[arg1:.*]]: !fir.box> +subroutine minloc_test(arr,res) + integer :: arr(:) + integer :: res(:) + ! CHECK-DAG: %[[c4:.*]] = arith.constant 4 : index + ! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box>> + ! CHECK-DAG: %[[a1:.*]] = fir.absent !fir.box + ! CHECK-DAG: %[[a6:.*]] = fir.convert %[[a0]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK-DAG: %[[a7:.*]] = fir.convert %[[arg0]] : (!fir.box>) -> !fir.box + ! CHECK-DAG: %[[a8:.*]] = fir.convert %[[c4]] : (index) -> i32 + ! CHECK-DAG: %[[a10:.*]] = fir.convert %[[a1]] : (!fir.box) -> !fir.box + res = minloc(arr) + ! CHECK: %{{.*}} = fir.call @_FortranAMinloc(%[[a6]], %[[a7]], %[[a8]], %{{.*}}, %{{.*}}, %[[a10]], %false) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box, i1) -> none + ! CHECK-DAG: %[[a12:.*]] = fir.load %[[a0]] : !fir.ref>>> + ! CHECK-DAG: %[[a14:.*]] = fir.box_addr %[[a12]] : (!fir.box>>) -> !fir.heap> + ! CHECK-DAG: fir.freemem %[[a14]] + end subroutine + + ! CHECK-LABEL: func @_QPminloc_test2( + ! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}, %[[arg1:.*]]: !fir.box>{{.*}}, %[[arg2:.*]]: !fir.ref + subroutine minloc_test2(arr,res,d) + integer :: arr(:) + integer :: res(:) + integer :: d + ! CHECK-DAG: %[[c4:.*]] = arith.constant 4 : index + ! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box> + ! CHECK-DAG: %[[a1:.*]] = fir.load %arg2 : !fir.ref + ! CHECK-DAG: %[[a2:.*]] = fir.absent !fir.box + ! CHECK-DAG: %[[a6:.*]] = fir.convert %[[a0]] : (!fir.ref>>) -> !fir.ref> + ! CHECK-DAG: %[[a7:.*]] = fir.convert %arg0 : (!fir.box>) -> !fir.box + ! CHECK-DAG: %[[a8:.*]] = fir.convert %[[c4]] : (index) -> i32 + ! CHECK-DAG: %[[a10:.*]] = fir.convert %[[a2]] : (!fir.box) -> !fir.box + res = minloc(arr, dim=d) + ! CHECK: %{{.*}} = fir.call @_FortranAMinlocDim(%[[a6]], %[[a7]], %[[a8]], %[[a1]], %{{.*}}, %{{.*}}, %[[a10]], %false) : (!fir.ref>, !fir.box, i32, i32, !fir.ref, i32, !fir.box, i1) -> none + ! CHECK: %[[a12:.*]] = fir.load %0 : !fir.ref>> + ! CHECK: %[[a13:.*]] = fir.box_addr %[[a12]] : (!fir.box>) -> !fir.heap + ! CHECK: fir.freemem %[[a13]] + end subroutine + + ! CHECK-LABEL: func @_QPtest_minloc_optional_scalar_mask( + ! CHECK-SAME: %[[VAL_0:[^:]+]]: !fir.ref> + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> + subroutine test_minloc_optional_scalar_mask(mask, back, array) + integer :: array(:) + logical, optional :: mask + logical, optional :: back + print *, minloc(array, mask=mask, back=back) + ! CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_0]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_10:.*]] = fir.embox %[[VAL_0]] : (!fir.ref>) -> !fir.box> + ! CHECK: %[[VAL_11:.*]] = fir.absent !fir.box> + ! CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_9]], %[[VAL_10]], %[[VAL_11]] : !fir.box> + ! CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.logical<4>) { + ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_1]] : !fir.ref> + ! CHECK: fir.result %[[VAL_15]] : !fir.logical<4> + ! CHECK: } else { + ! CHECK: %[[VAL_16:.*]] = arith.constant false + ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> + ! CHECK: fir.result %[[VAL_17]] : !fir.logical<4> + ! CHECK: } + ! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_12]] : (!fir.box>) -> !fir.box + ! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_14]] : (!fir.logical<4>) -> i1 + ! CHECK: fir.call @_FortranAMinloc(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_29]], %[[VAL_30]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box, i1) -> none + end subroutine + + ! CHECK-LABEL: func @_QPtest_minloc_optional_array_mask( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> + subroutine test_minloc_optional_array_mask(mask, back, array) + integer :: array(:) + logical, optional :: mask(:) + logical, optional :: back + print *, minloc(array, mask=mask, back=back) + ! CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_10:.*]] = fir.if %[[VAL_9]] -> (!fir.logical<4>) { + ! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_1]] : !fir.ref> + ! CHECK: fir.result %[[VAL_11]] : !fir.logical<4> + ! CHECK: } else { + ! CHECK: %[[VAL_12:.*]] = arith.constant false + ! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i1) -> !fir.logical<4> + ! CHECK: fir.result %[[VAL_13]] : !fir.logical<4> + ! CHECK: } + ! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box + ! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_10]] : (!fir.logical<4>) -> i1 + ! CHECK: fir.call @_FortranAMinloc(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_25]], %[[VAL_26]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box, i1) -> none + end subroutine diff --git a/flang/test/Lower/Intrinsics/minval.f90 b/flang/test/Lower/Intrinsics/minval.f90 new file mode 100644 index 000000000000..ecc11900d052 --- /dev/null +++ b/flang/test/Lower/Intrinsics/minval.f90 @@ -0,0 +1,69 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: func @_QPminval_test( +! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}) -> i32 +integer function minval_test(a) +integer :: a(:) +! CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index +! CHECK-DAG: %[[a2:.*]] = fir.absent !fir.box +! CHECK-DAG: %[[a4:.*]] = fir.convert %[[arg0]] : (!fir.box>) -> !fir.box +! CHECK: %[[a6:.*]] = fir.convert %[[c0]] : (index) -> i32 +! CHECK: %[[a7:.*]] = fir.convert %[[a2]] : (!fir.box) -> !fir.box +minval_test = minval(a) +! CHECK: %{{.*}} = fir.call @_FortranAMinvalInteger4(%[[a4]], %{{.*}}, %{{.*}}, %[[a6]], %[[a7]]) : (!fir.box, !fir.ref, i32, i32, !fir.box) -> i32 +end function + +! CHECK-LABEL: func @_QPminval_test2( +! CHECK-SAME: %[[arg0:.*]]: !fir.ref>{{.*}}, %[[arg1:.*]]: index{{.*}}, %[[arg2:.*]]: !fir.box>>{{.*}}) -> !fir.boxchar<1> +character function minval_test2(a) +character :: a(:) +! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box>> +! CHECK: %[[a1:.*]] = fir.absent !fir.box +! CHECK-DAG: %[[a5:.*]] = fir.convert %[[a0]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[a6:.*]] = fir.convert %[[arg2]] : (!fir.box>>) -> !fir.box +! CHECK-DAG: %[[a8:.*]] = fir.convert %[[a1]] : (!fir.box) -> !fir.box +minval_test2 = minval(a) +! CHECK: %{{.*}} = fir.call @_FortranAMinvalCharacter(%[[a5]], %[[a6]], %{{.*}}, %{{.*}}, %[[a8]]) : (!fir.ref>, !fir.box, !fir.ref, i32, !fir.box) -> none +end function + +! CHECK-LABEL: func @_QPminval_test3( +! CHECK-SAME: %[[arg0:.*]]: !fir.box>{{.*}}, %[[arg1:.*]]: !fir.box>{{.*}}) +subroutine minval_test3(a,r) +integer :: a(:,:) +integer :: r(:) +! CHECK-DAG: %[[c2_i32:.*]] = arith.constant 2 : i32 +! CHECK-DAG: %[[a0:.*]] = fir.alloca !fir.box>> +! CHECK: %[[a1:.*]] = fir.absent !fir.box +! CHECK-DAG: %[[a6:.*]] = fir.convert %[[a0]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[a7:.*]] = fir.convert %[[arg0]] : (!fir.box>) -> !fir.box +! CHECK-DAG: %[[a9:.*]] = fir.convert %[[a1]] : (!fir.box) -> !fir.box +r = minval(a,dim=2) +! CHECK: %{{.*}} = fir.call @_FortranAMinvalDim(%[[a6]], %[[a7]], %[[c2_i32]], %{{.*}}, %{{.*}}, %[[a9]]) : (!fir.ref>, !fir.box, i32, !fir.ref, i32, !fir.box) -> none +! CHECK: %[[a11:.*]] = fir.load %[[a0]] : !fir.ref>>> +! CHECK-DAG: %[[a13:.*]] = fir.box_addr %[[a11]] : (!fir.box>>) -> !fir.heap> +! CHECK-DAG: fir.freemem %[[a13]] +end subroutine + +! CHECK-LABEL: func @_QPtest_minval_optional_scalar_mask( +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> +subroutine test_minval_optional_scalar_mask(mask, array) +integer :: array(:) +logical, optional :: mask +print *, minval(array, mask) +! CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 +! CHECK: %[[VAL_8:.*]] = fir.embox %[[VAL_1]] : (!fir.ref>) -> !fir.box> +! CHECK: %[[VAL_9:.*]] = fir.absent !fir.box> +! CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_7]], %[[VAL_8]], %[[VAL_9]] : !fir.box> +! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_10]] : (!fir.box>) -> !fir.box +! CHECK: fir.call @_FortranAMinvalInteger4(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_17]]) : (!fir.box, !fir.ref, i32, i32, !fir.box) -> i32 +end subroutine + +! CHECK-LABEL: func @_QPtest_minval_optional_array_mask( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> +subroutine test_minval_optional_array_mask(mask, array) +integer :: array(:) +logical, optional :: mask(:) +print *, minval(array, mask) +! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +! CHECK: fir.call @_FortranAMinvalInteger4(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_13]]) : (!fir.box, !fir.ref, i32, i32, !fir.box) -> i32 +end subroutine