-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[flang] handle fir.call in AliasAnalysis::getModRef #117164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
#include "flang/Optimizer/Dialect/FIRType.h" | ||
#include "flang/Optimizer/Dialect/FortranVariableInterface.h" | ||
#include "flang/Optimizer/HLFIR/HLFIROps.h" | ||
#include "flang/Optimizer/Support/InternalNames.h" | ||
#include "mlir/Analysis/AliasAnalysis.h" | ||
#include "mlir/Dialect/OpenMP/OpenMPDialect.h" | ||
#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h" | ||
|
@@ -96,6 +97,17 @@ bool AliasAnalysis::Source::isBoxData() const { | |
origin.isData; | ||
} | ||
|
||
bool AliasAnalysis::Source::isFortranUserVariable() const { | ||
if (!origin.instantiationPoint) | ||
return false; | ||
return llvm::TypeSwitch<mlir::Operation *, bool>(origin.instantiationPoint) | ||
.template Case<fir::DeclareOp, hlfir::DeclareOp>([&](auto declOp) { | ||
return fir::NameUniquer::deconstruct(declOp.getUniqName()).first == | ||
fir::NameUniquer::NameKind::VARIABLE; | ||
}) | ||
.Default([&](auto op) { return false; }); | ||
} | ||
|
||
bool AliasAnalysis::Source::mayBeDummyArgOrHostAssoc() const { | ||
return kind != SourceKind::Allocate && kind != SourceKind::Global; | ||
} | ||
|
@@ -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 | ||
jeanPerier marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// 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. | ||
Comment on lines
+408
to
+411
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe lookups in an It is fine by me to leave this as a TODO in this PR and only attempt this if the optimization turns out to be useful on some real code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Makes some sense to me. The only limitation I see here is that any changes to the ModuleOp symbols (name change/new functions) would not propagate to it, so fir::AliasAnalysis users would have to ensure they do not modify symbols during the lifetime of the AliasAnalysis object (or to somehow update the symbol table too). I am planning to chase the moduleOp lookups at some point and try to think of a way to keep and maintain symbol tables in the pipeline. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That sounds great! |
||
return ModRefResult::getModAndRef(); | ||
} | ||
} | ||
// The call cannot access the variable. | ||
return ModRefResult::getNoModRef(); | ||
} | ||
|
||
/// This is mostly inspired by MLIR::LocalAliasAnalysis with 2 notable | ||
/// differences 1) Regions are not handled here but will be handled by a data | ||
/// flow analysis to come 2) Allocate and Free effects are considered | ||
/// modifying | ||
ModRefResult AliasAnalysis::getModRef(Operation *op, Value location) { | ||
MemoryEffectOpInterface interface = dyn_cast<MemoryEffectOpInterface>(op); | ||
if (!interface) | ||
if (!interface) { | ||
if (auto call = llvm::dyn_cast<fir::CallOp>(op)) | ||
return getCallModRef(call, location); | ||
return ModRefResult::getModAndRef(); | ||
} | ||
|
||
// Build a ModRefResult by merging the behavior of the effects of this | ||
// operation. | ||
|
@@ -408,19 +498,20 @@ static Value getPrivateArg(omp::BlockArgOpenMPOpInterface &argIface, | |
} | ||
|
||
AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, | ||
bool getInstantiationPoint) { | ||
bool getLastInstantiationPoint) { | ||
auto *defOp = v.getDefiningOp(); | ||
SourceKind type{SourceKind::Unknown}; | ||
mlir::Type ty; | ||
bool breakFromLoop{false}; | ||
bool approximateSource{false}; | ||
bool isCapturedInInternalProcedure{false}; | ||
bool followBoxData{mlir::isa<fir::BaseBoxType>(v.getType())}; | ||
bool isBoxRef{fir::isa_ref_type(v.getType()) && | ||
mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(v.getType()))}; | ||
bool followingData = !isBoxRef; | ||
mlir::SymbolRefAttr global; | ||
Source::Attributes attributes; | ||
mlir::Value instantiationPoint; | ||
mlir::Operation *instantiationPoint{nullptr}; | ||
while (defOp && !breakFromLoop) { | ||
ty = defOp->getResultTypes()[0]; | ||
llvm::TypeSwitch<Operation *>(defOp) | ||
|
@@ -548,6 +639,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, | |
// is the only carrier of the variable attributes, | ||
// so we have to collect them here. | ||
attributes |= getAttrsFromVariable(varIf); | ||
isCapturedInInternalProcedure |= | ||
varIf.isCapturedInInternalProcedure(); | ||
if (varIf.isHostAssoc()) { | ||
// Do not track past such DeclareOp, because it does not | ||
// currently provide any useful information. The host associated | ||
|
@@ -561,10 +654,10 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, | |
breakFromLoop = true; | ||
return; | ||
} | ||
if (getInstantiationPoint) { | ||
if (getLastInstantiationPoint) { | ||
// Fetch only the innermost instantiation point. | ||
if (!instantiationPoint) | ||
instantiationPoint = op->getResult(0); | ||
instantiationPoint = op; | ||
|
||
if (op.getDummyScope()) { | ||
// Do not track past DeclareOp that has the dummy_scope | ||
|
@@ -575,6 +668,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, | |
breakFromLoop = true; | ||
return; | ||
} | ||
} else { | ||
instantiationPoint = op; | ||
} | ||
// TODO: Look for the fortran attributes present on the operation | ||
// Track further through the operand | ||
|
@@ -620,13 +715,15 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, | |
type, | ||
ty, | ||
attributes, | ||
approximateSource}; | ||
approximateSource, | ||
isCapturedInInternalProcedure}; | ||
} | ||
return {{v, instantiationPoint, followingData}, | ||
type, | ||
ty, | ||
attributes, | ||
approximateSource}; | ||
approximateSource, | ||
isCapturedInInternalProcedure}; | ||
} | ||
|
||
} // namespace fir |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ add_flang_library(FIRAnalysis | |
|
||
DEPENDS | ||
FIRDialect | ||
FIRSupport | ||
HLFIRDialect | ||
MLIRIR | ||
MLIROpenMPDialect | ||
|
Uh oh!
There was an error while loading. Please reload this page.