MLIR-AIE 1.4.5.dev
AIEPlaceTiles.cpp
Go to the documentation of this file.
1//===- AIEPlaceTiles.cpp ----------------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2026 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
11
12#include "mlir/IR/Location.h"
13#include "mlir/IR/PatternMatch.h"
14#include "mlir/Transforms/DialectConversion.h"
15
16#include <cmath>
17
18namespace xilinx::AIE {
19#define GEN_PASS_DEF_AIEPLACETILES
20#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
21} // namespace xilinx::AIE
22
23#define DEBUG_TYPE "aie-place-tiles"
24
25using namespace mlir;
26using namespace xilinx;
27using namespace xilinx::AIE;
28
29namespace {
30
31struct ConvertLogicalTileToTile : OpConversionPattern<LogicalTileOp> {
32 ConvertLogicalTileToTile(MLIRContext *context, DeviceOp &d, Placer &p,
33 PatternBenefit benefit = 1)
34 : OpConversionPattern(context, benefit), device(d), placer(p) {}
35
36 LogicalResult
37 matchAndRewrite(LogicalTileOp logicalTile, OpAdaptor adaptor,
38 ConversionPatternRewriter &rewriter) const override {
39 auto placement = placer.getPlacement(logicalTile);
40 if (!placement)
41 return logicalTile.emitError("no placement found for logical tile");
42
43 // Handle merging multiple logical tiles to same physical tile
44 TileOp tileOp = TileOp::getOrCreate(rewriter, device, placement->col,
45 placement->row, logicalTile.getLoc());
46 rewriter.modifyOpInPlace(tileOp, [&] {
47 tileOp->setLoc(
48 rewriter.getFusedLoc({tileOp.getLoc(), logicalTile.getLoc()}));
49 });
50
51 if (auto controllerId = logicalTile->getAttr("controller_id"))
52 tileOp->setAttr("controller_id", controllerId);
53
54 rewriter.replaceOp(logicalTile, tileOp.getResult());
55 return success();
56 }
57
58private:
59 DeviceOp device;
60 Placer &placer;
61};
62
63struct AIEPlaceTilesPass
64 : xilinx::AIE::impl::AIEPlaceTilesBase<AIEPlaceTilesPass> {
65
66 AIEPlaceTilesPass() = default;
67
68 AIEPlaceTilesPass(const AIEPlaceTilesOptions &options)
69 : AIEPlaceTilesBase(options) {}
70
71 void runOnOperation() override {
72 DeviceOp device = getOperation();
73
74 // Create placer
75 std::shared_ptr<Placer> placer;
76 std::shared_ptr<SAPlacer> saPlacer;
77 switch (clPlacerType) {
79 std::optional<int> coresPerCol = std::nullopt;
80 if (clCoresPerCol >= 0)
81 coresPerCol = clCoresPerCol;
82 placer = std::make_shared<SequentialPlacer>(
83 coresPerCol, clMergeLogicalTiles, clSpreadUnanchoredTiles);
84 break;
85 }
87 double effort = clSAEffort.getValue();
88 if (!std::isfinite(effort) || effort <= 0) {
89 device.emitError("sa-effort must be positive and finite, got ")
90 << effort;
91 return signalPassFailure();
92 }
93 SAConfig config;
94 config.effort = effort;
95 placer = saPlacer = std::make_shared<SAPlacer>(clSASeed, config);
96 break;
97 }
98 }
99
100 placer->initialize(device.getTargetModel());
101 if (failed(placer->place(device)))
102 return signalPassFailure();
103 if (saPlacer)
104 saFinalCost += saPlacer->getFinalCost();
105
106 ConversionTarget target(getContext());
107 target.addLegalOp<TileOp>();
108 target.addIllegalOp<LogicalTileOp>();
109 target.addLegalDialect<AIEDialect>();
110
111 RewritePatternSet patterns(&getContext());
112 patterns.add<ConvertLogicalTileToTile>(device.getContext(), device,
113 *placer);
114
115 if (failed(applyPartialConversion(device, target, std::move(patterns))))
116 return signalPassFailure();
117
118 // Generate objectfifo.allocate ops right after their respective objectfifo
119 auto &allocs = placer->getAllocates();
120 if (!allocs.empty()) {
121 // Deduplicate: only emit one allocate per fifo
122 llvm::DenseSet<Operation *> emitted;
123 for (auto &[fifoOp, delegateTileID] : allocs) {
124 if (emitted.count(fifoOp))
125 continue;
126 emitted.insert(fifoOp);
127
128 auto ofOp = dyn_cast<ObjectFifoCreateOp>(fifoOp);
129 if (!ofOp)
130 continue;
131
132 // Insert right after the objectfifo op
133 OpBuilder builder(ofOp->getContext());
134 builder.setInsertionPointAfter(ofOp);
135
136 TileOp delegateTile =
137 TileOp::getOrCreate(builder, device, delegateTileID.col,
138 delegateTileID.row, ofOp.getLoc());
139 ObjectFifoAllocateOp::create(
140 builder, ofOp.getLoc(),
141 SymbolRefAttr::get(builder.getContext(), ofOp.getSymName()),
142 delegateTile.getResult());
143 }
144 }
145 }
146};
147
148} // namespace
149
150std::unique_ptr<OperationPass<DeviceOp>> AIE::createAIEPlaceTilesPass() {
151 return std::make_unique<AIEPlaceTilesPass>();
152}
153
154std::unique_ptr<OperationPass<DeviceOp>>
155AIE::createAIEPlaceTilesPass(const AIEPlaceTilesOptions &options) {
156 return std::make_unique<AIEPlaceTilesPass>(options);
157}
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIEPlaceTilesPass()