================ @@ -329,14 +341,92 @@ AliasResult AliasAnalysis::alias(Source lhsSrc, Source rhsSrc, mlir::Value lhs, // AliasAnalysis: getModRef //===----------------------------------------------------------------------===// +static bool isSavedLocal(const fir::AliasAnalysis::Source &src) { + if (auto symRef = llvm::dyn_cast<mlir::SymbolRefAttr>(src.origin.u)) { + auto [nameKind, deconstruct] = + fir::NameUniquer::deconstruct(symRef.getLeafReference().getValue()); + return nameKind == fir::NameUniquer::NameKind::VARIABLE && + !deconstruct.procs.empty(); + } + return false; +} + +static bool isCallToFortranUserProcedure(fir::CallOp call) { + // TODO: indirect calls are excluded by these checks. Maybe some attribute is + // needed to flag user calls in this case. + if (fir::hasBindcAttr(call)) + return true; + if (std::optional<mlir::SymbolRefAttr> callee = call.getCallee()) + return fir::NameUniquer::deconstruct(callee->getLeafReference().getValue()) + .first == fir::NameUniquer::NameKind::PROCEDURE; + return false; +} + +static ModRefResult getCallModRef(fir::CallOp call, mlir::Value var) { + // TODO: limit to Fortran functions?? + // 1. Detect variables that can be accessed indirectly. + fir::AliasAnalysis aliasAnalysis; + fir::AliasAnalysis::Source varSrc = aliasAnalysis.getSource(var); + // If the variable is not a user variable, we cannot safely assume that + // Fortran semantics apply (e.g., a bare alloca/allocmem result may very well + // be placed in an allocatable/pointer descriptor and escape). + + // All the logic bellows are based on Fortran semantics and only holds if this + // is a call to a procedure form the Fortran source and this is a variable + // from the Fortran source. Compiler generated temporaries or functions may + // not adhere to this semantic. + // TODO: add some opt-in or op-out mechanism for compiler generated temps. + // An example of something currently problematic is the allocmem generated for + // ALLOCATE of allocatable target. It currently does not have the target + // attribute, which would lead this analysis to believe it cannot escape. + if (!varSrc.isFortranUserVariable() || !isCallToFortranUserProcedure(call)) + return ModRefResult::getModAndRef(); + // Pointer and target may have been captured. + if (varSrc.isTargetOrPointer()) + return ModRefResult::getModAndRef(); + // Host associated variables may be addressed indirectly via an internal + // function call, whether the call is in the parent or an internal procedure. + // Note that the host associated/internal procedure may be referenced + // indirectly inside calls to non internal procedure. This is because internal + // procedures may be captured or passed. As this is tricky to analyze, always + // consider such variables may be accessed in any calls. + if (varSrc.kind == fir::AliasAnalysis::SourceKind::HostAssoc || + varSrc.isCapturedInInternalProcedure) + return ModRefResult::getModAndRef(); + // At that stage, it has been ruled out that local (including the saved ones) + // and dummy cannot be indirectly accessed in the call. + if (varSrc.kind != fir::AliasAnalysis::SourceKind::Allocate && + !varSrc.isDummyArgument()) { + if (varSrc.kind != fir::AliasAnalysis::SourceKind::Global || + !isSavedLocal(varSrc)) + return ModRefResult::getModAndRef(); + } + // 2. Check if the variable is passed via the arguments. + for (auto arg : call.getArgs()) { + if (fir::conformsWithPassByRef(arg.getType()) && + !aliasAnalysis.alias(arg, var).isNo()) { + // TODO: intent(in) would allow returning Ref here. This can be obtained + // in the func.func attributes for direct calls, but the module lookup is + // linear with the number of MLIR symbols, which would introduce a pseudo + // quadratic behavior num_calls * num_func. ---------------- tblah wrote:
That sounds great! https://github.com/llvm/llvm-project/pull/117164 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits