275 bool mergeLogicalTiles =
true,
276 bool spreadUnanchoredTiles =
false)
277 : coresPerCol(coresPerCol), mergeLogicalTiles(mergeLogicalTiles),
278 spreadUnanchoredTiles(spreadUnanchoredTiles) {}
282 mlir::LogicalResult
place(DeviceOp device)
override;
284 llvm::StringRef
getName()
const override {
return "sequential_placer"; }
287 std::optional<int> coresPerCol;
288 bool mergeLogicalTiles;
291 bool spreadUnanchoredTiles;
295 llvm::DenseSet<TileID> assignedNonCoreTiles;
296 int deviceCoresPerCol = 0;
300 std::optional<ShimTransferSpans> shimSpans;
301 ShareableShimEnds shareableShimEnds;
302 llvm::DenseMap<TileID, std::array<llvm::SmallVector<mlir::StringAttr>, 2>>
304 bool fitsSharingShim(
TileID tile, mlir::Operation *logicalTile,
305 std::pair<int, int> required);
306 void recordShimEnds(
TileID tile, mlir::Operation *logicalTile);
311 DeviceOp device, llvm::ArrayRef<ObjectFifoCreateOp> objectFifos,
312 llvm::DenseMap<mlir::Operation *, std::pair<int, int>> &requirements);
315 enum class DmaDir { In, Out };
319 enum class PlacementOrigin { Pinned, Selected };
321 void limitCoresPerColumn(
int maxCoresPerCol,
int numColumns);
326 std::optional<TileID>
327 findTileWithCapacity(std::optional<int> targetCol,
328 llvm::ArrayRef<TileID> tiles,
int requiredInputChannels,
329 int requiredOutputChannels, AIETileType requestedType,
330 mlir::Operation *logicalTile,
bool withinBudgets);
341 struct CapacityDiagnosis {
342 bool capacityExistsSomewhere =
false;
344 int inUsed = 0, inMax = 0, outUsed = 0, outMax = 0;
346 int closestShortIn = 0, closestShortOut = 0;
348 CapacityDiagnosis diagnoseCapacityExhaustion(AIETileType requestedType,
349 int requiredInputChannels,
350 int requiredOutputChannels);
352 void updateChannelUsage(
TileID tile, DmaDir direction,
int numChannels);
356 llvm::DenseMap<mlir::Operation *, StreamDemand> streamDemand;
358 llvm::DenseMap<int, StreamDemand> columnStreamsUsed;
360 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<mlir::Operation *>>
362 llvm::DenseMap<int, llvm::DenseSet<mlir::Operation *>> columnIncomingFifos;
363 void recordColumnStreamUsage(mlir::Operation *tile,
int col);
365 llvm::DenseMap<mlir::Operation *, int> broadcastFanout;
366 llvm::DenseMap<TileID, int> broadcastFanoutUsed;
367 void buildStreamDemand(llvm::ArrayRef<ObjectFifoCreateOp> objectFifos);
371 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<int>> runtimeBdProfiles;
375 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<std::pair<int, int>>>
377 void buildRuntimeBdProfiles(DeviceOp device,
378 llvm::ArrayRef<ObjectFifoCreateOp> objectFifos);
382 bool fitsStreamAndBdBudgets(mlir::Operation *logicalTile,
TileID tile)
const;
385 void recordStreamAndBdUsage(mlir::Operation *logicalTile,
TileID tile);
387 bool hasAvailableChannels(
TileID tile,
int inputChannels,
int outputChannels);
389 mlir::LogicalResult validateAndUpdateChannelUsage(
390 LogicalTileOp logicalTile,
TileID tile,
391 const llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
392 &channelRequirements,
393 PlacementOrigin origin);
395 llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
396 buildChannelRequirements(
397 llvm::SmallVector<ObjectFifoCreateOp> &objectFifos,
398 llvm::SmallVector<ObjectFifoLinkOp> &objectFifoLinks);
401 struct PlacementContext {
402 const AIETargetModel &targetModel;
403 const Adjacency &computePeerAdjacency;
404 const llvm::DenseMap<mlir::Operation *, int> &needNeighborIn;
405 const llvm::DenseMap<mlir::Operation *, int> &needNeighborOut;
408 llvm::DenseMap<TileID, llvm::SmallVector<mlir::Operation *, 2>>
411 int neighborDemand(mlir::Operation *op)
const {
412 return needNeighborIn.lookup(op) + needNeighborOut.lookup(op);
417 int placementPriority(mlir::Operation *op)
const;
420 void reserveNeighborSlots(mlir::Operation *placedOp,
TileID at);
423 bool isReservedForOther(mlir::Operation *lto,
TileID candidate)
const;
431 struct AdjacencyKind {
432 const Adjacency &adjacency;
433 llvm::function_ref<bool(
TileID firstPos,
TileID secondPos)> pred;
434 llvm::function_ref<llvm::StringRef(
bool thisIsFirst)> peerLabel;
435 llvm::StringRef name;
436 llvm::StringRef constraintHint;
442 mlir::LogicalResult enforceAdjacency(LogicalTileOp logicalTile,
TileID tile,
443 const AdjacencyKind &kind);
450 void recordPlacement(LogicalTileOp logicalTile,
TileID tile,
451 PlacementContext &ctx, llvm::StringRef debugLabel);
456 struct UnpinnedPlacementInputs {
457 const Adjacency &bufferAdjacency;
459 const Adjacency &cascadeAdjacency;
461 const Adjacency &sharedMemAdjacency;
463 const Adjacency &computePeerAdjacency;
464 const llvm::DenseMap<mlir::Operation *, int> &needNeighborIn;
465 const llvm::DenseMap<mlir::Operation *, int> &needNeighborOut;
466 llvm::function_ref<bool(mlir::Operation *,
TileID)> isReservedForOther;
469 llvm::ArrayRef<int> preferredCols;
476 struct UnpinnedSearchResult {
477 std::optional<TileID> placement;
478 bool sawConstraintMatch =
false;
479 bool allConstraintMatchesFailedAdjacency =
true;
480 bool computePeerWasCause =
false;
490 findUnconstrainedCoreCandidate(LogicalTileOp logicalTile,
491 std::optional<int> col, std::optional<int> row,
492 const UnpinnedPlacementInputs &inputs);
498 buildBufferAdjacency(llvm::ArrayRef<LogicalTileOp> logicalTiles,
499 llvm::ArrayRef<ObjectFifoAllocateOp>
allocates);
503 struct FlowMembership {
504 llvm::DenseMap<mlir::Value,
505 llvm::SmallVector<llvm::SmallVector<mlir::Value>>>
513 mlir::LogicalResult placeNonCoreLogicalTiles(
514 llvm::ArrayRef<LogicalTileOp> logicalTiles,
515 const FlowMembership &flowIndex,
516 const llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
517 &channelRequirements);
524 llvm::DenseMap<mlir::Operation *, unsigned> groupOf;
525 llvm::SmallVector<llvm::SmallVector<LogicalTileOp>> members;
528 CoreGroups buildCoreGroups(llvm::ArrayRef<LogicalTileOp> logicalTiles,
529 const FlowMembership &flowIndex)
const;
535 llvm::SmallVector<int> preferredGroupColumns(LogicalTileOp logicalTile,
536 const CoreGroups &groups)
const;
539 buildFlowMembership(llvm::ArrayRef<FlowOp> flows,
540 llvm::ArrayRef<PacketFlowOp> pktFlows,
541 llvm::ArrayRef<RouteOp> routes,
542 llvm::ArrayRef<ObjectFifoCreateOp> objectFifos);
547 std::optional<int> computeCentroidColumn(LogicalTileOp logicalTile,
548 const FlowMembership &flowIndex);
550 mlir::LogicalResult placeNonCoreTileByCentroid(
551 LogicalTileOp logicalTile,
const FlowMembership &flowIndex,
552 const llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
553 &channelRequirements);
557 bool satisfiesAdjacency(
558 LogicalTileOp logicalTile,
TileID candidate,
const Adjacency &adjacency,
559 llvm::function_ref<
bool(
TileID firstPos,
TileID secondPos)> pred)
const;
569 bool satisfiesComputePeer(
570 LogicalTileOp logicalTile,
TileID candidate,
572 const llvm::DenseMap<mlir::Operation *, int> &needNeighborIn,
573 const llvm::DenseMap<mlir::Operation *, int> &needNeighborOut)
const;
578 static std::pair<int, int> totalComputePeers(mlir::Operation *op,
583 void attachPeerNotes(
584 mlir::InFlightDiagnostic &diag, LogicalTileOp logicalTile,
586 llvm::function_ref<llvm::StringRef(
bool thisIsFirst)> labelPeer)
const;
588 void addChannelRequirementsFromFlows(
589 llvm::ArrayRef<FlowOp> flows, llvm::ArrayRef<PacketFlowOp> pktFlows,
590 llvm::ArrayRef<RouteOp> routes,
591 llvm::DenseMap<mlir::Operation *, std::pair<int, int>>
592 &channelRequirements);
728 : rngSeed(seed), config(config) {}
730 mlir::LogicalResult
place(DeviceOp device)
override;
731 llvm::StringRef
getName()
const override {
return "sa_placer"; }
743 CollectedOps collected;
744 llvm::DenseMap<mlir::Operation *, AIETileType> tileTypes;
745 llvm::DenseMap<mlir::Operation *, int64_t> staticBufferSizes;
746 llvm::DenseMap<mlir::Operation *, int64_t> stackSizes;
749 struct FifoBufferInfo {
750 mlir::Operation *fifoOp =
nullptr;
751 mlir::Operation *producer =
nullptr;
752 llvm::SmallVector<mlir::Operation *> consumers;
753 mlir::Operation *delegate =
nullptr;
754 int64_t producerSizeBytes = 0;
755 int64_t consumerSizeBytes = 0;
756 int producerDepth = 0;
757 llvm::SmallVector<int> consumerDepths;
758 int producerDMADepth = 0;
759 llvm::SmallVector<int> consumerDMADepths;
760 bool forcesDMA =
false;
761 bool linkSharedProd =
false;
763 int consumerDepthAt(
size_t ci)
const {
764 return (ci < consumerDepths.size()) ? consumerDepths[ci] : producerDepth;
767 llvm::SmallVector<NetInfo> nets;
768 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<size_t>> tileToNetIndices;
769 llvm::SmallVector<FifoBufferInfo> fifoBuffers;
773 struct RouteEndInfo {
774 mlir::Operation *tile;
777 llvm::SmallVector<RouteEndInfo> routeEnds;
778 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<size_t>> tileToRouteEnds;
780 llvm::DenseMap<mlir::Operation *, int> poolBDs;
783 llvm::DenseMap<mlir::Operation *, TileID> currentPlacement;
784 llvm::DenseMap<TileID, mlir::Operation *> physToLogical;
785 llvm::SmallVector<mlir::Operation *> movableTiles;
786 llvm::DenseSet<mlir::Operation *> constrainedTiles;
789 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<size_t>>
791 llvm::DenseMap<TileID, int64_t> currentMemUsage;
792 llvm::DenseMap<TileID, std::pair<int, int>> currentDMAUsage;
793 llvm::DenseMap<size_t, TileID> sharedMemDestination;
794 int cachedResourcePenalty = 0;
797 std::optional<ShimTransferSpans> shimSpans;
802 static constexpr std::pair<int, int> kCascadeOffsets[] = {{1, 0}, {0, -1}};
809 int bestCost = INT_MAX;
810 int bestOverallCost = INT_MAX;
814 int zeroDeltaMoves = 0, posDeltaMoves = 0, negDeltaMoves = 0;
815 int acceptedUphill = 0, rejectedMoves = 0;
816 std::chrono::steady_clock::time_point startTime;
819 mlir::LogicalResult collectAndBuildModel(DeviceOp device);
820 mlir::LogicalResult generateInitialPlacement();
821 void initializeSAState();
822 void runSAMainLoop();
823 mlir::LogicalResult finalizePlacement(DeviceOp device);
824 mlir::LogicalResult mergeMemShimTiles(DeviceOp device);
827 void initResourceTracking();
828 void addFifoContribution(
size_t fifoIdx,
int sign);
829 void addRouteEndContribution(
size_t endIdx,
int sign);
830 int updateResourcePenalty(
831 const llvm::SmallVector<std::pair<mlir::Operation *, TileID>>
833 int getResourcePenalty()
const {
return cachedResourcePenalty; }
834 int computePenalty()
const;
835 int computeMemSpilloverPenalty()
const;
836 int computeCoreOverflowPenalty()
const;
837 int computeDMAChannelPenalty()
const;
838 int computeBDCountPenalty()
const;
839 int computeDelegatePenalty()
const;
840 std::optional<TileID> positionOf(mlir::Operation *tile)
const;
841 int computeMemoryPressure()
const;
842 int computeAdjacencyPenalty(
const Adjacency &adj,
843 llvm::ArrayRef<std::pair<int, int>> validOffsets,
847 int computePairingPenalty()
const;
848 void generateAllocates();
851 void tryMove(llvm::SmallVector<std::pair<mlir::Operation *, TileID>> &moves);
853 generateMove(llvm::SmallVector<std::pair<mlir::Operation *, TileID>> &moves);
855 mlir::Operation *tile,
TileID newPos,
856 llvm::SmallVector<std::pair<size_t, NetBoundingBox>> &backups);
858 revertMove(llvm::SmallVector<std::pair<size_t, NetBoundingBox>> &backups);
861 void buildNetModel(llvm::SmallVector<ObjectFifoCreateOp> &objectFifos,
862 llvm::SmallVector<ObjectFifoLinkOp> &objectFifoLinks);
863 void buildFifoBufferInfo(DeviceOp device,
864 llvm::ArrayRef<ObjectFifoCreateOp> objectFifos,
865 llvm::ArrayRef<ObjectFifoLinkOp> objectFifoLinks);
866 void buildRouteModel(DeviceOp device, llvm::ArrayRef<RouteOp> routes);
867 int computeNetHPWL(
const NetInfo &net)
const;
868 int computeTotalHPWL()
const;
869 void initBoundingBoxes();
870 double estimateInitialTemperature(
int numSamples);
871 bool isLegalPosition(mlir::Operation *tile,
TileID pos)
const;
872 int64_t computeTileMemoryWeight(mlir::Operation *tile)
const;
873 void printPlacementStats(int64_t elapsedMs)
const;