MLIR-AIE 1.4.5.dev
AIEUnrollRuntimeSequenceLoops.cpp
Go to the documentation of this file.
1//===- AIEUnrollRuntimeSequenceLoops.cpp ------------------------*- C++ -*-===//
2//
3// Copyright (C) 2024-2026 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7//
8// Fully unrolls constant-bound scf.for loops inside aie.runtime_sequence
9// bodies. Running this before aie-assign-runtime-sequence-bd-ids leaves the
10// allocator with straight-line IR (no back-edges), so a task freed in a later
11// iteration than it is configured becomes several distinct configures whose BD
12// ids ordinary liveness-based allocation recycles -- no rolled-loop rotation
13// analysis is needed.
14//
15// Runtime-bound loops (non-constant trip count) are left in place; they will be
16// handled by the dynamic EmitC path in a later phase.
17//
18//===----------------------------------------------------------------------===//
19
23
24#include "mlir/Dialect/SCF/IR/SCF.h"
25#include "mlir/Dialect/SCF/Utils/Utils.h"
26#include "mlir/Pass/Pass.h"
27#include "llvm/ADT/SmallVector.h"
28
29namespace xilinx::AIEX {
30#define GEN_PASS_DEF_AIEUNROLLRUNTIMESEQUENCELOOPS
31#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
32} // namespace xilinx::AIEX
33
34using namespace mlir;
35using namespace xilinx;
36using namespace xilinx::AIE;
37using namespace xilinx::AIEX;
38
39namespace {
40
41struct AIEUnrollRuntimeSequenceLoopsPass
42 : xilinx::AIEX::impl::AIEUnrollRuntimeSequenceLoopsBase<
43 AIEUnrollRuntimeSequenceLoopsPass> {
44
45 void runOnOperation() override {
46 DeviceOp device = getOperation();
47
48 device.walk([&](RuntimeSequenceOp seq) {
49 // Collect constant-trip loops in post-order (innermost first), then
50 // unroll in that order. loopUnrollFull unrolls only the given loop,
51 // cloning any nested loops as-is -- so nested loops need their own calls.
52 // Post-order guarantees an inner loop is unrolled (and gone) before its
53 // enclosing loop, so every collected handle is still valid when reached
54 // and no re-walk is needed. Reaches loops anywhere in the sequence,
55 // including inside scf.if arms.
56 SmallVector<scf::ForOp> loops;
57 seq.walk([&](scf::ForOp forOp) {
58 if (forOp.getStaticTripCount().has_value())
59 loops.push_back(forOp);
60 });
61 for (scf::ForOp forOp : loops)
62 (void)loopUnrollFull(forOp);
63 });
64 }
65};
66
67} // namespace
68
69std::unique_ptr<mlir::OperationPass<AIE::DeviceOp>>
71 return std::make_unique<AIEUnrollRuntimeSequenceLoopsPass>();
72}
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEUnrollRuntimeSequenceLoopsPass()