634 lines · cpp
1//===-- HlfirIntrinsics.cpp -----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12 13#include "flang/Lower/HlfirIntrinsics.h"14 15#include "flang/Optimizer/Builder/BoxValue.h"16#include "flang/Optimizer/Builder/FIRBuilder.h"17#include "flang/Optimizer/Builder/HLFIRTools.h"18#include "flang/Optimizer/Builder/IntrinsicCall.h"19#include "flang/Optimizer/Builder/MutableBox.h"20#include "flang/Optimizer/Builder/Todo.h"21#include "flang/Optimizer/Dialect/FIRType.h"22#include "flang/Optimizer/HLFIR/HLFIRDialect.h"23#include "flang/Optimizer/HLFIR/HLFIROps.h"24#include "mlir/IR/Value.h"25#include "llvm/ADT/SmallVector.h"26#include <mlir/IR/ValueRange.h>27 28namespace {29 30class HlfirTransformationalIntrinsic {31public:32 explicit HlfirTransformationalIntrinsic(fir::FirOpBuilder &builder,33 mlir::Location loc)34 : builder(builder), loc(loc) {}35 36 virtual ~HlfirTransformationalIntrinsic() = default;37 38 hlfir::EntityWithAttributes39 lower(const Fortran::lower::PreparedActualArguments &loweredActuals,40 const fir::IntrinsicArgumentLoweringRules *argLowering,41 mlir::Type stmtResultType) {42 mlir::Value res = lowerImpl(loweredActuals, argLowering, stmtResultType);43 for (const hlfir::CleanupFunction &fn : cleanupFns)44 fn();45 return {hlfir::EntityWithAttributes{res}};46 }47 48protected:49 fir::FirOpBuilder &builder;50 mlir::Location loc;51 llvm::SmallVector<hlfir::CleanupFunction, 3> cleanupFns;52 53 virtual mlir::Value54 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,55 const fir::IntrinsicArgumentLoweringRules *argLowering,56 mlir::Type stmtResultType) = 0;57 58 llvm::SmallVector<mlir::Value> getOperandVector(59 const Fortran::lower::PreparedActualArguments &loweredActuals,60 const fir::IntrinsicArgumentLoweringRules *argLowering);61 62 mlir::Type computeResultType(mlir::Value argArray, mlir::Type stmtResultType);63 64 template <typename OP, typename... BUILD_ARGS>65 inline OP createOp(BUILD_ARGS... args) {66 return OP::create(builder, loc, args...);67 }68 69 mlir::Value loadBoxAddress(70 const std::optional<Fortran::lower::PreparedActualArgument> &arg);71 72 mlir::Value73 loadTrivialScalar(const Fortran::lower::PreparedActualArgument &arg);74 75 mlir::Value loadOptionalValue(Fortran::lower::PreparedActualArgument &arg);76 77 void addCleanup(std::optional<hlfir::CleanupFunction> cleanup) {78 if (cleanup)79 cleanupFns.emplace_back(std::move(*cleanup));80 }81};82 83template <typename OP, bool HAS_MASK>84class HlfirReductionIntrinsic : public HlfirTransformationalIntrinsic {85public:86 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;87 88protected:89 mlir::Value90 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,91 const fir::IntrinsicArgumentLoweringRules *argLowering,92 mlir::Type stmtResultType) override;93};94using HlfirSumLowering = HlfirReductionIntrinsic<hlfir::SumOp, true>;95using HlfirProductLowering = HlfirReductionIntrinsic<hlfir::ProductOp, true>;96using HlfirMaxvalLowering = HlfirReductionIntrinsic<hlfir::MaxvalOp, true>;97using HlfirMinvalLowering = HlfirReductionIntrinsic<hlfir::MinvalOp, true>;98using HlfirAnyLowering = HlfirReductionIntrinsic<hlfir::AnyOp, false>;99using HlfirAllLowering = HlfirReductionIntrinsic<hlfir::AllOp, false>;100 101template <typename OP>102class HlfirMinMaxLocIntrinsic : public HlfirTransformationalIntrinsic {103public:104 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;105 106protected:107 mlir::Value108 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,109 const fir::IntrinsicArgumentLoweringRules *argLowering,110 mlir::Type stmtResultType) override;111};112using HlfirMinlocLowering = HlfirMinMaxLocIntrinsic<hlfir::MinlocOp>;113using HlfirMaxlocLowering = HlfirMinMaxLocIntrinsic<hlfir::MaxlocOp>;114 115template <typename OP>116class HlfirProductIntrinsic : public HlfirTransformationalIntrinsic {117public:118 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;119 120protected:121 mlir::Value122 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,123 const fir::IntrinsicArgumentLoweringRules *argLowering,124 mlir::Type stmtResultType) override;125};126using HlfirMatmulLowering = HlfirProductIntrinsic<hlfir::MatmulOp>;127using HlfirDotProductLowering = HlfirProductIntrinsic<hlfir::DotProductOp>;128 129class HlfirTransposeLowering : public HlfirTransformationalIntrinsic {130public:131 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;132 133protected:134 mlir::Value135 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,136 const fir::IntrinsicArgumentLoweringRules *argLowering,137 mlir::Type stmtResultType) override;138};139 140class HlfirCountLowering : public HlfirTransformationalIntrinsic {141public:142 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;143 144protected:145 mlir::Value146 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,147 const fir::IntrinsicArgumentLoweringRules *argLowering,148 mlir::Type stmtResultType) override;149};150 151class HlfirCharExtremumLowering : public HlfirTransformationalIntrinsic {152public:153 HlfirCharExtremumLowering(fir::FirOpBuilder &builder, mlir::Location loc,154 hlfir::CharExtremumPredicate pred)155 : HlfirTransformationalIntrinsic(builder, loc), pred{pred} {}156 157protected:158 mlir::Value159 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,160 const fir::IntrinsicArgumentLoweringRules *argLowering,161 mlir::Type stmtResultType) override;162 163protected:164 hlfir::CharExtremumPredicate pred;165};166 167class HlfirCharTrimLowering : public HlfirTransformationalIntrinsic {168public:169 HlfirCharTrimLowering(fir::FirOpBuilder &builder, mlir::Location loc)170 : HlfirTransformationalIntrinsic(builder, loc) {}171 172protected:173 mlir::Value174 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,175 const fir::IntrinsicArgumentLoweringRules *argLowering,176 mlir::Type stmtResultType) override;177};178 179class HlfirCShiftLowering : public HlfirTransformationalIntrinsic {180public:181 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;182 183protected:184 mlir::Value185 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,186 const fir::IntrinsicArgumentLoweringRules *argLowering,187 mlir::Type stmtResultType) override;188};189 190class HlfirEOShiftLowering : public HlfirTransformationalIntrinsic {191public:192 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;193 194protected:195 mlir::Value196 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,197 const fir::IntrinsicArgumentLoweringRules *argLowering,198 mlir::Type stmtResultType) override;199};200 201class HlfirReshapeLowering : public HlfirTransformationalIntrinsic {202public:203 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;204 205protected:206 mlir::Value207 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,208 const fir::IntrinsicArgumentLoweringRules *argLowering,209 mlir::Type stmtResultType) override;210};211 212class HlfirIndexLowering : public HlfirTransformationalIntrinsic {213public:214 using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;215 216protected:217 mlir::Value218 lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,219 const fir::IntrinsicArgumentLoweringRules *argLowering,220 mlir::Type stmtResultType) override;221};222 223} // namespace224 225mlir::Value HlfirTransformationalIntrinsic::loadBoxAddress(226 const std::optional<Fortran::lower::PreparedActualArgument> &arg) {227 if (!arg)228 return mlir::Value{};229 230 hlfir::Entity actual = arg->getActual(loc, builder);231 232 if (!arg->handleDynamicOptional()) {233 if (actual.isMutableBox()) {234 // this is a box address type but is not dynamically optional. Just load235 // the box, assuming it is well formed (!fir.ref<!fir.box<...>> ->236 // !fir.box<...>)237 return fir::LoadOp::create(builder, loc, actual.getBase());238 }239 return actual;240 }241 242 auto [exv, cleanup] = hlfir::translateToExtendedValue(loc, builder, actual);243 addCleanup(cleanup);244 245 mlir::Value isPresent = arg->getIsPresent();246 // createBox will not do create any invalid memory dereferences if exv is247 // absent. The created fir.box will not be usable, but the SelectOp below248 // ensures it won't be.249 mlir::Value box = builder.createBox(loc, exv);250 mlir::Type boxType = box.getType();251 auto absent = fir::AbsentOp::create(builder, loc, boxType);252 auto boxOrAbsent = mlir::arith::SelectOp::create(builder, loc, boxType,253 isPresent, box, absent);254 255 return boxOrAbsent;256}257 258mlir::Value HlfirTransformationalIntrinsic::loadOptionalValue(259 Fortran::lower::PreparedActualArgument &arg) {260 mlir::Type eleType = arg.getFortranElementType();261 262 // For an elemental call, getActual() may produce263 // a designator denoting the array element to be passed264 // to the subprogram. If the actual array is dynamically265 // optional the designator must be generated under266 // isPresent check (see also genIntrinsicRefCore).267 return builder268 .genIfOp(loc, {eleType}, arg.getIsPresent(),269 /*withElseRegion=*/true)270 .genThen([&]() {271 hlfir::Entity actual = arg.getActual(loc, builder);272 assert(eleType == actual.getFortranElementType() &&273 "result type mismatch in genOptionalValue");274 assert(actual.isScalar() && fir::isa_trivial(eleType) &&275 "must be a numerical or logical scalar");276 hlfir::Entity val = hlfir::loadTrivialScalar(loc, builder, actual);277 fir::ResultOp::create(builder, loc, val);278 })279 .genElse([&]() {280 mlir::Value zero = fir::factory::createZeroValue(builder, loc, eleType);281 fir::ResultOp::create(builder, loc, zero);282 })283 .getResults()[0];284}285 286mlir::Value HlfirTransformationalIntrinsic::loadTrivialScalar(287 const Fortran::lower::PreparedActualArgument &arg) {288 hlfir::Entity actual = arg.getActual(loc, builder);289 return hlfir::loadTrivialScalar(loc, builder, actual);290}291 292llvm::SmallVector<mlir::Value> HlfirTransformationalIntrinsic::getOperandVector(293 const Fortran::lower::PreparedActualArguments &loweredActuals,294 const fir::IntrinsicArgumentLoweringRules *argLowering) {295 llvm::SmallVector<mlir::Value> operands;296 operands.reserve(loweredActuals.size());297 298 for (size_t i = 0; i < loweredActuals.size(); ++i) {299 std::optional<Fortran::lower::PreparedActualArgument> arg =300 loweredActuals[i];301 if (!arg) {302 operands.emplace_back();303 continue;304 }305 mlir::Value valArg;306 if (!argLowering) {307 valArg = loadTrivialScalar(*arg);308 operands.emplace_back(valArg);309 continue;310 }311 fir::ArgLoweringRule argRules =312 fir::lowerIntrinsicArgumentAs(*argLowering, i);313 if (argRules.lowerAs == fir::LowerIntrinsicArgAs::Box) {314 valArg = loadBoxAddress(arg);315 } else if (argRules.handleDynamicOptional) {316 if (argRules.lowerAs == fir::LowerIntrinsicArgAs::Value) {317 if (arg->handleDynamicOptional())318 valArg = loadOptionalValue(*arg);319 else320 valArg = loadTrivialScalar(*arg);321 } else {322 TODO(loc, "hlfir transformational intrinsic dynamically optional "323 "argument without box lowering");324 }325 } else {326 hlfir::Entity actual = arg->getActual(loc, builder);327 if (argRules.lowerAs != fir::LowerIntrinsicArgAs::Inquired)328 valArg = hlfir::derefPointersAndAllocatables(loc, builder, actual);329 else330 valArg = actual.getBase();331 }332 operands.emplace_back(valArg);333 }334 return operands;335}336 337mlir::Type338HlfirTransformationalIntrinsic::computeResultType(mlir::Value argArray,339 mlir::Type stmtResultType) {340 mlir::Type normalisedResult =341 hlfir::getFortranElementOrSequenceType(stmtResultType);342 if (auto array = mlir::dyn_cast<fir::SequenceType>(normalisedResult)) {343 hlfir::ExprType::Shape resultShape =344 hlfir::ExprType::Shape{array.getShape()};345 mlir::Type elementType = array.getEleTy();346 return hlfir::ExprType::get(builder.getContext(), resultShape, elementType,347 fir::isPolymorphicType(stmtResultType));348 } else if (auto resCharType =349 mlir::dyn_cast<fir::CharacterType>(stmtResultType)) {350 normalisedResult = hlfir::ExprType::get(351 builder.getContext(), hlfir::ExprType::Shape{}, resCharType,352 /*polymorphic=*/false);353 }354 return normalisedResult;355}356 357template <typename OP, bool HAS_MASK>358mlir::Value HlfirReductionIntrinsic<OP, HAS_MASK>::lowerImpl(359 const Fortran::lower::PreparedActualArguments &loweredActuals,360 const fir::IntrinsicArgumentLoweringRules *argLowering,361 mlir::Type stmtResultType) {362 auto operands = getOperandVector(loweredActuals, argLowering);363 mlir::Value array = operands[0];364 mlir::Value dim = operands[1];365 // dim, mask can be NULL if these arguments are not given366 if (dim)367 dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});368 369 mlir::Type resultTy = computeResultType(array, stmtResultType);370 371 OP op;372 if constexpr (HAS_MASK)373 op = createOp<OP>(resultTy, array, dim,374 /*mask=*/operands[2]);375 else376 op = createOp<OP>(resultTy, array, dim);377 return op;378}379 380template <typename OP>381mlir::Value HlfirMinMaxLocIntrinsic<OP>::lowerImpl(382 const Fortran::lower::PreparedActualArguments &loweredActuals,383 const fir::IntrinsicArgumentLoweringRules *argLowering,384 mlir::Type stmtResultType) {385 auto operands = getOperandVector(loweredActuals, argLowering);386 mlir::Value array = operands[0];387 mlir::Value dim = operands[1];388 mlir::Value mask = operands[2];389 mlir::Value back = operands[4];390 // dim, mask and back can be NULL if these arguments are not given.391 if (dim)392 dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});393 if (back)394 back = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{back});395 396 mlir::Type resultTy = computeResultType(array, stmtResultType);397 398 return createOp<OP>(resultTy, array, dim, mask, back);399}400 401template <typename OP>402mlir::Value HlfirProductIntrinsic<OP>::lowerImpl(403 const Fortran::lower::PreparedActualArguments &loweredActuals,404 const fir::IntrinsicArgumentLoweringRules *argLowering,405 mlir::Type stmtResultType) {406 auto operands = getOperandVector(loweredActuals, argLowering);407 mlir::Type resultType = computeResultType(operands[0], stmtResultType);408 return createOp<OP>(resultType, operands[0], operands[1]);409}410 411mlir::Value HlfirTransposeLowering::lowerImpl(412 const Fortran::lower::PreparedActualArguments &loweredActuals,413 const fir::IntrinsicArgumentLoweringRules *argLowering,414 mlir::Type stmtResultType) {415 auto operands = getOperandVector(loweredActuals, argLowering);416 hlfir::ExprType::Shape resultShape;417 mlir::Type normalisedResult =418 hlfir::getFortranElementOrSequenceType(stmtResultType);419 auto array = mlir::cast<fir::SequenceType>(normalisedResult);420 llvm::ArrayRef<int64_t> arrayShape = array.getShape();421 assert(arrayShape.size() == 2 && "arguments to transpose have a rank of 2");422 mlir::Type elementType = array.getEleTy();423 resultShape.push_back(arrayShape[0]);424 resultShape.push_back(arrayShape[1]);425 if (auto resCharType = mlir::dyn_cast<fir::CharacterType>(elementType))426 if (!resCharType.hasConstantLen()) {427 // The FunctionRef expression might have imprecise character428 // type at this point, and we can improve it by propagating429 // the constant length from the argument.430 auto argCharType = mlir::dyn_cast<fir::CharacterType>(431 hlfir::getFortranElementType(operands[0].getType()));432 if (argCharType && argCharType.hasConstantLen())433 elementType = fir::CharacterType::get(434 builder.getContext(), resCharType.getFKind(), argCharType.getLen());435 }436 437 mlir::Type resultTy =438 hlfir::ExprType::get(builder.getContext(), resultShape, elementType,439 fir::isPolymorphicType(stmtResultType));440 return createOp<hlfir::TransposeOp>(resultTy, operands[0]);441}442 443mlir::Value HlfirCountLowering::lowerImpl(444 const Fortran::lower::PreparedActualArguments &loweredActuals,445 const fir::IntrinsicArgumentLoweringRules *argLowering,446 mlir::Type stmtResultType) {447 auto operands = getOperandVector(loweredActuals, argLowering);448 mlir::Value array = operands[0];449 mlir::Value dim = operands[1];450 if (dim)451 dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});452 mlir::Type resultType = computeResultType(array, stmtResultType);453 return createOp<hlfir::CountOp>(resultType, array, dim);454}455 456mlir::Value HlfirCharExtremumLowering::lowerImpl(457 const Fortran::lower::PreparedActualArguments &loweredActuals,458 const fir::IntrinsicArgumentLoweringRules *argLowering,459 mlir::Type stmtResultType) {460 auto operands = getOperandVector(loweredActuals, argLowering);461 assert(operands.size() >= 2);462 return createOp<hlfir::CharExtremumOp>(pred, mlir::ValueRange{operands});463}464 465mlir::Value HlfirCharTrimLowering::lowerImpl(466 const Fortran::lower::PreparedActualArguments &loweredActuals,467 const fir::IntrinsicArgumentLoweringRules *argLowering,468 mlir::Type stmtResultType) {469 auto operands = getOperandVector(loweredActuals, argLowering);470 assert(operands.size() == 1);471 return createOp<hlfir::CharTrimOp>(operands[0]);472}473 474mlir::Value HlfirCShiftLowering::lowerImpl(475 const Fortran::lower::PreparedActualArguments &loweredActuals,476 const fir::IntrinsicArgumentLoweringRules *argLowering,477 mlir::Type stmtResultType) {478 auto operands = getOperandVector(loweredActuals, argLowering);479 assert(operands.size() == 3);480 mlir::Value dim = operands[2];481 if (!dim) {482 // If DIM is not present, drop the last element which is a null Value.483 operands.truncate(2);484 } else {485 // If DIM is present, then dereference it if it is a ref.486 dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});487 operands[2] = dim;488 }489 490 mlir::Type resultType = computeResultType(operands[0], stmtResultType);491 return createOp<hlfir::CShiftOp>(resultType, operands);492}493 494mlir::Value HlfirEOShiftLowering::lowerImpl(495 const Fortran::lower::PreparedActualArguments &loweredActuals,496 const fir::IntrinsicArgumentLoweringRules *argLowering,497 mlir::Type stmtResultType) {498 auto operands = getOperandVector(loweredActuals, argLowering);499 assert(operands.size() == 4);500 mlir::Value array = operands[0];501 mlir::Value shift = operands[1];502 mlir::Value boundary = operands[2];503 mlir::Value dim = operands[3];504 // If DIM is present, then dereference it if it is a ref.505 if (dim)506 dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});507 508 mlir::Type resultType = computeResultType(array, stmtResultType);509 510 if (boundary && fir::isa_trivial(boundary.getType())) {511 mlir::Type elementType = hlfir::getFortranElementType(resultType);512 if (auto logicalTy = mlir::dyn_cast<fir::LogicalType>(elementType)) {513 // Scalar logical constant boundary might be represented using i1, i2, ...514 // type. We need to cast it to fir.logical type of the ARRAY/result.515 if (boundary.getType() != logicalTy)516 boundary = builder.createConvert(loc, logicalTy, boundary);517 } else {518 // When the boundary is a constant like '1u', the lowering converts519 // it into a signless arith.constant value (which is a requirement520 // of the Arith dialect). If the ARRAY/RESULT is also UNSIGNED,521 // we have to cast the boundary to the same unsigned type.522 auto resultIntTy = mlir::dyn_cast<mlir::IntegerType>(elementType);523 auto boundaryIntTy =524 mlir::dyn_cast<mlir::IntegerType>(boundary.getType());525 if (resultIntTy && boundaryIntTy &&526 resultIntTy.getSignedness() != boundaryIntTy.getSignedness())527 boundary = builder.createConvert(loc, resultIntTy, boundary);528 }529 }530 531 return createOp<hlfir::EOShiftOp>(resultType, array, shift, boundary, dim);532}533 534mlir::Value HlfirReshapeLowering::lowerImpl(535 const Fortran::lower::PreparedActualArguments &loweredActuals,536 const fir::IntrinsicArgumentLoweringRules *argLowering,537 mlir::Type stmtResultType) {538 auto operands = getOperandVector(loweredActuals, argLowering);539 assert(operands.size() == 4);540 mlir::Type resultType = computeResultType(operands[0], stmtResultType);541 return createOp<hlfir::ReshapeOp>(resultType, operands[0], operands[1],542 operands[2], operands[3]);543}544 545mlir::Value HlfirIndexLowering::lowerImpl(546 const Fortran::lower::PreparedActualArguments &loweredActuals,547 const fir::IntrinsicArgumentLoweringRules *argLowering,548 mlir::Type stmtResultType) {549 auto operands = getOperandVector(loweredActuals, argLowering);550 // 'kind' optional operand is unused here as it has already been551 // translated into result type.552 assert(operands.size() == 4);553 mlir::Value substr = operands[1];554 mlir::Value str = operands[0];555 mlir::Value back = operands[2];556 mlir::Value result =557 createOp<hlfir::IndexOp>(stmtResultType, substr, str, back);558 return result;559}560 561std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(562 fir::FirOpBuilder &builder, mlir::Location loc, const std::string &name,563 const Fortran::lower::PreparedActualArguments &loweredActuals,564 const fir::IntrinsicArgumentLoweringRules *argLowering,565 mlir::Type stmtResultType) {566 // If the result is of a derived type that may need finalization,567 // we have to use DestroyOp with 'finalize' attribute for the result568 // of the intrinsic operation.569 if (name == "sum")570 return HlfirSumLowering{builder, loc}.lower(loweredActuals, argLowering,571 stmtResultType);572 if (name == "product")573 return HlfirProductLowering{builder, loc}.lower(loweredActuals, argLowering,574 stmtResultType);575 if (name == "any")576 return HlfirAnyLowering{builder, loc}.lower(loweredActuals, argLowering,577 stmtResultType);578 if (name == "all")579 return HlfirAllLowering{builder, loc}.lower(loweredActuals, argLowering,580 stmtResultType);581 if (name == "matmul")582 return HlfirMatmulLowering{builder, loc}.lower(loweredActuals, argLowering,583 stmtResultType);584 if (name == "dot_product")585 return HlfirDotProductLowering{builder, loc}.lower(586 loweredActuals, argLowering, stmtResultType);587 // FIXME: the result may need finalization.588 if (name == "transpose")589 return HlfirTransposeLowering{builder, loc}.lower(590 loweredActuals, argLowering, stmtResultType);591 if (name == "count")592 return HlfirCountLowering{builder, loc}.lower(loweredActuals, argLowering,593 stmtResultType);594 if (name == "maxval")595 return HlfirMaxvalLowering{builder, loc}.lower(loweredActuals, argLowering,596 stmtResultType);597 if (name == "minval")598 return HlfirMinvalLowering{builder, loc}.lower(loweredActuals, argLowering,599 stmtResultType);600 if (name == "minloc")601 return HlfirMinlocLowering{builder, loc}.lower(loweredActuals, argLowering,602 stmtResultType);603 if (name == "maxloc")604 return HlfirMaxlocLowering{builder, loc}.lower(loweredActuals, argLowering,605 stmtResultType);606 if (name == "cshift")607 return HlfirCShiftLowering{builder, loc}.lower(loweredActuals, argLowering,608 stmtResultType);609 if (name == "eoshift")610 return HlfirEOShiftLowering{builder, loc}.lower(loweredActuals, argLowering,611 stmtResultType);612 if (name == "reshape")613 return HlfirReshapeLowering{builder, loc}.lower(loweredActuals, argLowering,614 stmtResultType);615 if (name == "index")616 return HlfirIndexLowering{builder, loc}.lower(loweredActuals, argLowering,617 stmtResultType);618 619 if (mlir::isa<fir::CharacterType>(stmtResultType)) {620 if (name == "min")621 return HlfirCharExtremumLowering{builder, loc,622 hlfir::CharExtremumPredicate::min}623 .lower(loweredActuals, argLowering, stmtResultType);624 if (name == "max")625 return HlfirCharExtremumLowering{builder, loc,626 hlfir::CharExtremumPredicate::max}627 .lower(loweredActuals, argLowering, stmtResultType);628 if (name == "trim")629 return HlfirCharTrimLowering{builder, loc}.lower(630 loweredActuals, argLowering, stmtResultType);631 }632 return std::nullopt;633}634