@@ -233,6 +233,7 @@ void splitCondBranches(IRRewriter &rewriter, FunctionOpInterface function) {
233
233
// / AFTER:
234
234
// / ```mlir
235
235
// / %copy = arm_sme.copy_tile %tile : vector<[4]x[4]xf32>
236
+ // / cf.br ^bb1(%copy: vector<[4]x[4]xf32>)
236
237
// / ```
237
238
void insertCopiesAtBranches (IRRewriter &rewriter,
238
239
FunctionOpInterface function) {
@@ -258,16 +259,18 @@ void insertCopiesAtBranches(IRRewriter &rewriter,
258
259
// / branch (see `tile-allocation-copies.mlir` and
259
260
// / `tile-allocation-liveness.mlir` for examples). The copies break up live
260
261
// / ranges and ensure when moving out of SSA the semantics of the program are
261
- // / persevered .
262
+ // / preserved .
262
263
void preprocessForTileAllocation (IRRewriter &rewriter,
263
264
FunctionOpInterface function) {
264
265
splitCondBranches (rewriter, function);
265
266
insertCopiesAtBranches (rewriter, function);
266
267
}
267
268
268
269
// / A live range for a (collection of) tile values. A live range is built up of
269
- // / intervals [start, end) which represent parts of the program where the value
270
- // / needs to be live (i.e. in an SME virtual tile).
270
+ // / non-overlapping intervals [start, end) which represent parts of the program
271
+ // / where a value in the range needs to be live (i.e. in an SME virtual tile).
272
+ // / Note that as the intervals are non-overlapping all values within a live
273
+ // / range can be allocated to the same SME virtual tile.
271
274
struct LiveRange {
272
275
using RangeSet = llvm::IntervalMap<uint64_t , uint8_t , 16 ,
273
276
llvm::IntervalMapHalfOpenInfo<unsigned >>;
@@ -310,8 +313,14 @@ struct LiveRange {
310
313
return *getSMETileType (cast<VectorType>(values[0 ].getType ()));
311
314
}
312
315
313
- std::unique_ptr<RangeSet> ranges;
316
+ // / The values contained in this live range.
314
317
SetVector<Value> values;
318
+
319
+ // / A set of (non-overlapping) intervals that mark where any value in `values`
320
+ // / is live.
321
+ std::unique_ptr<RangeSet> ranges;
322
+
323
+ // / The tile ID (or none) assigned to this live range.
315
324
std::optional<unsigned > tileId;
316
325
};
317
326
@@ -345,6 +354,7 @@ DenseMap<Value, LiveRange>
345
354
gatherTileLiveRanges (DenseMap<Operation *, unsigned > const &operationToIndexMap,
346
355
LiveRange::Allocator &liveRangeAllocator,
347
356
Liveness &liveness, FunctionOpInterface function) {
357
+ assert (!operationToIndexMap.empty () && " expected operation numbering" );
348
358
DenseMap<Value, LiveRange> liveRanges;
349
359
// / Defines or updates a live range for an SME tile value. Live-ins may update
350
360
// / an existing live range (rather than define a new one). Note: If
@@ -420,6 +430,9 @@ coalesceTileLiveRanges(DenseMap<Value, LiveRange> &initialLiveRanges) {
420
430
liveRanges.insert ({value, &liveRange});
421
431
}
422
432
433
+ // Merge the live ranges of values `a` and `b` into one (if they do not
434
+ // overlap). After this, the values `a` and `b` will both point to the same
435
+ // live range (which will contain multiple values).
423
436
auto mergeValuesIfNonOverlapping = [&](Value a, Value b) {
424
437
LiveRange *aLiveRange = liveRanges.at (a);
425
438
LiveRange *bLiveRange = liveRanges.at (b);
@@ -695,6 +708,11 @@ struct TestTileAllocationPass
695
708
696
709
LogicalResult mlir::arm_sme::allocateSMETiles (FunctionOpInterface function,
697
710
bool dumpRanges) {
711
+ if (function.empty ()) {
712
+ // TODO: Also return early if the function contains no ArmSME ops?
713
+ return success ();
714
+ }
715
+
698
716
LiveRange::Allocator liveRangeAllocator;
699
717
IRRewriter rewriter (function.getContext ());
700
718
0 commit comments