Skip to content

Commit 87e2e89

Browse files
authored
[MLIR] Fuse locations of merged constants (llvm#74670)
When merging constants by the operation folder, the location of the op that remains should be updated to track the new meaning of this op. This way we do not lose track of all possible source locations that the constant op came from, and the final location of the op is less reliant on the order of folding. This will also help debuggers understand how to step these instructions. This PR introduces a helper for operation folder to fuse another location into the location of an op. When an op is deduplicated, fuse the location of the op to be removed into the op that is retained. The retained op now represents both original ops. The FusedLoc will have a string metadata to help understand the reason for the location fusion (motivated by the [example](https://github.com/llvm/llvm-project/blob/71be8f3c23497e28c86f1135f564b16106d8d6fb/mlir/include/mlir/IR/BuiltinLocationAttributes.td#L130) in the docstring of FusedLoc).
1 parent 59f3661 commit 87e2e89

File tree

4 files changed

+113
-2
lines changed

4 files changed

+113
-2
lines changed

mlir/include/mlir/Transforms/FoldUtils.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class Value;
3333
class OperationFolder {
3434
public:
3535
OperationFolder(MLIRContext *ctx, OpBuilder::Listener *listener = nullptr)
36-
: interfaces(ctx), rewriter(ctx, listener) {}
36+
: fusedLocationTag(StringAttr::get(ctx, "CSE")), interfaces(ctx),
37+
rewriter(ctx, listener) {}
3738

3839
/// Tries to perform folding on the given `op`, including unifying
3940
/// deduplicated constants. If successful, replaces `op`'s uses with
@@ -95,6 +96,15 @@ class OperationFolder {
9596
Dialect *dialect, Attribute value,
9697
Type type, Location loc);
9798

99+
// Fuse `foldedLocation` into the Location of `retainedOp`. This will result
100+
// in `retainedOp` having a FusedLoc with `fusedLocationTag` to help trace the
101+
// source of the fusion. If `retainedOp` already had a FusedLoc with the same
102+
// tag, `foldedLocation` will simply be appended to it.
103+
void appendFoldedLocation(Operation *retainedOp, Location foldedLocation);
104+
105+
/// Tag for annotating fused locations as a result of merging constants.
106+
StringAttr fusedLocationTag;
107+
98108
/// A mapping between an insertion region and the constants that have been
99109
/// created within it.
100110
DenseMap<Region *, ConstantMap> foldScopes;

mlir/lib/Transforms/Utils/FoldUtils.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ bool OperationFolder::insertKnownConstant(Operation *op, Attribute constValue) {
141141
// If there is an existing constant, replace `op`.
142142
if (folderConstOp) {
143143
notifyRemoval(op);
144+
appendFoldedLocation(folderConstOp, op->getLoc());
144145
rewriter.replaceOp(op, folderConstOp->getResults());
145146
return false;
146147
}
@@ -294,8 +295,10 @@ OperationFolder::tryGetOrCreateConstant(ConstantMap &uniquedConstants,
294295
// Check if an existing mapping already exists.
295296
auto constKey = std::make_tuple(dialect, value, type);
296297
Operation *&constOp = uniquedConstants[constKey];
297-
if (constOp)
298+
if (constOp) {
299+
appendFoldedLocation(constOp, loc);
298300
return constOp;
301+
}
299302

300303
// If one doesn't exist, try to materialize one.
301304
if (!(constOp = materializeConstant(dialect, rewriter, value, type, loc)))
@@ -316,6 +319,7 @@ OperationFolder::tryGetOrCreateConstant(ConstantMap &uniquedConstants,
316319
// materialized operation in favor of the existing one.
317320
if (auto *existingOp = uniquedConstants.lookup(newKey)) {
318321
notifyRemoval(constOp);
322+
appendFoldedLocation(existingOp, constOp->getLoc());
319323
rewriter.eraseOp(constOp);
320324
referencedDialects[existingOp].push_back(dialect);
321325
return constOp = existingOp;
@@ -326,3 +330,32 @@ OperationFolder::tryGetOrCreateConstant(ConstantMap &uniquedConstants,
326330
auto newIt = uniquedConstants.insert({newKey, constOp});
327331
return newIt.first->second;
328332
}
333+
334+
void OperationFolder::appendFoldedLocation(Operation *retainedOp,
335+
Location foldedLocation) {
336+
// Append into existing fused location if it has the same tag.
337+
if (auto existingFusedLoc =
338+
dyn_cast<FusedLocWith<StringAttr>>(retainedOp->getLoc())) {
339+
StringAttr existingMetadata = existingFusedLoc.getMetadata();
340+
if (existingMetadata == fusedLocationTag) {
341+
ArrayRef<Location> existingLocations = existingFusedLoc.getLocations();
342+
SetVector<Location> locations(existingLocations.begin(),
343+
existingLocations.end());
344+
locations.insert(foldedLocation);
345+
Location newFusedLoc = FusedLoc::get(
346+
retainedOp->getContext(), locations.takeVector(), existingMetadata);
347+
retainedOp->setLoc(newFusedLoc);
348+
return;
349+
}
350+
}
351+
352+
// Create a new fusedloc with retainedOp's loc and foldedLocation.
353+
// If they're already equal, no need to fuse.
354+
if (retainedOp->getLoc() == foldedLocation)
355+
return;
356+
357+
Location newFusedLoc =
358+
FusedLoc::get(retainedOp->getContext(),
359+
{retainedOp->getLoc(), foldedLocation}, fusedLocationTag);
360+
retainedOp->setLoc(newFusedLoc);
361+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{test-convergence}))' -split-input-file -mlir-print-debuginfo | FileCheck %s
2+
3+
// CHECK-LABEL: func @merge_constants
4+
func.func @merge_constants() -> (index, index, index, index) {
5+
// CHECK-NEXT: arith.constant 42 : index loc(#[[FusedLoc:.*]])
6+
%0 = arith.constant 42 : index loc("merge_constants":0:0)
7+
%1 = arith.constant 42 : index loc("merge_constants":1:0)
8+
%2 = arith.constant 42 : index loc("merge_constants":2:0)
9+
%3 = arith.constant 42 : index loc("merge_constants":2:0) // repeated loc
10+
return %0, %1, %2, %3: index, index, index, index
11+
}
12+
13+
// CHECK-DAG: #[[LocConst0:.*]] = loc("merge_constants":0:0)
14+
// CHECK-DAG: #[[LocConst1:.*]] = loc("merge_constants":1:0)
15+
// CHECK-DAG: #[[LocConst2:.*]] = loc("merge_constants":2:0)
16+
// CHECK: #[[FusedLoc]] = loc(fused<"CSE">[#[[LocConst0]], #[[LocConst1]], #[[LocConst2]]])
17+
18+
// -----
19+
20+
// CHECK-LABEL: func @hoist_constant
21+
func.func @hoist_constant(%arg0: memref<8xi32>) {
22+
// CHECK-NEXT: arith.constant 42 : i32 loc(#[[FusedLoc:.*]])
23+
affine.for %arg1 = 0 to 8 {
24+
%0 = arith.constant 42 : i32 loc("hoist_constant":0:0)
25+
%1 = arith.constant 42 : i32 loc("hoist_constant":1:0)
26+
memref.store %0, %arg0[%arg1] : memref<8xi32>
27+
memref.store %1, %arg0[%arg1] : memref<8xi32>
28+
}
29+
return
30+
}
31+
32+
// CHECK-DAG: #[[LocConst0:.*]] = loc("hoist_constant":0:0)
33+
// CHECK-DAG: #[[LocConst1:.*]] = loc("hoist_constant":1:0)
34+
// CHECK: #[[FusedLoc]] = loc(fused<"CSE">[#[[LocConst0]], #[[LocConst1]]])
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: mlir-opt %s -split-input-file -test-constant-fold -mlir-print-debuginfo | FileCheck %s
2+
3+
// CHECK-LABEL: func @fold_and_merge
4+
func.func @fold_and_merge() -> (i32, i32) {
5+
%0 = arith.constant 1 : i32
6+
%1 = arith.constant 5 : i32
7+
8+
// CHECK-NEXT: [[C:%.+]] = arith.constant 6 : i32 loc(#[[FusedLoc:.*]])
9+
%2 = arith.addi %0, %1 : i32 loc("fold_and_merge":0:0)
10+
11+
%3 = arith.constant 6 : i32 loc("fold_and_merge":1:0)
12+
13+
return %2, %3: i32, i32
14+
}
15+
16+
// CHECK-DAG: #[[LocConst0:.*]] = loc("fold_and_merge":0:0)
17+
// CHECK-DAG: #[[LocConst1:.*]] = loc("fold_and_merge":1:0)
18+
// CHECK: #[[FusedLoc]] = loc(fused<"CSE">[#[[LocConst1]], #[[LocConst0]]])
19+
20+
// -----
21+
22+
// CHECK-LABEL: func @materialize_different_dialect
23+
func.func @materialize_different_dialect() -> (f32, f32) {
24+
// CHECK: arith.constant 1.{{0*}}e+00 : f32 loc(#[[FusedLoc:.*]])
25+
%0 = arith.constant -1.0 : f32
26+
%1 = math.absf %0 : f32 loc("materialize_different_dialect":0:0)
27+
%2 = arith.constant 1.0 : f32 loc("materialize_different_dialect":1:0)
28+
29+
return %1, %2: f32, f32
30+
}
31+
32+
// CHECK-DAG: #[[LocConst0:.*]] = loc("materialize_different_dialect":0:0)
33+
// CHECK-DAG: #[[LocConst1:.*]] = loc("materialize_different_dialect":1:0)
34+
// CHECK: #[[FusedLoc]] = loc(fused<"CSE">[#[[LocConst1]], #[[LocConst0]]])

0 commit comments

Comments
 (0)