Skip to content

Commit 0526ce7

Browse files
vzakhariZijunZhaoCCK
authored andcommitted
[flang][hlfir] Alias analysis for host associated accesses. (llvm#65919)
This patch adds `host_assoc` attribute for operations that implement FortranVariableInterface (e.g. `hlfir.declare`). The attribute is used by the alias analysis to make better conclusions about memory overlap. For example, a dummy argument of an inner subroutine and a host's variable used inside the inner subroutine cannot refer to the same object (if the dummy argument does not satisify exceptions in F2018 15.5.2.13). This closes a performance gap between HLFIR optimization pipeline and FIR ArrayValueCopy for Polyhedron/nf.
1 parent 4a231e6 commit 0526ce7

File tree

10 files changed

+497
-23
lines changed

10 files changed

+497
-23
lines changed

flang/include/flang/Lower/ConvertVariable.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define FORTRAN_LOWER_CONVERT_VARIABLE_H
1919

2020
#include "flang/Lower/Support/Utils.h"
21+
#include "flang/Optimizer/Dialect/FIRAttr.h"
2122
#include "mlir/IR/Value.h"
2223
#include "llvm/ADT/DenseMap.h"
2324

@@ -115,15 +116,20 @@ void createRuntimeTypeInfoGlobal(Fortran::lower::AbstractConverter &converter,
115116
/// representation.
116117
fir::FortranVariableFlagsAttr
117118
translateSymbolAttributes(mlir::MLIRContext *mlirContext,
118-
const Fortran::semantics::Symbol &sym);
119+
const Fortran::semantics::Symbol &sym,
120+
fir::FortranVariableFlagsEnum extraFlags =
121+
fir::FortranVariableFlagsEnum::None);
119122

120123
/// Map a symbol to a given fir::ExtendedValue. This will generate an
121124
/// hlfir.declare when lowering to HLFIR and map the hlfir.declare result to the
122125
/// symbol.
123126
void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
124127
Fortran::lower::SymMap &symMap,
125128
const Fortran::semantics::Symbol &sym,
126-
const fir::ExtendedValue &exv, bool force = false);
129+
const fir::ExtendedValue &exv,
130+
fir::FortranVariableFlagsEnum extraFlags =
131+
fir::FortranVariableFlagsEnum::None,
132+
bool force = false);
127133

128134
/// For the given Cray pointee symbol return the corresponding
129135
/// Cray pointer symbol. Assert if the pointer symbol cannot be found.

flang/include/flang/Optimizer/Analysis/AliasAnalysis.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class AliasAnalysis {
3333
/// Memory allocated outside of a function and passed
3434
/// to the function as a by-ref argument.
3535
Argument,
36+
/// Represents memory allocated outside of a function
37+
/// and passed to the function via host association tuple.
38+
HostAssoc,
3639
/// Represents memory allocated by unknown means and
3740
/// with the memory address defined by a memory reading
3841
/// operation (e.g. fir::LoadOp).

flang/include/flang/Optimizer/Dialect/FIRAttr.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ def FIRpointer : I32BitEnumAttrCaseBit<"pointer", 9>;
3232
def FIRtarget : I32BitEnumAttrCaseBit<"target", 10>;
3333
def FIRvalue : I32BitEnumAttrCaseBit<"value", 11>;
3434
def FIRvolatile : I32BitEnumAttrCaseBit<"fortran_volatile", 12, "volatile">;
35+
def FIRHostAssoc : I32BitEnumAttrCaseBit<"host_assoc", 13>;
3536

3637
def fir_FortranVariableFlagsEnum : I32BitEnumAttr<
3738
"FortranVariableFlagsEnum",
3839
"Fortran variable attributes",
3940
[FIRnoAttributes, FIRallocatable, FIRasynchronous, FIRbind_c, FIRcontiguous,
4041
FIRintent_in, FIRintent_inout, FIRintent_out, FIRoptional, FIRparameter,
41-
FIRpointer, FIRtarget, FIRvalue, FIRvolatile]> {
42+
FIRpointer, FIRtarget, FIRvalue, FIRvolatile, FIRHostAssoc]> {
4243
let separator = ", ";
4344
let cppNamespace = "::fir";
4445
let printBitEnumPrimaryGroups = 1;

flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ def fir_FortranVariableOpInterface : OpInterface<"FortranVariableOpInterface"> {
170170
fir::FortranVariableFlagsEnum::parameter);
171171
}
172172

173+
/// Is this a host associated variable?
174+
bool isHostAssoc() {
175+
auto attrs = getFortranAttrs();
176+
return attrs && bitEnumContainsAny(*attrs,
177+
fir::FortranVariableFlagsEnum::host_assoc);
178+
}
179+
173180
/// Interface verifier imlementation for declare operations.
174181
mlir::LogicalResult verifyDeclareLikeOpImpl(mlir::Value memRef);
175182

flang/lib/Lower/Bridge.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
10181018
if (!forced && lookupSymbol(sym))
10191019
return false;
10201020
if (lowerToHighLevelFIR()) {
1021-
Fortran::lower::genDeclareSymbol(*this, localSymbols, sym, val, forced);
1021+
Fortran::lower::genDeclareSymbol(*this, localSymbols, sym, val,
1022+
fir::FortranVariableFlagsEnum::None,
1023+
forced);
10221024
} else {
10231025
localSymbols.addSymbol(sym, val, forced);
10241026
}

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,8 +1429,9 @@ recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec, mlir::Value initVal) {
14291429
}
14301430

14311431
fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
1432-
mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym) {
1433-
fir::FortranVariableFlagsEnum flags = fir::FortranVariableFlagsEnum::None;
1432+
mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym,
1433+
fir::FortranVariableFlagsEnum extraFlags) {
1434+
fir::FortranVariableFlagsEnum flags = extraFlags;
14341435
const auto &attrs = sym.attrs();
14351436
if (attrs.test(Fortran::semantics::Attr::ALLOCATABLE))
14361437
flags = flags | fir::FortranVariableFlagsEnum::allocatable;
@@ -1578,14 +1579,16 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
15781579
void Fortran::lower::genDeclareSymbol(
15791580
Fortran::lower::AbstractConverter &converter,
15801581
Fortran::lower::SymMap &symMap, const Fortran::semantics::Symbol &sym,
1581-
const fir::ExtendedValue &exv, bool force) {
1582+
const fir::ExtendedValue &exv, fir::FortranVariableFlagsEnum extraFlags,
1583+
bool force) {
15821584
if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
15831585
!Fortran::semantics::IsProcedure(sym) &&
15841586
!sym.detailsIf<Fortran::semantics::CommonBlockDetails>()) {
15851587
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
15861588
const mlir::Location loc = genLocation(converter, sym);
15871589
fir::FortranVariableFlagsAttr attributes =
1588-
Fortran::lower::translateSymbolAttributes(builder.getContext(), sym);
1590+
Fortran::lower::translateSymbolAttributes(builder.getContext(), sym,
1591+
extraFlags);
15891592
auto name = converter.mangleName(sym);
15901593
hlfir::EntityWithAttributes declare =
15911594
hlfir::genDeclare(loc, builder, exv, name, attributes);
@@ -1632,8 +1635,9 @@ static void genBoxDeclare(Fortran::lower::AbstractConverter &converter,
16321635
bool replace = false) {
16331636
if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
16341637
fir::BoxValue boxValue{box, lbounds, explicitParams, explicitExtents};
1635-
Fortran::lower::genDeclareSymbol(converter, symMap, sym,
1636-
std::move(boxValue), replace);
1638+
Fortran::lower::genDeclareSymbol(
1639+
converter, symMap, sym, std::move(boxValue),
1640+
fir::FortranVariableFlagsEnum::None, replace);
16371641
return;
16381642
}
16391643
symMap.addBoxSymbol(sym, box, lbounds, explicitParams, explicitExtents,

flang/lib/Lower/HostAssociations.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,11 @@ static void bindCapturedSymbol(const Fortran::semantics::Symbol &sym,
7373
fir::ExtendedValue val,
7474
Fortran::lower::AbstractConverter &converter,
7575
Fortran::lower::SymMap &symMap) {
76-
if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
77-
// TODO: add an indication that this is a host variable in the declare to
78-
// allow alias analysis to detect this case.
79-
Fortran::lower::genDeclareSymbol(converter, symMap, sym, val);
80-
} else {
76+
if (converter.getLoweringOptions().getLowerToHighLevelFIR())
77+
Fortran::lower::genDeclareSymbol(converter, symMap, sym, val,
78+
fir::FortranVariableFlagsEnum::host_assoc);
79+
else
8180
symMap.addSymbol(sym, val);
82-
}
8381
}
8482

8583
namespace {

flang/lib/Optimizer/Analysis/AliasAnalysis.cpp

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "flang/Optimizer/Dialect/FIROps.h"
1111
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
1212
#include "flang/Optimizer/Dialect/FIRType.h"
13+
#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
1314
#include "flang/Optimizer/HLFIR/HLFIROps.h"
1415
#include "mlir/Analysis/AliasAnalysis.h"
1516
#include "mlir/IR/BuiltinOps.h"
@@ -93,6 +94,10 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
9394
return AliasResult::MustAlias;
9495
}
9596

97+
// Two host associated accesses may overlap due to an equivalence.
98+
if (lhsSrc.kind == SourceKind::HostAssoc)
99+
return AliasResult::MayAlias;
100+
96101
// Allocate and global memory address cannot physically alias
97102
if (lhsSrc.kind == SourceKind::Allocate ||
98103
lhsSrc.kind == SourceKind::Global)
@@ -128,13 +133,37 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
128133
src2 = &lhsSrc;
129134
}
130135

131-
assert(src2->kind <= SourceKind::Argument && "unexpected memory source kind");
136+
assert(src2->kind <= SourceKind::HostAssoc &&
137+
"unexpected memory source kind");
132138
if (src1->kind == SourceKind::Allocate)
133139
return AliasResult::NoAlias;
134140

135-
assert(src1->kind == SourceKind::Global &&
136-
src2->kind == SourceKind::Argument &&
137-
"unexpected memory source kinds");
141+
assert((src1->kind == SourceKind::Global &&
142+
(src2->kind == SourceKind::Argument ||
143+
src2->kind == SourceKind::HostAssoc)) ||
144+
(src1->kind == SourceKind::Argument &&
145+
src2->kind == SourceKind::HostAssoc) &&
146+
"unexpected memory source kinds");
147+
148+
if (src1->kind == SourceKind::Argument &&
149+
src2->kind == SourceKind::HostAssoc) {
150+
// Treat the host entity as TARGET for the purpose of disambiguating
151+
// it with a dummy access. It is required for this particular case:
152+
// subroutine test
153+
// integer :: x(10)
154+
// call inner(x)
155+
// contains
156+
// subroutine inner(y)
157+
// integer, target :: y(:)
158+
// x(1) = y(1)
159+
// end subroutine inner
160+
// end subroutine test
161+
//
162+
// F18 15.5.2.13 (4) (b) allows 'x' and 'y' to address the same object.
163+
// 'y' has an explicit TARGET attribute, but 'x' has neither TARGET
164+
// nor POINTER.
165+
src2->attributes.set(Attribute::Target);
166+
}
138167

139168
// Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER.
140169
if (src1->isTargetOrPointer() && src2->isTargetOrPointer())
@@ -235,6 +264,21 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
235264
breakFromLoop = true;
236265
})
237266
.Case<hlfir::DeclareOp, fir::DeclareOp>([&](auto op) {
267+
auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
268+
if (varIf.isHostAssoc()) {
269+
// Do not track past such DeclareOp, because it does not
270+
// currently provide any useful information. The host associated
271+
// access will end up dereferencing the host association tuple,
272+
// so we may as well stop right now.
273+
v = defOp->getResult(0);
274+
// TODO: if the host associated variable is a dummy argument
275+
// of the host, I think, we can treat it as SourceKind::Argument
276+
// for the purpose of alias analysis inside the internal procedure.
277+
type = SourceKind::HostAssoc;
278+
breakFromLoop = true;
279+
return;
280+
}
281+
238282
// Track further through the operand
239283
v = op.getMemref();
240284
defOp = v.getDefiningOp();

0 commit comments

Comments
 (0)