@@ -1841,7 +1841,7 @@ static std::optional<hlfir::EntityWithAttributes> genCustomIntrinsicRefCore(
18411841static std::optional<hlfir::EntityWithAttributes>
18421842genIntrinsicRefCore (Fortran::lower::PreparedActualArguments &loweredActuals,
18431843 const Fortran::evaluate::SpecificIntrinsic *intrinsic,
1844- const fir::IntrinsicArgumentLoweringRules *argLowering ,
1844+ const fir::IntrinsicHandlerEntry &intrinsicEntry ,
18451845 CallContext &callContext) {
18461846 auto &converter = callContext.converter ;
18471847 if (intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling (
@@ -1856,6 +1856,8 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
18561856 auto &stmtCtx = callContext.stmtCtx ;
18571857 fir::FirOpBuilder &builder = callContext.getBuilder ();
18581858 mlir::Location loc = callContext.loc ;
1859+ const fir::IntrinsicArgumentLoweringRules *argLowering =
1860+ intrinsicEntry.getArgumentLoweringRules ();
18591861 for (auto arg : llvm::enumerate (loweredActuals)) {
18601862 if (!arg.value ()) {
18611863 operands.emplace_back (fir::getAbsentIntrinsicArgument ());
@@ -1991,7 +1993,7 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
19911993 const std::string intrinsicName = callContext.getProcedureName ();
19921994 // Let the intrinsic library lower the intrinsic procedure call.
19931995 auto [resultExv, mustBeFreed] = genIntrinsicCall (
1994- builder, loc, intrinsicName , scalarResultType, operands, &converter);
1996+ builder, loc, intrinsicEntry , scalarResultType, operands, &converter);
19951997 for (const hlfir::CleanupFunction &fn : cleanupFns)
19961998 fn ();
19971999 if (!fir::getBase (resultExv))
@@ -2023,18 +2025,16 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
20232025static std::optional<hlfir::EntityWithAttributes> genHLFIRIntrinsicRefCore (
20242026 Fortran::lower::PreparedActualArguments &loweredActuals,
20252027 const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2026- const fir::IntrinsicArgumentLoweringRules *argLowering ,
2028+ const fir::IntrinsicHandlerEntry &intrinsicEntry ,
20272029 CallContext &callContext) {
2028- if (!useHlfirIntrinsicOps)
2029- return genIntrinsicRefCore (loweredActuals, intrinsic, argLowering,
2030- callContext);
2031-
2032- fir::FirOpBuilder &builder = callContext.getBuilder ();
2033- mlir::Location loc = callContext.loc ;
2034- const std::string intrinsicName = callContext.getProcedureName ();
2035-
2036- // transformational intrinsic ops always have a result type
2037- if (callContext.resultType ) {
2030+ // Try lowering transformational intrinsic ops to HLFIR ops if enabled
2031+ // (transformational always have a result type)
2032+ if (useHlfirIntrinsicOps && callContext.resultType ) {
2033+ fir::FirOpBuilder &builder = callContext.getBuilder ();
2034+ mlir::Location loc = callContext.loc ;
2035+ const std::string intrinsicName = callContext.getProcedureName ();
2036+ const fir::IntrinsicArgumentLoweringRules *argLowering =
2037+ intrinsicEntry.getArgumentLoweringRules ();
20382038 std::optional<hlfir::EntityWithAttributes> res =
20392039 Fortran::lower::lowerHlfirIntrinsic (builder, loc, intrinsicName,
20402040 loweredActuals, argLowering,
@@ -2044,7 +2044,7 @@ static std::optional<hlfir::EntityWithAttributes> genHLFIRIntrinsicRefCore(
20442044 }
20452045
20462046 // fallback to calling the intrinsic via fir.call
2047- return genIntrinsicRefCore (loweredActuals, intrinsic, argLowering ,
2047+ return genIntrinsicRefCore (loweredActuals, intrinsic, intrinsicEntry ,
20482048 callContext);
20492049}
20502050
@@ -2303,13 +2303,13 @@ class ElementalIntrinsicCallBuilder
23032303public:
23042304 ElementalIntrinsicCallBuilder (
23052305 const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2306- const fir::IntrinsicArgumentLoweringRules *argLowering , bool isFunction)
2307- : intrinsic{intrinsic}, argLowering{argLowering}, isFunction{isFunction} {
2308- }
2306+ const fir::IntrinsicHandlerEntry &intrinsicEntry , bool isFunction)
2307+ : intrinsic{intrinsic}, intrinsicEntry{intrinsicEntry},
2308+ isFunction{isFunction} { }
23092309 std::optional<hlfir::Entity>
23102310 genElementalKernel (Fortran::lower::PreparedActualArguments &loweredActuals,
23112311 CallContext &callContext) {
2312- return genHLFIRIntrinsicRefCore (loweredActuals, intrinsic, argLowering ,
2312+ return genHLFIRIntrinsicRefCore (loweredActuals, intrinsic, intrinsicEntry ,
23132313 callContext);
23142314 }
23152315 // Elemental intrinsic functions cannot modify their arguments.
@@ -2363,7 +2363,7 @@ class ElementalIntrinsicCallBuilder
23632363
23642364private:
23652365 const Fortran::evaluate::SpecificIntrinsic *intrinsic;
2366- const fir::IntrinsicArgumentLoweringRules *argLowering ;
2366+ fir::IntrinsicHandlerEntry intrinsicEntry ;
23672367 const bool isFunction;
23682368};
23692369} // namespace
@@ -2436,11 +2436,16 @@ genCustomElementalIntrinsicRef(
24362436 callContext.procRef , *intrinsic, callContext.resultType ,
24372437 prepareOptionalArg, prepareOtherArg, converter);
24382438
2439- const fir::IntrinsicArgumentLoweringRules *argLowering =
2440- fir::getIntrinsicArgumentLowering (callContext.getProcedureName ());
2439+ std::optional<fir::IntrinsicHandlerEntry> intrinsicEntry =
2440+ fir::lookupIntrinsicHandler (callContext.getBuilder (),
2441+ callContext.getProcedureName (),
2442+ callContext.resultType );
2443+ assert (intrinsicEntry.has_value () &&
2444+ " intrinsic with custom handling for OPTIONAL arguments must have "
2445+ " lowering entries" );
24412446 // All of the custom intrinsic elementals with custom handling are pure
24422447 // functions
2443- return ElementalIntrinsicCallBuilder{intrinsic, argLowering ,
2448+ return ElementalIntrinsicCallBuilder{intrinsic, *intrinsicEntry ,
24442449 /* isFunction=*/ true }
24452450 .genElementalCall (operands, /* isImpure=*/ false , callContext);
24462451}
@@ -2517,21 +2522,15 @@ genCustomIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
25172522// / lowered as if it were an intrinsic module procedure (like C_LOC which is a
25182523// / procedure from intrinsic module iso_c_binding). Otherwise, \p intrinsic
25192524// / must not be null.
2525+
25202526static std::optional<hlfir::EntityWithAttributes>
25212527genIntrinsicRef (const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2528+ const fir::IntrinsicHandlerEntry &intrinsicEntry,
25222529 CallContext &callContext) {
25232530 mlir::Location loc = callContext.loc ;
2524- auto &converter = callContext.converter ;
2525- if (intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling (
2526- callContext.procRef , *intrinsic, converter)) {
2527- if (callContext.isElementalProcWithArrayArgs ())
2528- return genCustomElementalIntrinsicRef (intrinsic, callContext);
2529- return genCustomIntrinsicRef (intrinsic, callContext);
2530- }
2531-
25322531 Fortran::lower::PreparedActualArguments loweredActuals;
25332532 const fir::IntrinsicArgumentLoweringRules *argLowering =
2534- fir::getIntrinsicArgumentLowering (callContext. getProcedureName () );
2533+ intrinsicEntry. getArgumentLoweringRules ( );
25352534 for (const auto &arg : llvm::enumerate (callContext.procRef .arguments ())) {
25362535
25372536 if (!arg.value ()) {
@@ -2581,12 +2580,12 @@ genIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
25812580 if (callContext.isElementalProcWithArrayArgs ()) {
25822581 // All intrinsic elemental functions are pure.
25832582 const bool isFunction = callContext.resultType .has_value ();
2584- return ElementalIntrinsicCallBuilder{intrinsic, argLowering , isFunction}
2583+ return ElementalIntrinsicCallBuilder{intrinsic, intrinsicEntry , isFunction}
25852584 .genElementalCall (loweredActuals, /* isImpure=*/ !isFunction,
25862585 callContext);
25872586 }
25882587 std::optional<hlfir::EntityWithAttributes> result = genHLFIRIntrinsicRefCore (
2589- loweredActuals, intrinsic, argLowering , callContext);
2588+ loweredActuals, intrinsic, intrinsicEntry , callContext);
25902589 if (result && mlir::isa<hlfir::ExprType>(result->getType ())) {
25912590 fir::FirOpBuilder *bldr = &callContext.getBuilder ();
25922591 callContext.stmtCtx .attachCleanup (
@@ -2595,18 +2594,43 @@ genIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
25952594 return result;
25962595}
25972596
2597+ static std::optional<hlfir::EntityWithAttributes>
2598+ genIntrinsicRef (const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2599+ CallContext &callContext) {
2600+ mlir::Location loc = callContext.loc ;
2601+ auto &converter = callContext.converter ;
2602+ if (intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling (
2603+ callContext.procRef , *intrinsic, converter)) {
2604+ if (callContext.isElementalProcWithArrayArgs ())
2605+ return genCustomElementalIntrinsicRef (intrinsic, callContext);
2606+ return genCustomIntrinsicRef (intrinsic, callContext);
2607+ }
2608+ std::optional<fir::IntrinsicHandlerEntry> intrinsicEntry =
2609+ fir::lookupIntrinsicHandler (callContext.getBuilder (),
2610+ callContext.getProcedureName (),
2611+ callContext.resultType );
2612+ if (!intrinsicEntry)
2613+ fir::crashOnMissingIntrinsic (loc, callContext.getProcedureName ());
2614+ return genIntrinsicRef (intrinsic, *intrinsicEntry, callContext);
2615+ }
2616+
25982617// / Main entry point to lower procedure references, regardless of what they are.
25992618static std::optional<hlfir::EntityWithAttributes>
26002619genProcedureRef (CallContext &callContext) {
26012620 mlir::Location loc = callContext.loc ;
2621+ fir::FirOpBuilder &builder = callContext.getBuilder ();
26022622 if (auto *intrinsic = callContext.procRef .proc ().GetSpecificIntrinsic ())
26032623 return genIntrinsicRef (intrinsic, callContext);
2604- // If it is an intrinsic module procedure reference - then treat as
2605- // intrinsic unless it is bind(c) (since implementation is external from
2606- // module).
2624+ // Intercept non BIND(C) module procedure reference that have lowering
2625+ // handlers defined for there name. Otherwise, lower them as user
2626+ // procedure calls and expect the implementation to be part of
2627+ // runtime libraries with the proper name mangling.
26072628 if (Fortran::lower::isIntrinsicModuleProcRef (callContext.procRef ) &&
26082629 !callContext.isBindcCall ())
2609- return genIntrinsicRef (nullptr , callContext);
2630+ if (std::optional<fir::IntrinsicHandlerEntry> intrinsicEntry =
2631+ fir::lookupIntrinsicHandler (builder, callContext.getProcedureName (),
2632+ callContext.resultType ))
2633+ return genIntrinsicRef (nullptr , *intrinsicEntry, callContext);
26102634
26112635 if (callContext.isStatementFunctionCall ())
26122636 return genStmtFunctionRef (loc, callContext.converter , callContext.symMap ,
@@ -2641,7 +2665,6 @@ genProcedureRef(CallContext &callContext) {
26412665 // TYPE(*) cannot be ALLOCATABLE/POINTER (C709) so there is no
26422666 // need to cover the case of passing an ALLOCATABLE/POINTER to an
26432667 // OPTIONAL.
2644- fir::FirOpBuilder &builder = callContext.getBuilder ();
26452668 isPresent =
26462669 builder.create <fir::IsPresentOp>(loc, builder.getI1Type (), actual)
26472670 .getResult ();
0 commit comments