@@ -54,17 +54,22 @@ bool Fortran::lower::CallerInterface::hasAlternateReturns() const {
54
54
return procRef.hasAlternateReturns ();
55
55
}
56
56
57
- std::string Fortran::lower::CallerInterface::getMangledName () const {
58
- const Fortran::evaluate::ProcedureDesignator &proc = procRef.proc ();
59
- // Return the binding label (from BIND(C...)) or the mangled name of the
60
- // symbol.
57
+ // / Return the binding label (from BIND(C...)) or the mangled name of the
58
+ // / symbol.
59
+ static std::string
60
+ getProcMangledName (const Fortran::evaluate::ProcedureDesignator &proc,
61
+ Fortran::lower::AbstractConverter &converter) {
61
62
if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol ())
62
63
return converter.mangleName (symbol->GetUltimate ());
63
64
assert (proc.GetSpecificIntrinsic () &&
64
65
" expected intrinsic procedure in designator" );
65
66
return proc.GetName ();
66
67
}
67
68
69
+ std::string Fortran::lower::CallerInterface::getMangledName () const {
70
+ return getProcMangledName (procRef.proc (), converter);
71
+ }
72
+
68
73
const Fortran::semantics::Symbol *
69
74
Fortran::lower::CallerInterface::getProcedureSymbol () const {
70
75
return procRef.proc ().GetSymbol ();
@@ -127,17 +132,25 @@ Fortran::lower::CallerInterface::getIfIndirectCallSymbol() const {
127
132
return nullptr ;
128
133
}
129
134
130
- mlir::Location Fortran::lower::CallerInterface::getCalleeLocation () const {
131
- const Fortran::evaluate::ProcedureDesignator &proc = procRef.proc ();
132
- // FIXME: If the callee is defined in the same file but after the current
135
+ static mlir::Location
136
+ getProcedureDesignatorLoc (const Fortran::evaluate::ProcedureDesignator &proc,
137
+ Fortran::lower::AbstractConverter &converter) {
138
+ // Note: If the callee is defined in the same file but after the current
133
139
// unit we cannot get its location here and the funcOp is created at the
134
140
// wrong location (i.e, the caller location).
141
+ // To prevent this, it is up to the bridge to first declare all functions
142
+ // defined in the translation unit before lowering any calls or procedure
143
+ // designator references.
135
144
if (const Fortran::semantics::Symbol *symbol = proc.GetSymbol ())
136
145
return converter.genLocation (symbol->name ());
137
146
// Use current location for intrinsics.
138
147
return converter.getCurrentLocation ();
139
148
}
140
149
150
+ mlir::Location Fortran::lower::CallerInterface::getCalleeLocation () const {
151
+ return getProcedureDesignatorLoc (procRef.proc (), converter);
152
+ }
153
+
141
154
// Get dummy argument characteristic for a procedure with implicit interface
142
155
// from the actual argument characteristic. The actual argument may not be a F77
143
156
// entity. The attribute must be dropped and the shape, if any, must be made
@@ -1341,6 +1354,12 @@ class SignatureBuilder
1341
1354
bool isImplicit = forceImplicit || proc.CanBeCalledViaImplicitInterface ();
1342
1355
determineInterface (isImplicit, proc);
1343
1356
}
1357
+ SignatureBuilder (const Fortran::evaluate::ProcedureDesignator &procDes,
1358
+ Fortran::lower::AbstractConverter &c)
1359
+ : CallInterface{c}, procDesignator{&procDes},
1360
+ proc{Fortran::evaluate::characteristics::Procedure::Characterize (
1361
+ procDes, converter.getFoldingContext ())
1362
+ .value ()} {}
1344
1363
// / Does the procedure characteristics being translated have alternate
1345
1364
// / returns ?
1346
1365
bool hasAlternateReturns () const {
@@ -1354,17 +1373,24 @@ class SignatureBuilder
1354
1373
1355
1374
// / This is only here to fulfill CRTP dependencies and should not be called.
1356
1375
std::string getMangledName () const {
1357
- llvm_unreachable (" trying to get name from SignatureBuilder" );
1376
+ if (procDesignator)
1377
+ return getProcMangledName (*procDesignator, converter);
1378
+ fir::emitFatalError (
1379
+ converter.getCurrentLocation (),
1380
+ " should not query name when only building function type" );
1358
1381
}
1359
1382
1360
1383
// / This is only here to fulfill CRTP dependencies and should not be called.
1361
1384
mlir::Location getCalleeLocation () const {
1362
- llvm_unreachable (" trying to get callee location from SignatureBuilder" );
1385
+ if (procDesignator)
1386
+ return getProcedureDesignatorLoc (*procDesignator, converter);
1387
+ return converter.getCurrentLocation ();
1363
1388
}
1364
1389
1365
- // / This is only here to fulfill CRTP dependencies and should not be called.
1366
1390
const Fortran::semantics::Symbol *getProcedureSymbol () const {
1367
- llvm_unreachable (" trying to get callee symbol from SignatureBuilder" );
1391
+ if (procDesignator)
1392
+ return procDesignator->GetSymbol ();
1393
+ return nullptr ;
1368
1394
};
1369
1395
1370
1396
Fortran::evaluate::characteristics::Procedure characterize () const {
@@ -1380,11 +1406,37 @@ class SignatureBuilder
1380
1406
return proc;
1381
1407
}
1382
1408
1409
+ // / Set internal procedure attribute on MLIR function. Internal procedure
1410
+ // / are defined in the current file and will not go through SignatureBuilder.
1411
+ void setFuncAttrs (mlir::func::FuncOp) const {}
1412
+
1383
1413
// / This is not the description of an indirect call.
1384
1414
static constexpr bool isIndirectCall () { return false ; }
1385
1415
1386
1416
// / Return the translated signature.
1387
- mlir::FunctionType getFunctionType () { return genFunctionType (); }
1417
+ mlir::FunctionType getFunctionType () {
1418
+ if (interfaceDetermined)
1419
+ fir::emitFatalError (converter.getCurrentLocation (),
1420
+ " SignatureBuilder should only be used once" );
1421
+ // Most unrestricted intrinsic characteristics have the Elemental attribute
1422
+ // which triggers CanBeCalledViaImplicitInterface to return false. However,
1423
+ // using implicit interface rules is just fine here.
1424
+ bool forceImplicit =
1425
+ procDesignator && procDesignator->GetSpecificIntrinsic ();
1426
+ bool isImplicit = forceImplicit || proc.CanBeCalledViaImplicitInterface ();
1427
+ determineInterface (isImplicit, proc);
1428
+ interfaceDetermined = true ;
1429
+ return genFunctionType ();
1430
+ }
1431
+
1432
+ mlir::func::FuncOp getOrCreateFuncOp () {
1433
+ if (interfaceDetermined)
1434
+ fir::emitFatalError (converter.getCurrentLocation (),
1435
+ " SignatureBuilder should only be used once" );
1436
+ declare ();
1437
+ interfaceDetermined = true ;
1438
+ return getFuncOp ();
1439
+ }
1388
1440
1389
1441
// Copy of base implementation.
1390
1442
static constexpr bool hasHostAssociated () { return false ; }
@@ -1393,47 +1445,30 @@ class SignatureBuilder
1393
1445
}
1394
1446
1395
1447
private:
1396
- const Fortran::evaluate::characteristics::Procedure &proc;
1448
+ const Fortran::evaluate::ProcedureDesignator *procDesignator = nullptr ;
1449
+ Fortran::evaluate::characteristics::Procedure proc;
1450
+ bool interfaceDetermined = false ;
1397
1451
};
1398
1452
1399
1453
mlir::FunctionType Fortran::lower::translateSignature (
1400
1454
const Fortran::evaluate::ProcedureDesignator &proc,
1401
1455
Fortran::lower::AbstractConverter &converter) {
1402
- std::optional<Fortran::evaluate::characteristics::Procedure> characteristics =
1403
- Fortran::evaluate::characteristics::Procedure::Characterize (
1404
- proc, converter.getFoldingContext ());
1405
- // Most unrestricted intrinsic characteristic has the Elemental attribute
1406
- // which triggers CanBeCalledViaImplicitInterface to return false. However,
1407
- // using implicit interface rules is just fine here.
1408
- bool forceImplicit = proc.GetSpecificIntrinsic ();
1409
- return SignatureBuilder{characteristics.value (), converter, forceImplicit}
1410
- .getFunctionType ();
1456
+ return SignatureBuilder{proc, converter}.getFunctionType ();
1411
1457
}
1412
1458
1413
1459
mlir::func::FuncOp Fortran::lower::getOrDeclareFunction (
1414
- llvm::StringRef name, const Fortran::evaluate::ProcedureDesignator &proc,
1460
+ const Fortran::evaluate::ProcedureDesignator &proc,
1415
1461
Fortran::lower::AbstractConverter &converter) {
1416
1462
mlir::ModuleOp module = converter.getModuleOp ();
1463
+ std::string name = getProcMangledName (proc, converter);
1417
1464
mlir::func::FuncOp func = fir::FirOpBuilder::getNamedFunction (module, name);
1418
1465
if (func)
1419
1466
return func;
1420
1467
1421
- const Fortran::semantics::Symbol *symbol = proc.GetSymbol ();
1422
- assert (symbol && " non user function in getOrDeclareFunction" );
1423
1468
// getOrDeclareFunction is only used for functions not defined in the current
1424
1469
// program unit, so use the location of the procedure designator symbol, which
1425
1470
// is the first occurrence of the procedure in the program unit.
1426
- mlir::Location loc = converter.genLocation (symbol->name ());
1427
- std::optional<Fortran::evaluate::characteristics::Procedure> characteristics =
1428
- Fortran::evaluate::characteristics::Procedure::Characterize (
1429
- proc, converter.getFoldingContext ());
1430
- mlir::FunctionType ty = SignatureBuilder{characteristics.value (), converter,
1431
- /* forceImplicit=*/ false }
1432
- .getFunctionType ();
1433
- mlir::func::FuncOp newFunc =
1434
- fir::FirOpBuilder::createFunction (loc, module, name, ty);
1435
- addSymbolAttribute (newFunc, *symbol, converter.getMLIRContext ());
1436
- return newFunc;
1471
+ return SignatureBuilder{proc, converter}.getOrCreateFuncOp ();
1437
1472
}
1438
1473
1439
1474
// Is it required to pass a dummy procedure with \p characteristics as a tuple
0 commit comments