@@ -534,6 +534,16 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
534534 mlir::SymbolRefAttr global;
535535 Source::Attributes attributes;
536536 mlir::Operation *instantiationPoint{nullptr };
537+ // Helper to conservatively classify a candidate value as coming from a
538+ // dummy argument or as indirect when no allocation or global can be proven.
539+ auto classifyFallbackFrom = [&](mlir::Value candidate) {
540+ if (isDummyArgument (candidate)) {
541+ defOp = nullptr ;
542+ v = candidate;
543+ } else {
544+ type = SourceKind::Indirect;
545+ }
546+ };
537547 while (defOp && !breakFromLoop) {
538548 ty = defOp->getResultTypes ()[0 ];
539549
@@ -578,22 +588,14 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
578588 defOp = v.getDefiningOp ();
579589 })
580590 .Case <hlfir::AssociateOp>([&](auto op) {
591+ // Do not pattern-match Allocate. Trace through the source.
581592 mlir::Value source = op.getSource ();
582- if (fir::isa_trivial (source.getType ())) {
583- // Trivial values will always use distinct temp memory,
584- // so we can classify this as Allocate and stop.
585- type = SourceKind::Allocate;
586- breakFromLoop = true ;
587- } else {
588- // AssociateOp may reuse the expression storage,
589- // so we have to trace further.
590- v = source;
591- defOp = v.getDefiningOp ();
592- }
593+ v = source;
594+ defOp = v.getDefiningOp ();
593595 })
594596 .Case <fir::AllocaOp, fir::AllocMemOp>([&](auto op) {
595- // Unique memory allocation.
596- type = SourceKind::Allocate;
597+ // Do not pattern-match allocations by op name; rely on memory
598+ // effects classification above. Nothing to do here.
597599 breakFromLoop = true ;
598600 })
599601 .Case <fir::ConvertOp>([&](auto op) {
@@ -665,17 +667,60 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
665667 type = SourceKind::Global;
666668 } else {
667669 auto def = llvm::cast<mlir::Value>(boxSrc.origin .u );
668- // TODO: Add support to fir.allocmem
669- if (auto allocOp = def.template getDefiningOp <fir::AllocaOp>()) {
670- v = def;
671- defOp = v.getDefiningOp ();
672- type = SourceKind::Allocate;
673- } else if (isDummyArgument (def)) {
674- defOp = nullptr ;
675- v = def;
676- } else {
677- type = SourceKind::Indirect;
670+ bool classified = false ;
671+ if (auto defDefOp = def.getDefiningOp ()) {
672+ if (auto defIface =
673+ llvm::dyn_cast<mlir::MemoryEffectOpInterface>(defDefOp)) {
674+ llvm::SmallVector<mlir::MemoryEffects::EffectInstance, 4 > eff;
675+ defIface.getEffects (eff);
676+ // Prefer value-scoped Allocate on the underlying storage.
677+ for (auto &e : eff) {
678+ if (mlir::isa<mlir::MemoryEffects::Allocate>(e.getEffect ()) &&
679+ e.getValue () && e.getValue () == def) {
680+ v = def;
681+ defOp = v.getDefiningOp ();
682+ type = SourceKind::Allocate;
683+ classified = true ;
684+ break ;
685+ }
686+ }
687+ // Heuristic for op-scoped Allocate at the underlying defining op.
688+ if (!classified) {
689+ bool sawOpScopedAlloc = llvm::any_of (
690+ eff, [](auto &e) {
691+ return !e.getValue () &&
692+ mlir::isa<mlir::MemoryEffects::Allocate>(
693+ e.getEffect ());
694+ });
695+ if (sawOpScopedAlloc) {
696+ auto isMemoryRefLikeType = [](mlir::Type t) {
697+ return fir::isa_ref_type (t) ||
698+ mlir::isa<mlir::BaseMemRefType>(t) ||
699+ mlir::isa<mlir::LLVM::LLVMPointerType>(t);
700+ };
701+ bool opIsViewLike = (bool )mlir::dyn_cast_or_null<
702+ mlir::ViewLikeOpInterface>(defDefOp);
703+ bool hasMemOperands = llvm::any_of (
704+ defDefOp->getOperands (), [&](mlir::Value opnd) {
705+ return isMemoryRefLikeType (opnd.getType ());
706+ });
707+ if (!opIsViewLike && !hasMemOperands) {
708+ for (mlir::Value res : defDefOp->getResults ()) {
709+ if (res == def && isMemoryRefLikeType (res.getType ())) {
710+ v = def;
711+ defOp = v.getDefiningOp ();
712+ type = SourceKind::Allocate;
713+ classified = true ;
714+ break ;
715+ }
716+ }
717+ }
718+ }
719+ }
720+ }
678721 }
722+ if (!classified)
723+ classifyFallbackFrom (def);
679724 }
680725 breakFromLoop = true ;
681726 return ;
0 commit comments