279 bool mergeLogicalTiles =
true,
280 bool spreadUnanchoredTiles =
false)
281 : coresPerCol(coresPerCol), mergeLogicalTiles(mergeLogicalTiles),
282 spreadUnanchoredTiles(spreadUnanchoredTiles) {}
286 mlir::LogicalResult
place(DeviceOp device)
override;
288 llvm::StringRef
getName()
const override {
return "sequential_placer"; }
291 std::optional<int> coresPerCol;
292 bool mergeLogicalTiles;
295 bool spreadUnanchoredTiles;
299 llvm::DenseSet<TileID> assignedNonCoreTiles;
300 int deviceCoresPerCol = 0;
304 std::optional<ShimTransferSpans> shimSpans;
305 ShareableShimEnds shareableShimEnds;
306 llvm::DenseMap<TileID, std::array<llvm::SmallVector<mlir::StringAttr>, 2>>
308 bool fitsSharingShim(
TileID tile, mlir::Operation *logicalTile,
309 std::pair<int, int> required);
310 void recordShimEnds(
TileID tile, mlir::Operation *logicalTile);
315 DeviceOp device, llvm::ArrayRef<ObjectFifoCreateOp> objectFifos,
316 llvm::DenseMap<mlir::Operation *, std::pair<int, int>> &requirements);
319 enum class DmaDir { In, Out };
323 enum class PlacementOrigin { Pinned, Selected };
325 void limitCoresPerColumn(
int maxCoresPerCol,
int numColumns);
330 std::optional<TileID>
331 findTileWithCapacity(std::optional<int> targetCol,
332 llvm::ArrayRef<TileID> tiles,
int requiredInputChannels,
333 int requiredOutputChannels, AIETileType requestedType,
334 mlir::Operation *logicalTile,
bool withinBudgets);
345 struct CapacityDiagnosis {
346 bool capacityExistsSomewhere =
false;
348 int inUsed = 0, inMax = 0, outUsed = 0, outMax = 0;
350 int closestShortIn = 0, closestShortOut = 0;
352 CapacityDiagnosis diagnoseCapacityExhaustion(AIETileType requestedType,
353 int requiredInputChannels,
354 int requiredOutputChannels);
356 void updateChannelUsage(
TileID tile, DmaDir direction,
int numChannels);
360 llvm::DenseMap<mlir::Operation *, StreamDemand> streamDemand;
362 llvm::DenseMap<int, StreamDemand> columnStreamsUsed;
364 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<mlir::Operation *>>
366 llvm::DenseMap<int, llvm::DenseSet<mlir::Operation *>> columnIncomingFifos;
367 void recordColumnStreamUsage(mlir::Operation *tile,
int col);
369 llvm::DenseMap<mlir::Operation *, int> broadcastFanout;
370 llvm::DenseMap<TileID, int> broadcastFanoutUsed;
371 void buildStreamDemand(llvm::ArrayRef<ObjectFifoCreateOp> objectFifos);
375 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<int>> runtimeBdProfiles;
379 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<std::pair<int, int>>>
381 void buildRuntimeBdProfiles(DeviceOp device,
382 llvm::ArrayRef<ObjectFifoCreateOp> objectFifos);
386 bool fitsStreamAndBdBudgets(mlir::Operation *logicalTile,
TileID tile)
const;
389 void recordStreamAndBdUsage(mlir::Operation *logicalTile,
TileID tile);
391 bool hasAvailableChannels(
TileID tile,
int inputChannels,
int outputChannels);
393 mlir::LogicalResult validateAndUpdateChannelUsage(
394 LogicalTileOp logicalTile,
TileID tile,
395 const llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
396 &channelRequirements,
397 PlacementOrigin origin);
399 llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
400 buildChannelRequirements(
401 llvm::SmallVector<ObjectFifoCreateOp> &objectFifos,
402 llvm::SmallVector<ObjectFifoLinkOp> &objectFifoLinks);
405 struct PlacementContext {
406 const AIETargetModel &targetModel;
407 const Adjacency &computePeerAdjacency;
408 const llvm::DenseMap<mlir::Operation *, int> &needNeighborIn;
409 const llvm::DenseMap<mlir::Operation *, int> &needNeighborOut;
412 llvm::DenseMap<TileID, llvm::SmallVector<mlir::Operation *, 2>>
415 int neighborDemand(mlir::Operation *op)
const {
416 return needNeighborIn.lookup(op) + needNeighborOut.lookup(op);
421 int placementPriority(mlir::Operation *op)
const;
424 void reserveNeighborSlots(mlir::Operation *placedOp,
TileID at);
427 bool isReservedForOther(mlir::Operation *lto,
TileID candidate)
const;
435 struct AdjacencyKind {
436 const Adjacency &adjacency;
437 llvm::function_ref<bool(
TileID firstPos,
TileID secondPos)> pred;
438 llvm::function_ref<llvm::StringRef(
bool thisIsFirst)> peerLabel;
439 llvm::StringRef name;
440 llvm::StringRef constraintHint;
446 mlir::LogicalResult enforceAdjacency(LogicalTileOp logicalTile,
TileID tile,
447 const AdjacencyKind &kind);
454 void recordPlacement(LogicalTileOp logicalTile,
TileID tile,
455 PlacementContext &ctx, llvm::StringRef debugLabel);
460 struct UnpinnedPlacementInputs {
461 const Adjacency &bufferAdjacency;
463 const Adjacency &cascadeAdjacency;
465 const Adjacency &sharedMemAdjacency;
467 const Adjacency &computePeerAdjacency;
468 const llvm::DenseMap<mlir::Operation *, int> &needNeighborIn;
469 const llvm::DenseMap<mlir::Operation *, int> &needNeighborOut;
470 llvm::function_ref<bool(mlir::Operation *,
TileID)> isReservedForOther;
473 llvm::ArrayRef<int> preferredCols;
480 struct UnpinnedSearchResult {
481 std::optional<TileID> placement;
482 bool sawConstraintMatch =
false;
483 bool allConstraintMatchesFailedAdjacency =
true;
484 bool computePeerWasCause =
false;
494 findUnconstrainedCoreCandidate(LogicalTileOp logicalTile,
495 std::optional<int> col, std::optional<int> row,
496 const UnpinnedPlacementInputs &inputs);
502 buildBufferAdjacency(llvm::ArrayRef<LogicalTileOp> logicalTiles,
503 llvm::ArrayRef<ObjectFifoAllocateOp>
allocates);
507 struct FlowMembership {
508 llvm::DenseMap<mlir::Value,
509 llvm::SmallVector<llvm::SmallVector<mlir::Value>>>
517 mlir::LogicalResult placeNonCoreLogicalTiles(
518 llvm::ArrayRef<LogicalTileOp> logicalTiles,
519 const FlowMembership &flowIndex,
520 const llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
521 &channelRequirements);
528 llvm::DenseMap<mlir::Operation *, unsigned> groupOf;
529 llvm::SmallVector<llvm::SmallVector<LogicalTileOp>> members;
532 CoreGroups buildCoreGroups(llvm::ArrayRef<LogicalTileOp> logicalTiles,
533 const FlowMembership &flowIndex)
const;
539 llvm::SmallVector<int> preferredGroupColumns(LogicalTileOp logicalTile,
540 const CoreGroups &groups)
const;
543 buildFlowMembership(llvm::ArrayRef<FlowOp> flows,
544 llvm::ArrayRef<PacketFlowOp> pktFlows,
545 llvm::ArrayRef<RouteOp> routes,
546 llvm::ArrayRef<ObjectFifoCreateOp> objectFifos);
551 std::optional<int> computeCentroidColumn(LogicalTileOp logicalTile,
552 const FlowMembership &flowIndex);
554 mlir::LogicalResult placeNonCoreTileByCentroid(
555 LogicalTileOp logicalTile,
const FlowMembership &flowIndex,
556 const llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
557 &channelRequirements);
561 bool satisfiesAdjacency(
562 LogicalTileOp logicalTile,
TileID candidate,
const Adjacency &adjacency,
563 llvm::function_ref<
bool(
TileID firstPos,
TileID secondPos)> pred)
const;
573 bool satisfiesComputePeer(
574 LogicalTileOp logicalTile,
TileID candidate,
576 const llvm::DenseMap<mlir::Operation *, int> &needNeighborIn,
577 const llvm::DenseMap<mlir::Operation *, int> &needNeighborOut)
const;
582 static std::pair<int, int> totalComputePeers(mlir::Operation *op,
587 void attachPeerNotes(
588 mlir::InFlightDiagnostic &diag, LogicalTileOp logicalTile,
590 llvm::function_ref<llvm::StringRef(
bool thisIsFirst)> labelPeer)
const;
592 void addChannelRequirementsFromFlows(
593 llvm::ArrayRef<FlowOp> flows, llvm::ArrayRef<PacketFlowOp> pktFlows,
594 llvm::ArrayRef<RouteOp> routes,
595 llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
596 &channelRequirements);
732 : rngSeed(seed), config(config) {}
734 mlir::LogicalResult
place(DeviceOp device)
override;
735 llvm::StringRef
getName()
const override {
return "sa_placer"; }
747 CollectedOps collected;
748 llvm::DenseMap<mlir::Operation *, AIETileType> tileTypes;
749 llvm::DenseMap<mlir::Operation *, int64_t> staticBufferSizes;
750 llvm::DenseMap<mlir::Operation *, int64_t> stackSizes;
753 struct FifoBufferInfo {
754 mlir::Operation *fifoOp =
nullptr;
755 mlir::Operation *producer =
nullptr;
756 llvm::SmallVector<mlir::Operation *> consumers;
757 mlir::Operation *delegate =
nullptr;
758 int64_t producerSizeBytes = 0;
759 int64_t consumerSizeBytes = 0;
760 int producerDepth = 0;
761 llvm::SmallVector<int> consumerDepths;
762 int producerDMADepth = 0;
763 llvm::SmallVector<int> consumerDMADepths;
764 bool forcesDMA =
false;
765 bool linkSharedProd =
false;
767 int consumerDepthAt(
size_t ci)
const {
768 return (ci < consumerDepths.size()) ? consumerDepths[ci] : producerDepth;
771 llvm::SmallVector<NetInfo> nets;
772 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<size_t>> tileToNetIndices;
773 llvm::SmallVector<FifoBufferInfo> fifoBuffers;
777 struct RouteEndInfo {
778 mlir::Operation *tile;
781 llvm::SmallVector<RouteEndInfo> routeEnds;
782 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<size_t>> tileToRouteEnds;
784 llvm::DenseMap<mlir::Operation *, int> poolBDs;
787 llvm::DenseMap<mlir::Operation *, TileID> currentPlacement;
788 llvm::DenseMap<TileID, mlir::Operation *> physToLogical;
789 llvm::SmallVector<mlir::Operation *> movableTiles;
790 llvm::DenseSet<mlir::Operation *> constrainedTiles;
793 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<size_t>>
795 llvm::DenseMap<TileID, int64_t> currentMemUsage;
796 llvm::DenseMap<TileID, std::pair<int, int>> currentDMAUsage;
797 llvm::DenseMap<size_t, TileID> sharedMemDestination;
798 int cachedResourcePenalty = 0;
801 std::optional<ShimTransferSpans> shimSpans;
806 static constexpr std::pair<int, int> kCascadeOffsets[] = {{1, 0}, {0, -1}};
813 int bestCost = INT_MAX;
814 int bestOverallCost = INT_MAX;
818 int zeroDeltaMoves = 0, posDeltaMoves = 0, negDeltaMoves = 0;
819 int acceptedUphill = 0, rejectedMoves = 0;
820 std::chrono::steady_clock::time_point startTime;
823 mlir::LogicalResult collectAndBuildModel(DeviceOp device);
824 mlir::LogicalResult generateInitialPlacement();
825 void initializeSAState();
826 void runSAMainLoop();
827 mlir::LogicalResult finalizePlacement(DeviceOp device);
828 mlir::LogicalResult mergeMemShimTiles(DeviceOp device);
831 void initResourceTracking();
832 void addFifoContribution(
size_t fifoIdx,
int sign);
833 void addRouteEndContribution(
size_t endIdx,
int sign);
834 int updateResourcePenalty(
835 const llvm::SmallVector<std::pair<mlir::Operation *, TileID>>
837 int getResourcePenalty()
const {
return cachedResourcePenalty; }
838 int computePenalty()
const;
839 int computeMemSpilloverPenalty()
const;
840 int computeCoreOverflowPenalty()
const;
841 int computeDMAChannelPenalty()
const;
842 int computeBDCountPenalty()
const;
843 int computeDelegatePenalty()
const;
844 std::optional<TileID> positionOf(mlir::Operation *tile)
const;
845 int computeMemoryPressure()
const;
846 int computeAdjacencyPenalty(
const Adjacency &adj,
847 llvm::ArrayRef<std::pair<int, int>> validOffsets,
851 int computePairingPenalty()
const;
852 void generateAllocates();
855 void tryMove(llvm::SmallVector<std::pair<mlir::Operation *, TileID>> &moves);
857 generateMove(llvm::SmallVector<std::pair<mlir::Operation *, TileID>> &moves);
859 mlir::Operation *tile,
TileID newPos,
860 llvm::SmallVector<std::pair<size_t, NetBoundingBox>> &backups);
862 revertMove(llvm::SmallVector<std::pair<size_t, NetBoundingBox>> &backups);
865 void buildNetModel(llvm::SmallVector<ObjectFifoCreateOp> &objectFifos,
866 llvm::SmallVector<ObjectFifoLinkOp> &objectFifoLinks);
867 void buildFifoBufferInfo(DeviceOp device,
868 llvm::ArrayRef<ObjectFifoCreateOp> objectFifos,
869 llvm::ArrayRef<ObjectFifoLinkOp> objectFifoLinks);
870 void buildRouteModel(DeviceOp device, llvm::ArrayRef<RouteOp> routes);
871 int computeNetHPWL(
const NetInfo &net)
const;
872 int computeTotalHPWL()
const;
873 void initBoundingBoxes();
874 double estimateInitialTemperature(
int numSamples);
875 bool isLegalPosition(mlir::Operation *tile,
TileID pos)
const;
876 int64_t computeTileMemoryWeight(mlir::Operation *tile)
const;
877 void printPlacementStats(int64_t elapsedMs)
const;