@@ -1841,7 +1841,7 @@ static std::optional<hlfir::EntityWithAttributes> genCustomIntrinsicRefCore(
1841
1841
static std::optional<hlfir::EntityWithAttributes>
1842
1842
genIntrinsicRefCore (Fortran::lower::PreparedActualArguments &loweredActuals,
1843
1843
const Fortran::evaluate::SpecificIntrinsic *intrinsic,
1844
- const fir::IntrinsicArgumentLoweringRules *argLowering ,
1844
+ const fir::IntrinsicHandlerEntry &intrinsicEntry ,
1845
1845
CallContext &callContext) {
1846
1846
auto &converter = callContext.converter ;
1847
1847
if (intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling (
@@ -1856,6 +1856,8 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
1856
1856
auto &stmtCtx = callContext.stmtCtx ;
1857
1857
fir::FirOpBuilder &builder = callContext.getBuilder ();
1858
1858
mlir::Location loc = callContext.loc ;
1859
+ const fir::IntrinsicArgumentLoweringRules *argLowering =
1860
+ intrinsicEntry.getArgumentLoweringRules ();
1859
1861
for (auto arg : llvm::enumerate (loweredActuals)) {
1860
1862
if (!arg.value ()) {
1861
1863
operands.emplace_back (fir::getAbsentIntrinsicArgument ());
@@ -1991,7 +1993,7 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
1991
1993
const std::string intrinsicName = callContext.getProcedureName ();
1992
1994
// Let the intrinsic library lower the intrinsic procedure call.
1993
1995
auto [resultExv, mustBeFreed] = genIntrinsicCall (
1994
- builder, loc, intrinsicName , scalarResultType, operands, &converter);
1996
+ builder, loc, intrinsicEntry , scalarResultType, operands, &converter);
1995
1997
for (const hlfir::CleanupFunction &fn : cleanupFns)
1996
1998
fn ();
1997
1999
if (!fir::getBase (resultExv))
@@ -2023,18 +2025,16 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
2023
2025
static std::optional<hlfir::EntityWithAttributes> genHLFIRIntrinsicRefCore (
2024
2026
Fortran::lower::PreparedActualArguments &loweredActuals,
2025
2027
const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2026
- const fir::IntrinsicArgumentLoweringRules *argLowering ,
2028
+ const fir::IntrinsicHandlerEntry &intrinsicEntry ,
2027
2029
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 ();
2038
2038
std::optional<hlfir::EntityWithAttributes> res =
2039
2039
Fortran::lower::lowerHlfirIntrinsic (builder, loc, intrinsicName,
2040
2040
loweredActuals, argLowering,
@@ -2044,7 +2044,7 @@ static std::optional<hlfir::EntityWithAttributes> genHLFIRIntrinsicRefCore(
2044
2044
}
2045
2045
2046
2046
// fallback to calling the intrinsic via fir.call
2047
- return genIntrinsicRefCore (loweredActuals, intrinsic, argLowering ,
2047
+ return genIntrinsicRefCore (loweredActuals, intrinsic, intrinsicEntry ,
2048
2048
callContext);
2049
2049
}
2050
2050
@@ -2303,13 +2303,13 @@ class ElementalIntrinsicCallBuilder
2303
2303
public:
2304
2304
ElementalIntrinsicCallBuilder (
2305
2305
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} { }
2309
2309
std::optional<hlfir::Entity>
2310
2310
genElementalKernel (Fortran::lower::PreparedActualArguments &loweredActuals,
2311
2311
CallContext &callContext) {
2312
- return genHLFIRIntrinsicRefCore (loweredActuals, intrinsic, argLowering ,
2312
+ return genHLFIRIntrinsicRefCore (loweredActuals, intrinsic, intrinsicEntry ,
2313
2313
callContext);
2314
2314
}
2315
2315
// Elemental intrinsic functions cannot modify their arguments.
@@ -2363,7 +2363,7 @@ class ElementalIntrinsicCallBuilder
2363
2363
2364
2364
private:
2365
2365
const Fortran::evaluate::SpecificIntrinsic *intrinsic;
2366
- const fir::IntrinsicArgumentLoweringRules *argLowering ;
2366
+ fir::IntrinsicHandlerEntry intrinsicEntry ;
2367
2367
const bool isFunction;
2368
2368
};
2369
2369
} // namespace
@@ -2436,11 +2436,16 @@ genCustomElementalIntrinsicRef(
2436
2436
callContext.procRef , *intrinsic, callContext.resultType ,
2437
2437
prepareOptionalArg, prepareOtherArg, converter);
2438
2438
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" );
2441
2446
// All of the custom intrinsic elementals with custom handling are pure
2442
2447
// functions
2443
- return ElementalIntrinsicCallBuilder{intrinsic, argLowering ,
2448
+ return ElementalIntrinsicCallBuilder{intrinsic, *intrinsicEntry ,
2444
2449
/* isFunction=*/ true }
2445
2450
.genElementalCall (operands, /* isImpure=*/ false , callContext);
2446
2451
}
@@ -2517,21 +2522,15 @@ genCustomIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2517
2522
// / lowered as if it were an intrinsic module procedure (like C_LOC which is a
2518
2523
// / procedure from intrinsic module iso_c_binding). Otherwise, \p intrinsic
2519
2524
// / must not be null.
2525
+
2520
2526
static std::optional<hlfir::EntityWithAttributes>
2521
2527
genIntrinsicRef (const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2528
+ const fir::IntrinsicHandlerEntry &intrinsicEntry,
2522
2529
CallContext &callContext) {
2523
2530
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
-
2532
2531
Fortran::lower::PreparedActualArguments loweredActuals;
2533
2532
const fir::IntrinsicArgumentLoweringRules *argLowering =
2534
- fir::getIntrinsicArgumentLowering (callContext. getProcedureName () );
2533
+ intrinsicEntry. getArgumentLoweringRules ( );
2535
2534
for (const auto &arg : llvm::enumerate (callContext.procRef .arguments ())) {
2536
2535
2537
2536
if (!arg.value ()) {
@@ -2581,12 +2580,12 @@ genIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2581
2580
if (callContext.isElementalProcWithArrayArgs ()) {
2582
2581
// All intrinsic elemental functions are pure.
2583
2582
const bool isFunction = callContext.resultType .has_value ();
2584
- return ElementalIntrinsicCallBuilder{intrinsic, argLowering , isFunction}
2583
+ return ElementalIntrinsicCallBuilder{intrinsic, intrinsicEntry , isFunction}
2585
2584
.genElementalCall (loweredActuals, /* isImpure=*/ !isFunction,
2586
2585
callContext);
2587
2586
}
2588
2587
std::optional<hlfir::EntityWithAttributes> result = genHLFIRIntrinsicRefCore (
2589
- loweredActuals, intrinsic, argLowering , callContext);
2588
+ loweredActuals, intrinsic, intrinsicEntry , callContext);
2590
2589
if (result && mlir::isa<hlfir::ExprType>(result->getType ())) {
2591
2590
fir::FirOpBuilder *bldr = &callContext.getBuilder ();
2592
2591
callContext.stmtCtx .attachCleanup (
@@ -2595,18 +2594,43 @@ genIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
2595
2594
return result;
2596
2595
}
2597
2596
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
+
2598
2617
// / Main entry point to lower procedure references, regardless of what they are.
2599
2618
static std::optional<hlfir::EntityWithAttributes>
2600
2619
genProcedureRef (CallContext &callContext) {
2601
2620
mlir::Location loc = callContext.loc ;
2621
+ fir::FirOpBuilder &builder = callContext.getBuilder ();
2602
2622
if (auto *intrinsic = callContext.procRef .proc ().GetSpecificIntrinsic ())
2603
2623
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.
2607
2628
if (Fortran::lower::isIntrinsicModuleProcRef (callContext.procRef ) &&
2608
2629
!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);
2610
2634
2611
2635
if (callContext.isStatementFunctionCall ())
2612
2636
return genStmtFunctionRef (loc, callContext.converter , callContext.symMap ,
@@ -2641,7 +2665,6 @@ genProcedureRef(CallContext &callContext) {
2641
2665
// TYPE(*) cannot be ALLOCATABLE/POINTER (C709) so there is no
2642
2666
// need to cover the case of passing an ALLOCATABLE/POINTER to an
2643
2667
// OPTIONAL.
2644
- fir::FirOpBuilder &builder = callContext.getBuilder ();
2645
2668
isPresent =
2646
2669
builder.create <fir::IsPresentOp>(loc, builder.getI1Type (), actual)
2647
2670
.getResult ();
0 commit comments