Skip to content

Commit 388a061

Browse files
committed
Implement sequential placer pass, set up placement pass infrastructure.
1 parent 82b8159 commit 388a061

13 files changed

Lines changed: 1023 additions & 0 deletions

File tree

include/aie/Dialect/AIE/Transforms/AIEPasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace xilinx::AIE {
2323
#define GEN_PASS_CLASSES
2424
#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
2525

26+
std::unique_ptr<mlir::OperationPass<DeviceOp>> createAIEPlaceTilesPass();
2627
std::unique_ptr<mlir::OperationPass<DeviceOp>>
2728
createAIEAssignBufferAddressesPass();
2829
std::unique_ptr<mlir::OperationPass<DeviceOp>> createAIEAssignLockIDsPass();

include/aie/Dialect/AIE/Transforms/AIEPasses.td

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@
1313

1414
include "mlir/Pass/PassBase.td"
1515

16+
def AIEPlaceTiles : Pass<"aie-place-tiles", "DeviceOp"> {
17+
let summary = "Place logical tiles onto physical AIE tiles";
18+
let description = [{
19+
Sequential placer algorithm places core tiles in a
20+
column-major order and places fifo-connected Shim/Mem tiles
21+
near its core tiles. One or more aie.logical_tile operation is mapped
22+
to one aie.tile.
23+
}];
24+
25+
let constructor = "xilinx::AIE::createAIEPlaceTilesPass()";
26+
27+
let dependentDialects = ["xilinx::AIE::AIEDialect"];
28+
29+
let options = [
30+
Option<"clPlacerName", "placer", "std::string",
31+
/*default=*/"\"sequential_placer\"",
32+
"Placement algorithm to use (currently only 'sequential_placer')">
33+
];
34+
}
35+
1636
def AIEAssignBufferAddresses : Pass<"aie-assign-buffer-addresses", "DeviceOp"> {
1737
let summary = "Assign memory locations for buffers in each tile";
1838
let description = [{
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//===- AIEPlacer.h ----------------------------------------------*- C++ -*-===//
2+
//
3+
// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
// (c) Copyright 2024-2026 Advanced Micro Devices, Inc.
8+
//
9+
//===----------------------------------------------------------------------===//
10+
// This file contains the interface for tile placement algorithms.
11+
// Placers assign physical tile coordinates to logical tiles.
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef AIE_PLACER_H
15+
#define AIE_PLACER_H
16+
17+
#include "aie/Dialect/AIE/IR/AIEDialect.h"
18+
#include "aie/Dialect/AIE/IR/AIETargetModel.h"
19+
20+
namespace xilinx::AIE {
21+
22+
// maps logical tile operations to physical coordinates
23+
using PlacementResult = llvm::DenseMap<mlir::Operation *, TileID>;
24+
25+
// Track available tiles and resource usage
26+
struct TileAvailability {
27+
std::vector<TileID> compTiles;
28+
std::vector<TileID> nonCompTiles; // Memory and shim tiles
29+
30+
llvm::DenseMap<TileID, int> inputChannelsUsed;
31+
llvm::DenseMap<TileID, int> outputChannelsUsed;
32+
33+
void removeTile(TileID tile, AIETileType type);
34+
};
35+
36+
// Abstract placer interface
37+
class Placer {
38+
public:
39+
Placer() = default;
40+
virtual ~Placer() = default;
41+
42+
virtual void initialize(DeviceOp device,
43+
const AIETargetModel &targetModel) = 0;
44+
45+
virtual mlir::LogicalResult
46+
place(llvm::ArrayRef<mlir::Operation *> logicalTiles,
47+
llvm::ArrayRef<mlir::Operation *> objectFifos,
48+
llvm::ArrayRef<mlir::Operation *> cores, PlacementResult &result) = 0;
49+
50+
virtual llvm::StringRef getName() const = 0;
51+
};
52+
53+
// Sequential placement algorithm
54+
//
55+
// Places logical tiles to physical tiles using a simple strategy:
56+
// - Compute tiles: Sequential row-major placement
57+
// - Memory/shim tiles: Channel capacity placement near common column
58+
//
59+
// Core-to-core connections are NOT validated because SequentialPlacer
60+
// doesn't account for shared memory optimization.
61+
//
62+
// Shim/Mem tiles with identical placement constraints and sufficient
63+
// DMA capacity are merged to the same physical tile.
64+
class SequentialPlacer : public Placer {
65+
public:
66+
SequentialPlacer(std::optional<int> coresPerCol = std::nullopt)
67+
: coresPerCol(coresPerCol) {}
68+
69+
void initialize(DeviceOp device, const AIETargetModel &targetModel) override;
70+
71+
mlir::LogicalResult place(llvm::ArrayRef<mlir::Operation *> logicalTiles,
72+
llvm::ArrayRef<mlir::Operation *> objectFifos,
73+
llvm::ArrayRef<mlir::Operation *> cores,
74+
PlacementResult &result) override;
75+
76+
llvm::StringRef getName() const override { return "sequential_placer"; }
77+
78+
private:
79+
std::optional<int> coresPerCol;
80+
TileAvailability availability;
81+
const AIETargetModel *targetModel;
82+
DeviceOp device;
83+
84+
int getCommonColumn(const PlacementResult &result);
85+
86+
std::optional<TileID> findTileWithCapacity(int targetCol,
87+
std::vector<TileID> &tiles,
88+
int requiredInputChannels,
89+
int requiredOutputChannels);
90+
91+
void updateChannelUsage(TileID tile, bool isOutput, int numChannels);
92+
93+
bool hasAvailableChannels(TileID tile, int inputChannels, int outputChannels);
94+
95+
mlir::LogicalResult validateAndUpdateChannelUsage(
96+
LogicalTileOp logicalTile, TileID tile,
97+
const llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
98+
&channelRequirements,
99+
bool isConstrained);
100+
};
101+
102+
// PlacementAnalysis integrates the Pathfinder class into the MLIR
103+
// environment.
104+
class PlacementAnalysis {
105+
public:
106+
PlacementAnalysis() : placer(std::make_shared<SequentialPlacer>()) {}
107+
explicit PlacementAnalysis(std::shared_ptr<Placer> p)
108+
: placer(std::move(p)) {}
109+
110+
mlir::LogicalResult runAnalysis(DeviceOp &device);
111+
112+
std::optional<TileID> getPlacement(mlir::Operation *logicalTile) const;
113+
114+
Placer &getPlacer() { return *placer; }
115+
116+
private:
117+
std::shared_ptr<Placer> placer;
118+
PlacementResult result;
119+
};
120+
121+
} // namespace xilinx::AIE
122+
123+
#endif // AIE_PLACER_H
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===- AIEPlaceTiles.cpp ----------------------------------------*- C++ -*-===//
2+
//
3+
// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
// (c) Copyright 2024-2026 Advanced Micro Devices, Inc.
8+
//
9+
//===----------------------------------------------------------------------===//
10+
11+
#include "aie/Dialect/AIE/IR/AIEDialect.h"
12+
#include "aie/Dialect/AIE/Transforms/AIEPasses.h"
13+
#include "aie/Dialect/AIE/Transforms/AIEPlacer.h"
14+
15+
#include "mlir/IR/PatternMatch.h"
16+
#include "mlir/Transforms/DialectConversion.h"
17+
18+
#define DEBUG_TYPE "aie-place-tiles"
19+
20+
using namespace mlir;
21+
using namespace xilinx;
22+
using namespace xilinx::AIE;
23+
24+
namespace {
25+
26+
struct ConvertLogicalTileToTile : OpConversionPattern<LogicalTileOp> {
27+
ConvertLogicalTileToTile(MLIRContext *context, DeviceOp &d,
28+
PlacementAnalysis &a, PatternBenefit benefit = 1)
29+
: OpConversionPattern(context, benefit), device(d), analyzer(a) {}
30+
31+
LogicalResult
32+
matchAndRewrite(LogicalTileOp logicalTile, OpAdaptor adaptor,
33+
ConversionPatternRewriter &rewriter) const override {
34+
// Get pre-computed placement from analysis
35+
auto placement = analyzer.getPlacement(logicalTile);
36+
if (!placement) {
37+
return logicalTile.emitError("no placement found for logical tile");
38+
}
39+
40+
// handle merging multiple logical tiles to same physical tile
41+
TileOp tileOp =
42+
TileOp::getOrCreate(rewriter, device, placement->col, placement->row);
43+
44+
// Copy allocation_scheme if present
45+
if (auto scheme = logicalTile.getAllocationScheme())
46+
tileOp.setAllocationScheme(scheme);
47+
48+
// Replace all uses and erase logical tile
49+
rewriter.replaceOp(logicalTile, tileOp.getResult());
50+
return success();
51+
}
52+
53+
private:
54+
DeviceOp device;
55+
PlacementAnalysis &analyzer;
56+
};
57+
58+
} // namespace
59+
60+
struct AIEPlaceTilesPass : AIEPlaceTilesBase<AIEPlaceTilesPass> {
61+
void runOnOperation() override {
62+
DeviceOp device = getOperation();
63+
64+
// Create placer
65+
std::shared_ptr<Placer> placer;
66+
if (clPlacerName == "sequential_placer") {
67+
placer = std::make_shared<SequentialPlacer>();
68+
} else {
69+
device.emitError() << "Unknown placer: " << clPlacerName;
70+
return signalPassFailure();
71+
}
72+
73+
// Run placement analysis
74+
PlacementAnalysis analyzer(placer);
75+
if (failed(analyzer.runAnalysis(device)))
76+
return signalPassFailure();
77+
78+
// Apply placement using conversion pattern
79+
ConversionTarget target(getContext());
80+
target.addLegalOp<TileOp>();
81+
target.addIllegalOp<LogicalTileOp>();
82+
83+
RewritePatternSet patterns(&getContext());
84+
patterns.add<ConvertLogicalTileToTile>(device.getContext(), device,
85+
analyzer);
86+
87+
if (failed(applyPartialConversion(device, target, std::move(patterns))))
88+
return signalPassFailure();
89+
}
90+
};
91+
92+
std::unique_ptr<OperationPass<DeviceOp>> AIE::createAIEPlaceTilesPass() {
93+
return std::make_unique<AIEPlaceTilesPass>();
94+
}

0 commit comments

Comments
 (0)