Skip to content

Commit bd3e3db

Browse files
committed
[NFC][flang] Introduce FortranObjectViewOpInterface.
This patch adds initial version of `FortranObjectViewOpInterface` that helps walking def-use chains containing "pass-through" operations (like `fir.convert`, etc.). The new interface is used in FIR AliasAnalysis to demonstrate potential usage (I know we have such walks elsewhere in Flang, but I am only changing FIR AliasAnalysis in this patch). This is an NFC change. I noticed that if I remove followBoxData code there are no failing LIT tests, but I decided to keep it in order to keep the change looking more like NFC. This change is a follow-up on the discussion in #164020: it is unclear if the `FortranObjectViewOpInterface` methods and their usage, as in this patch, apply to the ViewLike operations that use the core MLIR `ViewLikeOpInterface`. So this patch is the path towards simplifying Flang code while also enabling a future discussion about having such an interface in core MLIR.
1 parent 97d50b5 commit bd3e3db

File tree

6 files changed

+230
-62
lines changed

6 files changed

+230
-62
lines changed

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,8 @@ def fir_HasValueOp : fir_Op<"has_value", [Terminator, HasParent<"GlobalOp">]> {
806806
// Operations on !fir.box<T> type objects
807807
//===----------------------------------------------------------------------===//
808808

809-
def fir_EmboxOp : fir_Op<"embox", [NoMemoryEffect, AttrSizedOperandSegments]> {
809+
def fir_EmboxOp : fir_Op<"embox", [NoMemoryEffect, AttrSizedOperandSegments,
810+
fir_FortranObjectViewOpInterface]> {
810811
let summary = "boxes a given reference and (optional) dimension information";
811812

812813
let description = [{
@@ -870,10 +871,14 @@ def fir_EmboxOp : fir_Op<"embox", [NoMemoryEffect, AttrSizedOperandSegments]> {
870871
return 1 + (getShape() ? 1 : 0) + (getSlice() ? 1 : 0)
871872
+ numLenParams();
872873
}
874+
// FortranObjectViewOpInterface methods:
875+
mlir::Value getViewSource(mlir::OpResult) { return getMemref(); }
876+
std::optional<std::int64_t> getViewOffset(mlir::OpResult);
873877
}];
874878
}
875879

876-
def fir_ReboxOp : fir_Op<"rebox", [NoMemoryEffect, AttrSizedOperandSegments]> {
880+
def fir_ReboxOp : fir_Op<"rebox", [NoMemoryEffect, AttrSizedOperandSegments,
881+
fir_FortranObjectViewOpInterface]> {
877882
let summary =
878883
"create a box given another box and (optional) dimension information";
879884

@@ -923,6 +928,12 @@ def fir_ReboxOp : fir_Op<"rebox", [NoMemoryEffect, AttrSizedOperandSegments]> {
923928
}];
924929

925930
let hasVerifier = 1;
931+
932+
let extraClassDeclaration = [{
933+
// FortranObjectViewOpInterface methods:
934+
mlir::Value getViewSource(mlir::OpResult) { return getBox(); }
935+
std::optional<std::int64_t> getViewOffset(mlir::OpResult);
936+
}];
926937
}
927938

928939
def fir_ReboxAssumedRankOp : fir_Op<"rebox_assumed_rank",
@@ -1071,7 +1082,9 @@ def fir_UnboxProcOp : fir_SimpleOp<"unboxproc", [NoMemoryEffect]> {
10711082
let results = (outs FunctionType, fir_ReferenceType:$refTuple);
10721083
}
10731084

1074-
def fir_BoxAddrOp : fir_SimpleOneResultOp<"box_addr", [NoMemoryEffect]> {
1085+
def fir_BoxAddrOp
1086+
: fir_SimpleOneResultOp<"box_addr", [NoMemoryEffect,
1087+
fir_FortranObjectViewOpInterface]> {
10751088
let summary = "return a memory reference to the boxed value";
10761089

10771090
let description = [{
@@ -1094,6 +1107,12 @@ def fir_BoxAddrOp : fir_SimpleOneResultOp<"box_addr", [NoMemoryEffect]> {
10941107
let hasFolder = 1;
10951108

10961109
let builders = [OpBuilder<(ins "mlir::Value":$val)>];
1110+
1111+
let extraClassDeclaration = [{
1112+
// FortranObjectViewOpInterface methods:
1113+
mlir::Value getViewSource(mlir::OpResult) { return getVal(); }
1114+
std::optional<std::int64_t> getViewOffset(mlir::OpResult);
1115+
}];
10971116
}
10981117

10991118
def fir_BoxCharLenOp : fir_SimpleOp<"boxchar_len", [NoMemoryEffect]> {
@@ -1766,8 +1785,9 @@ def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store",
17661785
// Record and array type operations
17671786
//===----------------------------------------------------------------------===//
17681787

1769-
def fir_ArrayCoorOp : fir_Op<"array_coor",
1770-
[NoMemoryEffect, AttrSizedOperandSegments]> {
1788+
def fir_ArrayCoorOp
1789+
: fir_Op<"array_coor", [NoMemoryEffect, AttrSizedOperandSegments,
1790+
fir_FortranObjectViewOpInterface]> {
17711791

17721792
let summary = "Find the coordinate of an element of an array";
17731793

@@ -1810,9 +1830,16 @@ def fir_ArrayCoorOp : fir_Op<"array_coor",
18101830

18111831
let hasVerifier = 1;
18121832
let hasCanonicalizer = 1;
1833+
let extraClassDeclaration = [{
1834+
// FortranObjectViewOpInterface methods:
1835+
mlir::Value getViewSource(mlir::OpResult) { return getMemref(); }
1836+
std::optional<std::int64_t> getViewOffset(mlir::OpResult);
1837+
}];
18131838
}
18141839

1815-
def fir_CoordinateOp : fir_Op<"coordinate_of", [NoMemoryEffect]> {
1840+
def fir_CoordinateOp
1841+
: fir_Op<"coordinate_of", [NoMemoryEffect,
1842+
fir_FortranObjectViewOpInterface]> {
18161843

18171844
let summary = "Finds the coordinate (location) of a value in memory";
18181845

@@ -1864,6 +1891,10 @@ def fir_CoordinateOp : fir_Op<"coordinate_of", [NoMemoryEffect]> {
18641891
let extraClassDeclaration = [{
18651892
constexpr static int32_t kDynamicIndex = std::numeric_limits<int32_t>::min();
18661893
CoordinateIndicesAdaptor getIndices();
1894+
1895+
// FortranObjectViewOpInterface methods:
1896+
mlir::Value getViewSource(mlir::OpResult) { return getRef(); }
1897+
std::optional<std::int64_t> getViewOffset(mlir::OpResult);
18671898
}];
18681899
}
18691900

@@ -2830,7 +2861,8 @@ def fir_VolatileCastOp : fir_SimpleOneResultOp<"volatile_cast", [Pure]> {
28302861
}
28312862

28322863
def fir_ConvertOp
2833-
: fir_SimpleOneResultOp<"convert", [NoMemoryEffect, ViewLikeOpInterface]> {
2864+
: fir_SimpleOneResultOp<"convert", [NoMemoryEffect, ViewLikeOpInterface,
2865+
fir_FortranObjectViewOpInterface]> {
28342866
let summary = "encapsulates all Fortran entity type conversions";
28352867

28362868
let description = [{
@@ -2868,7 +2900,13 @@ def fir_ConvertOp
28682900
static bool isPointerCompatible(mlir::Type ty);
28692901
static bool canBeConverted(mlir::Type inType, mlir::Type outType);
28702902
static bool areVectorsCompatible(mlir::Type inTy, mlir::Type outTy);
2903+
2904+
// ViewLikeOpInterface methods:
28712905
mlir::Value getViewSource() { return getValue(); }
2906+
2907+
// FortranObjectViewOpInterface methods:
2908+
mlir::Value getViewSource(mlir::OpResult) { return getValue(); }
2909+
std::optional<std::int64_t> getViewOffset(mlir::OpResult) { return 0; }
28722910
}];
28732911
let hasCanonicalizer = 1;
28742912
}
@@ -3221,7 +3259,8 @@ def fir_DeclareOp
32213259
: fir_Op<"declare", [AttrSizedOperandSegments,
32223260
MemoryEffects<[MemAlloc<DebuggingResource>]>,
32233261
DeclareOpInterfaceMethods<
3224-
fir_FortranVariableStorageOpInterface>]> {
3262+
fir_FortranVariableStorageOpInterface>,
3263+
fir_FortranObjectViewOpInterface]> {
32253264
let summary = "declare a variable";
32263265

32273266
let description = [{
@@ -3285,6 +3324,12 @@ def fir_DeclareOp
32853324
attr-dict `:` functional-type(operands, results)
32863325
}];
32873326

3327+
let extraClassDeclaration = [{
3328+
// FortranObjectViewOpInterface methods:
3329+
mlir::Value getViewSource(mlir::OpResult) { return getMemref(); }
3330+
std::optional<std::int64_t> getViewOffset(mlir::OpResult) { return 0; }
3331+
}];
3332+
32883333
let hasVerifier = 1;
32893334
}
32903335

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,4 +265,59 @@ def fir_FortranVariableStorageOpInterface
265265
[{ return detail::verifyFortranVariableStorageOpInterface($_op); }];
266266
}
267267

268+
def fir_FortranObjectViewOpInterface
269+
: OpInterface<"FortranObjectViewOpInterface"> {
270+
let description = [{
271+
Interface for operations that may produce results that allow accessing
272+
objects in memory based on the operands of these operations.
273+
For example:
274+
```
275+
%0 = fir.convert %x : (!llvm.ptr) -> !fir.llvm_ptr<i32>
276+
```
277+
When the result of `fir.convert` is used to access an object in memory,
278+
FIR alias analysis may want to pass through `fir.convert` to be able
279+
to find the original Fortran object that is being accessed.
280+
This interface provides methods that allow discovering information
281+
about the accessed object and the characteristics of the resulting
282+
"view" of the object, e.g. whether the result and the input
283+
access the object from the same location within the object or
284+
whether they are offsetted (which may happen, for example, in case of
285+
`fir.array_coor` operation).
286+
}];
287+
let cppNamespace = "::fir";
288+
289+
let methods =
290+
[InterfaceMethod<
291+
/*desc=*/
292+
[{ Returns the operand which the given OpResult is based on. }],
293+
/*retTy=*/"::mlir::Value",
294+
/*methodName=*/"getViewSource",
295+
/*args=*/(ins "::mlir::OpResult":$resultView),
296+
/*methodBody=*/"",
297+
/*defaultImplementation=*/[{
298+
assert($_op.getOperation() == resultView.getOwner() &&
299+
"resultView must be a result of this operation");
300+
return $_op.getViewSource(resultView);
301+
}]>,
302+
InterfaceMethod<
303+
/*desc=*/[{
304+
Returns the constant offset (in bytes) applied to the corresponding
305+
operand to produce the resulting view.
306+
If it is not possible to identify the constant offset,
307+
the result in nullopt.
308+
Note that the offset may be negative, e.g. when addressing
309+
an array section with a negative stride.
310+
}],
311+
/*retTy=*/"std::optional<std::int64_t>",
312+
/*methodName=*/"getViewOffset",
313+
/*args=*/(ins "::mlir::OpResult":$resultView),
314+
/*methodBody=*/"",
315+
/*defaultImplementation=*/[{
316+
assert($_op.getOperation() == resultView.getOwner() &&
317+
"resultView must be a result of this operation");
318+
return $_op.getViewOffset(resultView);
319+
}]>,
320+
];
321+
}
322+
268323
#endif // FORTRANVARIABLEINTERFACE

flang/include/flang/Optimizer/HLFIR/HLFIROps.td

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ def hlfir_DeclareOp
3939
: hlfir_Op<"declare", [AttrSizedOperandSegments,
4040
MemoryEffects<[MemAlloc<DebuggingResource>]>,
4141
DeclareOpInterfaceMethods<
42-
fir_FortranVariableStorageOpInterface>]> {
42+
fir_FortranVariableStorageOpInterface>,
43+
fir_FortranObjectViewOpInterface]> {
4344
let summary = "declare a variable and produce an SSA value that can be used as a variable in HLFIR operations";
4445

4546
let description = [{
@@ -140,6 +141,10 @@ def hlfir_DeclareOp
140141
/// Given a FIR memory type, and information about non default lower
141142
/// bounds, get the related HLFIR variable type.
142143
static mlir::Type getHLFIRVariableType(mlir::Type type, bool hasLowerBounds);
144+
145+
// FortranObjectViewOpInterface methods:
146+
mlir::Value getViewSource(mlir::OpResult) { return getMemref(); }
147+
std::optional<std::int64_t> getViewOffset(mlir::OpResult) { return 0; }
143148
}];
144149

145150
let hasVerifier = 1;
@@ -213,8 +218,11 @@ def fir_AssignOp : hlfir_Op<"assign", [DeclareOpInterfaceMethods<MemoryEffectsOp
213218
let hasVerifier = 1;
214219
}
215220

216-
def hlfir_DesignateOp : hlfir_Op<"designate", [AttrSizedOperandSegments,
217-
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>, NoMemoryEffect]> {
221+
def hlfir_DesignateOp
222+
: hlfir_Op<"designate",
223+
[AttrSizedOperandSegments,
224+
DeclareOpInterfaceMethods<fir_FortranVariableOpInterface>,
225+
NoMemoryEffect, fir_FortranObjectViewOpInterface]> {
218226
let summary = "Designate a Fortran variable";
219227

220228
let description = [{
@@ -278,6 +286,9 @@ def hlfir_DesignateOp : hlfir_Op<"designate", [AttrSizedOperandSegments,
278286
void setFortranAttrs(fir::FortranVariableFlagsEnum flags) {
279287
this->setFortranAttrs(std::optional<fir::FortranVariableFlagsEnum>(flags));
280288
}
289+
// FortranObjectViewOpInterface methods:
290+
mlir::Value getViewSource(mlir::OpResult) { return getMemref(); }
291+
std::optional<std::int64_t> getViewOffset(mlir::OpResult);
281292
}];
282293

283294
let builders = [
@@ -938,8 +949,9 @@ def hlfir_EndAssociateOp : hlfir_Op<"end_associate", [MemoryEffects<[MemFree]>]>
938949
let hasVerifier = 1;
939950
}
940951

941-
def hlfir_AsExprOp : hlfir_Op<"as_expr",
942-
[DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
952+
def hlfir_AsExprOp
953+
: hlfir_Op<"as_expr", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
954+
fir_FortranObjectViewOpInterface]> {
943955
let summary = "Take the value of an array, character or derived variable";
944956

945957
let description = [{
@@ -961,8 +973,11 @@ def hlfir_AsExprOp : hlfir_Op<"as_expr",
961973
let results = (outs hlfir_ExprType);
962974

963975
let extraClassDeclaration = [{
964-
// Is this a "move" ?
965-
bool isMove() { return getMustFree() != mlir::Value{}; }
976+
// Is this a "move" ?
977+
bool isMove() { return getMustFree() != mlir::Value{}; }
978+
// FortranObjectViewOpInterface methods:
979+
mlir::Value getViewSource(mlir::OpResult) { return getVar(); }
980+
std::optional<std::int64_t> getViewOffset(mlir::OpResult) { return 0; }
966981
}];
967982

968983
let assemblyFormat = [{

0 commit comments

Comments
 (0)