Skip to content

Commit 5a636c6

Browse files
authored
[mlir][LocalAliasAnalysis] Check for memref.distinct_objects in LocalAliasAnalysis (llvm#161533)
Continuation of llvm#156913, I'm planning to use it to infer LLVM alias scope attributes. * Introduce `DistinctObjectsTrait` so analysis won't need to depend on memref dialect directly. * Check the trairin `LocalAliasAnalysis::aliasImpl`.
1 parent b176efe commit 5a636c6

File tree

5 files changed

+81
-0
lines changed

5 files changed

+81
-0
lines changed

mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ def AssumeAlignmentOp : MemRef_Op<"assume_alignment", [
184184

185185
def DistinctObjectsOp : MemRef_Op<"distinct_objects", [
186186
Pure,
187+
DistinctObjectsTrait,
187188
DeclareOpInterfaceMethods<InferTypeOpInterface>
188189
// ViewLikeOpInterface TODO: ViewLikeOpInterface only supports a single argument
189190
]> {

mlir/include/mlir/Interfaces/ViewLikeInterface.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,22 @@ LogicalResult verifyListOfOperandsOrIntegers(Operation *op, StringRef name,
230230
ArrayRef<int64_t> attr,
231231
ValueRange values);
232232

233+
namespace OpTrait {
234+
/// This trai indicates that pointer-like objects (such as memrefs) returned
235+
/// from this operation will never alias with each other. This provides a
236+
/// guarantee to optimization passes that accesses through different results
237+
/// of this operation can be safely reordered, as they will never reference
238+
/// overlapping memory locations.
239+
///
240+
/// Operations with this trait take multiple pointer-like operands
241+
/// and return the same operands with additional non-aliasing guarantees.
242+
/// If the access to the results of this operation aliases at runtime, the
243+
/// behavior of such access is undefined.
244+
template <typename ConcreteType>
245+
class DistinctObjectsTrait
246+
: public TraitBase<ConcreteType, DistinctObjectsTrait> {};
247+
} // namespace OpTrait
248+
233249
} // namespace mlir
234250

235251
#endif // MLIR_INTERFACES_VIEWLIKEINTERFACE_H_

mlir/include/mlir/Interfaces/ViewLikeInterface.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,4 +414,16 @@ def OffsetSizeAndStrideOpInterface : OpInterface<"OffsetSizeAndStrideOpInterface
414414
}];
415415
}
416416

417+
// This trai indicates that pointer-like objects (such as memrefs) returned
418+
// from this operation will never alias with each other. This provides a
419+
// guarantee to optimization passes that accesses through different results
420+
// of this operation can be safely reordered, as they will never reference
421+
// overlapping memory locations.
422+
//
423+
// Operations with this trait take multiple pointer-like operands
424+
// and return the same operands with additional non-aliasing guarantees.
425+
// If the access to the results of this operation aliases at runtime, the
426+
// behavior of such access is undefined.
427+
def DistinctObjectsTrait : NativeOpTrait<"DistinctObjectsTrait">;
428+
417429
#endif // MLIR_INTERFACES_VIEWLIKEINTERFACE

mlir/lib/Analysis/AliasAnalysis/LocalAliasAnalysis.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,39 @@ getAllocEffectFor(Value value,
258258
return success();
259259
}
260260

261+
static Operation *isDistinctObjectsOp(Operation *op) {
262+
if (op && op->hasTrait<OpTrait::DistinctObjectsTrait>())
263+
return op;
264+
265+
return nullptr;
266+
}
267+
268+
static Value getDistinctObjectsOperand(Operation *op, Value value) {
269+
unsigned argNumber = cast<OpResult>(value).getResultNumber();
270+
return op->getOperand(argNumber);
271+
}
272+
273+
static std::optional<AliasResult> checkDistinctObjects(Value lhs, Value rhs) {
274+
// We should already checked that lhs and rhs are different.
275+
assert(lhs != rhs && "lhs and rhs must be different");
276+
277+
// Result and corresponding operand must alias.
278+
auto lhsOp = isDistinctObjectsOp(lhs.getDefiningOp());
279+
if (lhsOp && getDistinctObjectsOperand(lhsOp, lhs) == rhs)
280+
return AliasResult::MustAlias;
281+
282+
auto rhsOp = isDistinctObjectsOp(rhs.getDefiningOp());
283+
if (rhsOp && getDistinctObjectsOperand(rhsOp, rhs) == lhs)
284+
return AliasResult::MustAlias;
285+
286+
// If two different values come from the same `DistinctObjects` operation,
287+
// they don't alias.
288+
if (lhsOp && lhsOp == rhsOp)
289+
return AliasResult::NoAlias;
290+
291+
return std::nullopt;
292+
}
293+
261294
/// Given the two values, return their aliasing behavior.
262295
AliasResult LocalAliasAnalysis::aliasImpl(Value lhs, Value rhs) {
263296
if (lhs == rhs)
@@ -289,6 +322,9 @@ AliasResult LocalAliasAnalysis::aliasImpl(Value lhs, Value rhs) {
289322
: AliasResult::MayAlias;
290323
}
291324

325+
if (std::optional<AliasResult> result = checkDistinctObjects(lhs, rhs))
326+
return *result;
327+
292328
// Otherwise, neither of the values are constant so check to see if either has
293329
// an allocation effect.
294330
bool lhsHasAlloc = succeeded(getAllocEffectFor(lhs, lhsAlloc, lhsAllocScope));

mlir/test/Analysis/test-alias-analysis.mlir

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,19 @@ func.func @constants(%arg: memref<2xf32>) attributes {test.ptr = "func"} {
256256

257257
return
258258
}
259+
260+
// -----
261+
262+
// CHECK-LABEL: Testing : "distinct_objects"
263+
// CHECK-DAG: func.region0#0 <-> func.region0#1: MayAlias
264+
265+
// CHECK-DAG: distinct#0 <-> distinct#1: NoAlias
266+
// CHECK-DAG: distinct#0 <-> func.region0#0: MustAlias
267+
// CHECK-DAG: distinct#1 <-> func.region0#0: MayAlias
268+
// CHECK-DAG: distinct#0 <-> func.region0#1: MayAlias
269+
// CHECK-DAG: distinct#1 <-> func.region0#1: MustAlias
270+
271+
func.func @distinct_objects(%arg: memref<?xf32>, %arg1: memref<?xf32>) attributes {test.ptr = "func"} {
272+
%0, %1 = memref.distinct_objects %arg, %arg1 {test.ptr = "distinct"} : memref<?xf32>, memref<?xf32>
273+
return
274+
}

0 commit comments

Comments
 (0)