12
12
#include " flang/Optimizer/Dialect/FIRType.h"
13
13
#include " flang/Optimizer/Dialect/FortranVariableInterface.h"
14
14
#include " flang/Optimizer/HLFIR/HLFIROps.h"
15
+ #include " flang/Optimizer/Support/InternalNames.h"
15
16
#include " mlir/Analysis/AliasAnalysis.h"
16
17
#include " mlir/Dialect/OpenMP/OpenMPDialect.h"
17
18
#include " mlir/Dialect/OpenMP/OpenMPInterfaces.h"
@@ -96,6 +97,17 @@ bool AliasAnalysis::Source::isBoxData() const {
96
97
origin.isData ;
97
98
}
98
99
100
+ bool AliasAnalysis::Source::isFortranUserVariable () const {
101
+ if (!origin.instantiationPoint )
102
+ return false ;
103
+ return llvm::TypeSwitch<mlir::Operation *, bool >(origin.instantiationPoint )
104
+ .template Case <fir::DeclareOp, hlfir::DeclareOp>([&](auto declOp) {
105
+ return fir::NameUniquer::deconstruct (declOp.getUniqName ()).first ==
106
+ fir::NameUniquer::NameKind::VARIABLE;
107
+ })
108
+ .Default ([&](auto op) { return false ; });
109
+ }
110
+
99
111
bool AliasAnalysis::Source::mayBeDummyArgOrHostAssoc () const {
100
112
return kind != SourceKind::Allocate && kind != SourceKind::Global;
101
113
}
@@ -329,14 +341,92 @@ AliasResult AliasAnalysis::alias(Source lhsSrc, Source rhsSrc, mlir::Value lhs,
329
341
// AliasAnalysis: getModRef
330
342
// ===----------------------------------------------------------------------===//
331
343
344
+ static bool isSavedLocal (const fir::AliasAnalysis::Source &src) {
345
+ if (auto symRef = llvm::dyn_cast<mlir::SymbolRefAttr>(src.origin .u )) {
346
+ auto [nameKind, deconstruct] =
347
+ fir::NameUniquer::deconstruct (symRef.getLeafReference ().getValue ());
348
+ return nameKind == fir::NameUniquer::NameKind::VARIABLE &&
349
+ !deconstruct.procs .empty ();
350
+ }
351
+ return false ;
352
+ }
353
+
354
+ static bool isCallToFortranUserProcedure (fir::CallOp call) {
355
+ // TODO: indirect calls are excluded by these checks. Maybe some attribute is
356
+ // needed to flag user calls in this case.
357
+ if (fir::hasBindcAttr (call))
358
+ return true ;
359
+ if (std::optional<mlir::SymbolRefAttr> callee = call.getCallee ())
360
+ return fir::NameUniquer::deconstruct (callee->getLeafReference ().getValue ())
361
+ .first == fir::NameUniquer::NameKind::PROCEDURE;
362
+ return false ;
363
+ }
364
+
365
+ static ModRefResult getCallModRef (fir::CallOp call, mlir::Value var) {
366
+ // TODO: limit to Fortran functions??
367
+ // 1. Detect variables that can be accessed indirectly.
368
+ fir::AliasAnalysis aliasAnalysis;
369
+ fir::AliasAnalysis::Source varSrc = aliasAnalysis.getSource (var);
370
+ // If the variable is not a user variable, we cannot safely assume that
371
+ // Fortran semantics apply (e.g., a bare alloca/allocmem result may very well
372
+ // be placed in an allocatable/pointer descriptor and escape).
373
+
374
+ // All the logic below is based on Fortran semantics and only holds if this
375
+ // is a call to a procedure from the Fortran source and this is a variable
376
+ // from the Fortran source. Compiler generated temporaries or functions may
377
+ // not adhere to this semantic.
378
+ // TODO: add some opt-in or op-out mechanism for compiler generated temps.
379
+ // An example of something currently problematic is the allocmem generated for
380
+ // ALLOCATE of allocatable target. It currently does not have the target
381
+ // attribute, which would lead this analysis to believe it cannot escape.
382
+ if (!varSrc.isFortranUserVariable () || !isCallToFortranUserProcedure (call))
383
+ return ModRefResult::getModAndRef ();
384
+ // Pointer and target may have been captured.
385
+ if (varSrc.isTargetOrPointer ())
386
+ return ModRefResult::getModAndRef ();
387
+ // Host associated variables may be addressed indirectly via an internal
388
+ // function call, whether the call is in the parent or an internal procedure.
389
+ // Note that the host associated/internal procedure may be referenced
390
+ // indirectly inside calls to non internal procedure. This is because internal
391
+ // procedures may be captured or passed. As this is tricky to analyze, always
392
+ // consider such variables may be accessed in any calls.
393
+ if (varSrc.kind == fir::AliasAnalysis::SourceKind::HostAssoc ||
394
+ varSrc.isCapturedInInternalProcedure )
395
+ return ModRefResult::getModAndRef ();
396
+ // At that stage, it has been ruled out that local (including the saved ones)
397
+ // and dummy cannot be indirectly accessed in the call.
398
+ if (varSrc.kind != fir::AliasAnalysis::SourceKind::Allocate &&
399
+ !varSrc.isDummyArgument ()) {
400
+ if (varSrc.kind != fir::AliasAnalysis::SourceKind::Global ||
401
+ !isSavedLocal (varSrc))
402
+ return ModRefResult::getModAndRef ();
403
+ }
404
+ // 2. Check if the variable is passed via the arguments.
405
+ for (auto arg : call.getArgs ()) {
406
+ if (fir::conformsWithPassByRef (arg.getType ()) &&
407
+ !aliasAnalysis.alias (arg, var).isNo ()) {
408
+ // TODO: intent(in) would allow returning Ref here. This can be obtained
409
+ // in the func.func attributes for direct calls, but the module lookup is
410
+ // linear with the number of MLIR symbols, which would introduce a pseudo
411
+ // quadratic behavior num_calls * num_func.
412
+ return ModRefResult::getModAndRef ();
413
+ }
414
+ }
415
+ // The call cannot access the variable.
416
+ return ModRefResult::getNoModRef ();
417
+ }
418
+
332
419
// / This is mostly inspired by MLIR::LocalAliasAnalysis with 2 notable
333
420
// / differences 1) Regions are not handled here but will be handled by a data
334
421
// / flow analysis to come 2) Allocate and Free effects are considered
335
422
// / modifying
336
423
ModRefResult AliasAnalysis::getModRef (Operation *op, Value location) {
337
424
MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op);
338
- if (!interface)
425
+ if (!interface) {
426
+ if (auto call = llvm::dyn_cast<fir::CallOp>(op))
427
+ return getCallModRef (call, location);
339
428
return ModRefResult::getModAndRef ();
429
+ }
340
430
341
431
// Build a ModRefResult by merging the behavior of the effects of this
342
432
// operation.
@@ -408,19 +498,20 @@ static Value getPrivateArg(omp::BlockArgOpenMPOpInterface &argIface,
408
498
}
409
499
410
500
AliasAnalysis::Source AliasAnalysis::getSource (mlir::Value v,
411
- bool getInstantiationPoint ) {
501
+ bool getLastInstantiationPoint ) {
412
502
auto *defOp = v.getDefiningOp ();
413
503
SourceKind type{SourceKind::Unknown};
414
504
mlir::Type ty;
415
505
bool breakFromLoop{false };
416
506
bool approximateSource{false };
507
+ bool isCapturedInInternalProcedure{false };
417
508
bool followBoxData{mlir::isa<fir::BaseBoxType>(v.getType ())};
418
509
bool isBoxRef{fir::isa_ref_type (v.getType ()) &&
419
510
mlir::isa<fir::BaseBoxType>(fir::unwrapRefType (v.getType ()))};
420
511
bool followingData = !isBoxRef;
421
512
mlir::SymbolRefAttr global;
422
513
Source::Attributes attributes;
423
- mlir::Value instantiationPoint;
514
+ mlir::Operation * instantiationPoint{ nullptr } ;
424
515
while (defOp && !breakFromLoop) {
425
516
ty = defOp->getResultTypes ()[0 ];
426
517
llvm::TypeSwitch<Operation *>(defOp)
@@ -548,6 +639,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
548
639
// is the only carrier of the variable attributes,
549
640
// so we have to collect them here.
550
641
attributes |= getAttrsFromVariable (varIf);
642
+ isCapturedInInternalProcedure |=
643
+ varIf.isCapturedInInternalProcedure ();
551
644
if (varIf.isHostAssoc ()) {
552
645
// Do not track past such DeclareOp, because it does not
553
646
// currently provide any useful information. The host associated
@@ -561,10 +654,10 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
561
654
breakFromLoop = true ;
562
655
return ;
563
656
}
564
- if (getInstantiationPoint ) {
657
+ if (getLastInstantiationPoint ) {
565
658
// Fetch only the innermost instantiation point.
566
659
if (!instantiationPoint)
567
- instantiationPoint = op-> getResult ( 0 ) ;
660
+ instantiationPoint = op;
568
661
569
662
if (op.getDummyScope ()) {
570
663
// Do not track past DeclareOp that has the dummy_scope
@@ -575,6 +668,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
575
668
breakFromLoop = true ;
576
669
return ;
577
670
}
671
+ } else {
672
+ instantiationPoint = op;
578
673
}
579
674
// TODO: Look for the fortran attributes present on the operation
580
675
// Track further through the operand
@@ -620,13 +715,15 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
620
715
type,
621
716
ty,
622
717
attributes,
623
- approximateSource};
718
+ approximateSource,
719
+ isCapturedInInternalProcedure};
624
720
}
625
721
return {{v, instantiationPoint, followingData},
626
722
type,
627
723
ty,
628
724
attributes,
629
- approximateSource};
725
+ approximateSource,
726
+ isCapturedInInternalProcedure};
630
727
}
631
728
632
729
} // namespace fir
0 commit comments