Skip to content

Commit be717af

Browse files
authored
[NFC][flang] Introduce FortranObjectViewOpInterface. (#166841)
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 83118de commit be717af

File tree

6 files changed

+230
-58
lines changed

6 files changed

+230
-58
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 = [{
@@ -3286,6 +3325,12 @@ def fir_DeclareOp
32863325
attr-dict `:` functional-type(operands, results)
32873326
}];
32883327

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

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 is 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: 19 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 = [{
@@ -141,6 +142,10 @@ def hlfir_DeclareOp
141142
/// Given a FIR memory type, and information about non default lower
142143
/// bounds, get the related HLFIR variable type.
143144
static mlir::Type getHLFIRVariableType(mlir::Type type, bool hasLowerBounds);
145+
146+
// FortranObjectViewOpInterface methods:
147+
mlir::Value getViewSource(mlir::OpResult) { return getMemref(); }
148+
std::optional<std::int64_t> getViewOffset(mlir::OpResult) { return 0; }
144149
}];
145150

146151
let hasVerifier = 1;
@@ -214,8 +219,11 @@ def fir_AssignOp : hlfir_Op<"assign", [DeclareOpInterfaceMethods<MemoryEffectsOp
214219
let hasVerifier = 1;
215220
}
216221

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

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

284295
let builders = [
@@ -939,8 +950,9 @@ def hlfir_EndAssociateOp : hlfir_Op<"end_associate", [MemoryEffects<[MemFree]>]>
939950
let hasVerifier = 1;
940951
}
941952

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

946958
let description = [{
@@ -962,8 +974,8 @@ def hlfir_AsExprOp : hlfir_Op<"as_expr",
962974
let results = (outs hlfir_ExprType);
963975

964976
let extraClassDeclaration = [{
965-
// Is this a "move" ?
966-
bool isMove() { return getMustFree() != mlir::Value{}; }
977+
// Is this a "move" ?
978+
bool isMove() { return getMustFree() != mlir::Value{}; }
967979
}];
968980

969981
let assemblyFormat = [{

0 commit comments

Comments
 (0)