Skip to content

Commit

Permalink
Implement aie-assign-bd-ids pass (#1092)
Browse files Browse the repository at this point in the history
  • Loading branch information
makslevental authored Mar 5, 2024
1 parent c0a4daa commit 8368c00
Show file tree
Hide file tree
Showing 14 changed files with 691 additions and 183 deletions.
11 changes: 0 additions & 11 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,3 @@ CheckOptions:
value: camelBack
- key: readability-identifier-naming.VariableCase
value: camelBack
# Ours
- key: readability-identifier-naming.GlobalConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.LocalConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.StaticConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.ConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.ConstexprVariableCase
value: UPPER_CASE
5 changes: 4 additions & 1 deletion include/aie/Dialect/AIE/IR/AIEOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,10 @@ def AIE_DMABDOp: AIE_Op<"dma_bd", []> {
ins AnyMemRef:$buffer,
OptionalAttr<AIEI32Attr>:$offset,
OptionalAttr<AIEI32Attr>:$len,
OptionalAttr<BDDimLayoutArrayAttr>:$dimensions
OptionalAttr<BDDimLayoutArrayAttr>:$dimensions,
OptionalAttr<AIEI32Attr>:$bd_id,
// should never be assigned by user...
OptionalAttr<AIEI32Attr>:$next_bd_id
);

let hasVerifier = 1;
Expand Down
2 changes: 2 additions & 0 deletions include/aie/Dialect/AIE/Transforms/AIEPasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ createAIEObjectFifoStatefulTransformPass();
std::unique_ptr<mlir::OperationPass<DeviceOp>>
createAIEObjectFifoRegisterProcessPass();
std::unique_ptr<mlir::OperationPass<DeviceOp>> createAIELowerCascadeFlowsPass();
std::unique_ptr<mlir::OperationPass<DeviceOp>>
createAIEAssignBufferDescriptorIDsPass();

/// Generate the code for registering passes.
#define GEN_PASS_REGISTRATION
Expand Down
5 changes: 5 additions & 0 deletions include/aie/Dialect/AIE/Transforms/AIEPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ def AIELocalizeLocks : Pass<"aie-localize-locks", "DeviceOp"> {
let constructor = "xilinx::AIE::createAIELocalizeLocksPass()";
}

def AIEAssignBufferDescriptorIDs : Pass<"aie-assign-bd-ids", "DeviceOp"> {
let summary = "Assign bd ids to aie.dma_bd ops.";
let constructor = "xilinx::AIE::createAIEAssignBufferDescriptorIDsPass()";
}

def AIENormalizeAddressSpaces : Pass<"aie-normalize-address-spaces", "DeviceOp"> {
let summary = "Remove non-default address spaces";
let description = [{
Expand Down
17 changes: 15 additions & 2 deletions lib/Dialect/AIE/IR/AIEDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,9 +1514,22 @@ LogicalResult MemTileDMAOp::verify() {
LogicalResult DMAOp::verify() {
auto *parentOp = getOperation()->getParentOp();
if (parentOp->getRegion(0).getBlocks().size() > 1)
return emitOpError("DMA op can only appear in single block region");
return emitOpError("DMAOp can only appear in single block region");
if (!parentOp->getRegion(0).getOps<DMAStartOp>().empty())
return emitOpError("DMA op is not compatible with DMAStart ops");
return emitOpError("DMAOp is not compatible with DMAStart ops");
auto bdRegions = getBds();
for (auto &bdRegion : bdRegions) {
if (!bdRegion.hasOneBlock())
return emitOpError("DMAOp regions must have only one block");
auto bds = llvm::to_vector_of<DMABDOp>(bdRegion.front().getOps<DMABDOp>());
if (bds.size() != 1)
return emitOpError("DMAOp regions/blocks must have exactly one DMABDOp");
auto useLocks =
llvm::to_vector_of<UseLockOp>(bdRegion.front().getOps<UseLockOp>());
if (useLocks.size() != 2)
return emitOpError(
"DMAOp regions/blocks must have exactly two UseLock ops");
}
return success();
}

Expand Down
178 changes: 178 additions & 0 deletions lib/Dialect/AIE/Transforms/AIEAssignBufferDescriptorIDs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
//===- AIEAssignBufferDescriptorIDs.cpp -------------------------*- C++ -*-===//
//
// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// (c) Copyright 2024 Advanced Micro Devices Inc.
//
//===----------------------------------------------------------------------===//

#include "aie/Dialect/AIE/IR/AIEDialect.h"
#include "aie/Dialect/AIE/Transforms/AIEPasses.h"

#include "mlir/Pass/Pass.h"

#define DEBUG_TYPE "aie-assign-bd-ids"
#define EVEN_BD_ID_START 0
#define ODD_BD_ID_START 24

using namespace mlir;
using namespace xilinx;
using namespace xilinx::AIE;

struct BdIdGenerator {
BdIdGenerator(int col, int row, const AIETargetModel &targetModel)
: col(col), row(row), isMemTile(targetModel.isMemTile(col, row)) {}

int32_t nextBdId(int channelIndex) {
int32_t bdId = isMemTile && channelIndex & 1 ? oddBdId++ : evenBdId++;
while (bdIdAlreadyAssigned(bdId))
bdId = isMemTile && channelIndex & 1 ? oddBdId++ : evenBdId++;
assignBdId(bdId);
return bdId;
}

void assignBdId(int32_t bdId) {
assert(!alreadyAssigned.count(bdId) && "bdId has already been assigned");
alreadyAssigned.insert(bdId);
}

bool bdIdAlreadyAssigned(int32_t bdId) { return alreadyAssigned.count(bdId); }

int col;
int row;
int oddBdId = ODD_BD_ID_START;
int evenBdId = EVEN_BD_ID_START;
bool isMemTile;
std::set<int32_t> alreadyAssigned;
};

struct AIEAssignBufferDescriptorIDsPass
: AIEAssignBufferDescriptorIDsBase<AIEAssignBufferDescriptorIDsPass> {
void runOnOperation() override {
DeviceOp targetOp = getOperation();
const AIETargetModel &targetModel = targetOp.getTargetModel();

auto memOps = llvm::to_vector_of<TileElement>(targetOp.getOps<MemOp>());
llvm::append_range(memOps, targetOp.getOps<MemTileDMAOp>());
llvm::append_range(memOps, targetOp.getOps<ShimDMAOp>());
for (TileElement memOp : memOps) {
int col = memOp.getTileID().col;
int row = memOp.getTileID().row;

BdIdGenerator gen(col, row, targetModel);
memOp->walk<WalkOrder::PreOrder>([&](DMABDOp bd) {
if (bd.getBdId().has_value())
gen.assignBdId(bd.getBdId().value());
});

auto dmaOps = memOp.getOperation()->getRegion(0).getOps<DMAOp>();
if (!dmaOps.empty()) {
for (auto dmaOp : dmaOps) {
auto bdRegions = dmaOp.getBds();
for (auto &bdRegion : bdRegions) {
auto &block = bdRegion.getBlocks().front();
DMABDOp bd = *block.getOps<DMABDOp>().begin();
if (bd.getBdId().has_value())
assert(
gen.bdIdAlreadyAssigned(bd.getBdId().value()) &&
"bdId assigned by user but not found during previous walk");
else
bd.setBdId(gen.nextBdId(dmaOp.getChannelIndex()));
}
}
} else {
DenseMap<Block *, int> blockChannelMap;
// Associate with each block the channel index specified by the
// dma_start
for (Block &block : memOp.getOperation()->getRegion(0))
for (auto op : block.getOps<DMAStartOp>()) {
int chNum = op.getChannelIndex();
blockChannelMap[&block] = chNum;
Block *dest = op.getDest();
while (dest) {
blockChannelMap[dest] = chNum;
if (dest->hasNoSuccessors())
break;
dest = dest->getSuccessors()[0];
if (blockChannelMap.contains(dest))
dest = nullptr;
}
}

for (Block &block : memOp.getOperation()->getRegion(0)) {
if (block.getOps<DMABDOp>().empty())
continue;
assert(blockChannelMap.count(&block));
DMABDOp bd = (*block.getOps<DMABDOp>().begin());
if (bd.getBdId().has_value())
assert(gen.bdIdAlreadyAssigned(bd.getBdId().value()) &&
"bdId assigned by user but not found during previous walk");
else
bd.setBdId(gen.nextBdId(blockChannelMap[&block]));
}
}
}
for (TileElement memOp : memOps) {
auto dmaOps = memOp.getOperation()->getRegion(0).getOps<DMAOp>();
if (!dmaOps.empty()) {
for (auto dmaOp : dmaOps) {
auto bdRegions = dmaOp.getBds();
for (auto *bdRegionIt = bdRegions.begin();
bdRegionIt != bdRegions.end();) {
auto &block = bdRegionIt->getBlocks().front();
DMABDOp bd = *block.getOps<DMABDOp>().begin();
std::optional<int> nextBdId;
if (++bdRegionIt != bdRegions.end())
nextBdId =
(*bdRegionIt->getBlocks().front().getOps<DMABDOp>().begin())
.getBdId();
else if (dmaOp.getLoop())
nextBdId = (*bdRegions.front()
.getBlocks()
.front()
.getOps<DMABDOp>()
.begin())
.getBdId();
bd.setNextBdId(nextBdId);
}
}
} else {
DenseMap<Block *, int> blockBdIdMap;
for (Block &block : memOp.getOperation()->getRegion(0)) {
if (block.getOps<DMABDOp>().empty())
continue;
DMABDOp bd = *block.getOps<DMABDOp>().begin();
assert(bd.getBdId().has_value() &&
"DMABDOp should have bd_id assigned by now");
blockBdIdMap[&block] = bd.getBdId().value();
}

for (Block &block : memOp.getOperation()->getRegion(0)) {
if (block.getOps<DMABDOp>().empty())
continue;
DMABDOp bd = *block.getOps<DMABDOp>().begin();
std::optional<int> nextBdId;
if (block.getNumSuccessors()) {
assert(llvm::range_size(block.getSuccessors()) == 1 &&
"should have only one successor block");
Block *nextBlock = block.getSuccessor(0);
if (!blockBdIdMap.contains(nextBlock))
assert(nextBlock->getOperations().size() == 1 &&
isa<EndOp>(nextBlock->getOperations().front()) &&
"bb that's not in blockMap can only have aie.end");
else
nextBdId = blockBdIdMap[nextBlock];
bd.setNextBdId(nextBdId);
}
}
}
}
}
};

std::unique_ptr<OperationPass<DeviceOp>>
AIE::createAIEAssignBufferDescriptorIDsPass() {
return std::make_unique<AIEAssignBufferDescriptorIDsPass>();
}
1 change: 1 addition & 0 deletions lib/Dialect/AIE/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
add_mlir_dialect_library(
AIETransforms
AIEAssignBuffers.cpp
AIEAssignBufferDescriptorIDs.cpp
AIEAssignLockIDs.cpp
AIEFindFlows.cpp
AIEPathFinder.cpp
Expand Down
Loading

0 comments on commit 8368c00

Please sign in to comment.