@@ -233,6 +233,7 @@ void splitCondBranches(IRRewriter &rewriter, FunctionOpInterface function) {
233233// / AFTER:
234234// / ```mlir
235235// / %copy = arm_sme.copy_tile %tile : vector<[4]x[4]xf32>
236+ // / cf.br ^bb1(%copy: vector<[4]x[4]xf32>)
236237// / ```
237238void insertCopiesAtBranches (IRRewriter &rewriter,
238239 FunctionOpInterface function) {
@@ -258,16 +259,18 @@ void insertCopiesAtBranches(IRRewriter &rewriter,
258259// / branch (see `tile-allocation-copies.mlir` and
259260// / `tile-allocation-liveness.mlir` for examples). The copies break up live
260261// / ranges and ensure when moving out of SSA the semantics of the program are
261- // / persevered .
262+ // / preserved .
262263void preprocessForTileAllocation (IRRewriter &rewriter,
263264 FunctionOpInterface function) {
264265 splitCondBranches (rewriter, function);
265266 insertCopiesAtBranches (rewriter, function);
266267}
267268
268269// / 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.
271274struct LiveRange {
272275 using RangeSet = llvm::IntervalMap<uint64_t , uint8_t , 16 ,
273276 llvm::IntervalMapHalfOpenInfo<unsigned >>;
@@ -310,8 +313,14 @@ struct LiveRange {
310313 return *getSMETileType (cast<VectorType>(values[0 ].getType ()));
311314 }
312315
313- std::unique_ptr<RangeSet> ranges;
316+ // / The values contained in this live range.
314317 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.
315324 std::optional<unsigned > tileId;
316325};
317326
@@ -345,6 +354,7 @@ DenseMap<Value, LiveRange>
345354gatherTileLiveRanges (DenseMap<Operation *, unsigned > const &operationToIndexMap,
346355 LiveRange::Allocator &liveRangeAllocator,
347356 Liveness &liveness, FunctionOpInterface function) {
357+ assert (!operationToIndexMap.empty () && " expected operation numbering" );
348358 DenseMap<Value, LiveRange> liveRanges;
349359 // / Defines or updates a live range for an SME tile value. Live-ins may update
350360 // / an existing live range (rather than define a new one). Note: If
@@ -420,6 +430,9 @@ coalesceTileLiveRanges(DenseMap<Value, LiveRange> &initialLiveRanges) {
420430 liveRanges.insert ({value, &liveRange});
421431 }
422432
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).
423436 auto mergeValuesIfNonOverlapping = [&](Value a, Value b) {
424437 LiveRange *aLiveRange = liveRanges.at (a);
425438 LiveRange *bLiveRange = liveRanges.at (b);
@@ -695,6 +708,11 @@ struct TestTileAllocationPass
695708
696709LogicalResult mlir::arm_sme::allocateSMETiles (FunctionOpInterface function,
697710 bool dumpRanges) {
711+ if (function.empty ()) {
712+ // TODO: Also return early if the function contains no ArmSME ops?
713+ return success ();
714+ }
715+
698716 LiveRange::Allocator liveRangeAllocator;
699717 IRRewriter rewriter (function.getContext ());
700718
0 commit comments