diff --git a/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/AMDAIETypes.cpp b/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/AMDAIETypes.cpp index 3b7654330..162f995a9 100644 --- a/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/AMDAIETypes.cpp +++ b/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/AMDAIETypes.cpp @@ -32,11 +32,6 @@ void AMDAIEDialect::initializeAMDAIETypes() { LogicalResult LogicalObjectFifoType::verify( llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::MemRefType elementType, unsigned depth) { - if (llvm::any_of(elementType.getShape(), [](auto dimSize) { - return ShapedType::isDynamic(dimSize); - })) { - return emitError() << "should encapsulate static memref"; - } if (depth < 1 || depth > 4) return emitError() << "depth should be in [1, 4]"; return success(); } diff --git a/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/test/invalid.mlir b/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/test/invalid.mlir index 1b580843f..1a778ea86 100644 --- a/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/test/invalid.mlir +++ b/compiler/plugins/target/AMD-AIE/iree-amd-aie/IR/test/invalid.mlir @@ -20,11 +20,6 @@ func.func @logicalobjectfifo_tensor(!amdaie.logicalobjectfifo<tensor<8x16xi32>>) // ----- -// expected-error @+1 {{should encapsulate static memref}} -func.func @logicalobjectfifo_dynamic(!amdaie.logicalobjectfifo<memref<?x8x16xi32>>) - -// ----- - func.func @circular_dma_cpy_nd_invalid_src_offsets() { %c0 = arith.constant 0 : index %c1 = arith.constant 1 : index diff --git a/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/AMDAIEGenerateControlOverlay.cpp b/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/AMDAIEGenerateControlOverlay.cpp index 4087ee6b1..909611e19 100644 --- a/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/AMDAIEGenerateControlOverlay.cpp +++ b/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/AMDAIEGenerateControlOverlay.cpp @@ -17,7 +17,7 @@ namespace mlir::iree_compiler::AMDAIE { namespace { /// Initializes the channel generators for the shim tiles, excluding any -/// channels that are already in use by existing circuit flows. +/// channels that are already in use by existing circuit-mode connections. LogicalResult initializeChannelsGenerators( AMDAIE::WorkgroupOp workgroupOp, const AMDAIEDeviceModel &deviceModel, const DenseSet<TileOp> &shimTileOps, @@ -29,11 +29,15 @@ LogicalResult initializeChannelsGenerators( shimTileToGeneratorMap[shimTileOp.getResult()] = ChannelGenerator(numShimDmaChannels, numShimDmaChannels); }); - // Exclude those channels that are already used by a circuit flow. - workgroupOp->walk([&](AMDAIE::FlowOp flowOp) { - if (flowOp.getIsPacketFlow()) return WalkResult::advance(); + // Exclude those channels that are already used by a circuit-mode connection. + workgroupOp->walk([&](AMDAIE::ConnectionOp connectionOp) { + std::optional<AMDAIE::ConnectionType> connectionType = + connectionOp.getConnectionType(); + bool isPacketFlow = connectionType && connectionType.value() == + AMDAIE::ConnectionType::Packet; + if (isPacketFlow) return WalkResult::advance(); SmallVector<AMDAIE::ChannelOp> sourceChannels; - for (Value source : flowOp.getSources()) { + for (Value source : connectionOp.getSourceChannels()) { if (auto channelOp = dyn_cast<AMDAIE::ChannelOp>(source.getDefiningOp())) { sourceChannels.push_back(channelOp); @@ -97,8 +101,8 @@ LogicalResult generateControlOverlay(AMDAIE::WorkgroupOp workgroupOp, } } - // Create a packet flow from the shim DMA to the tile CTRL, for sending - // control packets. + // Create a packet-mode connection from the shim DMA to the tile CTRL, for + // sending control packets. if (routeShimToTileCtrl) { DenseMap<Value, ChannelGenerator> shimTileToGeneratorMap; DenseSet<TileOp> shimTileOps; @@ -111,7 +115,7 @@ LogicalResult generateControlOverlay(AMDAIE::WorkgroupOp workgroupOp, uint32_t col = getConstantIndexOrAssert(tileOp.getCol()); TileOp shimTileOp = columnToShimTile[col]; // Get the available channel, but do not assign it. Allow it to be - // shared across multiple packet flows as needed. + // shared across multiple packet-mode connections as needed. std::optional<uint8_t> maybeChannel = shimTileToGeneratorMap[shimTileOp.getResult()] .getProducerDMAChannel(); @@ -119,35 +123,69 @@ LogicalResult generateControlOverlay(AMDAIE::WorkgroupOp workgroupOp, shimTileOp.emitOpError() << "no producer DMA channel available"; return WalkResult::interrupt(); } - auto shimDmaChannelOp = rewriter.create<AMDAIE::ChannelOp>( + auto sourceChannelOp = rewriter.create<AMDAIE::ChannelOp>( rewriter.getUnknownLoc(), shimTileOp, maybeChannel.value(), StrmSwPortType::DMA, AMDAIE::DMAChannelDir::MM2S); - auto tileCtrlChannelOp = rewriter.create<AMDAIE::ChannelOp>( + auto targetChannelOp = rewriter.create<AMDAIE::ChannelOp>( rewriter.getUnknownLoc(), tileOp, 0, StrmSwPortType::CTRL, AMDAIE::DMAChannelDir::S2MM); - rewriter.create<AMDAIE::FlowOp>( - rewriter.getUnknownLoc(), ValueRange{shimDmaChannelOp}, - ValueRange{tileCtrlChannelOp}, - /*isPacketFlow*/ true, /*packetId*/ nullptr); + + // Get the objectfifo placeholder for both the source and target. + MemRefType elementType = + MemRefType::get(ShapedType::kDynamic, rewriter.getI32Type()); + auto sourcePlaceholder = + rewriter.create<AMDAIE::LogicalObjectFifoPlaceholderOp>( + rewriter.getUnknownLoc(), LogicalObjectFifoType::get(elementType), + ValueRange(shimTileOp)); + auto targetPlaceholder = + rewriter.create<AMDAIE::LogicalObjectFifoPlaceholderOp>( + rewriter.getUnknownLoc(), LogicalObjectFifoType::get(elementType), + ValueRange(tileOp)); + + rewriter.create<AMDAIE::ConnectionOp>( + rewriter.getUnknownLoc(), targetPlaceholder, + ValueRange{targetChannelOp}, sourcePlaceholder, + ValueRange{sourceChannelOp}, + ConnectionTypeAttr::get(rewriter.getContext(), + ConnectionType::Packet), + /*flow=*/nullptr); return WalkResult::advance(); }); if (res.wasInterrupted()) return failure(); } - // Create a circuit flow from the shim CTRL to the shim SOUTH 0, for sending - // Task Completion Tokens (TCTs). + // Create a circuit-mode connection from the shim CTRL to the shim SOUTH 0, + // for sending Task Completion Tokens (TCTs). if (routeShimCtrlToTct) { for (auto [_, shimTileOp] : columnToShimTile) { - auto shimCtrlChannelOp = rewriter.create<AMDAIE::ChannelOp>( + auto sourceChannelOp = rewriter.create<AMDAIE::ChannelOp>( rewriter.getUnknownLoc(), shimTileOp, 0, StrmSwPortType::CTRL, AMDAIE::DMAChannelDir::MM2S); - auto shimSouthChannelOp = rewriter.create<AMDAIE::ChannelOp>( + auto targetChannelOp = rewriter.create<AMDAIE::ChannelOp>( rewriter.getUnknownLoc(), shimTileOp, 0, StrmSwPortType::SOUTH, AMDAIE::DMAChannelDir::S2MM); - rewriter.create<AMDAIE::FlowOp>( - rewriter.getUnknownLoc(), ValueRange{shimCtrlChannelOp}, - ValueRange{shimSouthChannelOp}, - /*isPacketFlow*/ false, /*packetId*/ nullptr); + + // Get the objectfifo placeholder for both the source and target. + // Set the shape to dynamic because the size of the control packet + // sequence is unknown and may vary based on the reconfiguration content. + MemRefType elementType = + MemRefType::get(ShapedType::kDynamic, rewriter.getI32Type()); + auto sourcePlaceholder = + rewriter.create<AMDAIE::LogicalObjectFifoPlaceholderOp>( + rewriter.getUnknownLoc(), LogicalObjectFifoType::get(elementType), + ValueRange(shimTileOp)); + auto targetPlaceholder = + rewriter.create<AMDAIE::LogicalObjectFifoPlaceholderOp>( + rewriter.getUnknownLoc(), LogicalObjectFifoType::get(elementType), + ValueRange(shimTileOp)); + + rewriter.create<AMDAIE::ConnectionOp>( + rewriter.getUnknownLoc(), targetPlaceholder, + ValueRange{targetChannelOp}, sourcePlaceholder, + ValueRange{sourceChannelOp}, + ConnectionTypeAttr::get(rewriter.getContext(), + ConnectionType::Circuit), + /*flow=*/nullptr); } } diff --git a/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/Passes.cpp b/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/Passes.cpp index 50fe1ffd1..610e63d2d 100644 --- a/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/Passes.cpp +++ b/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/Passes.cpp @@ -884,12 +884,10 @@ void addAMDAIEObjectFifoLoweringPasses( passManager.addPass(createAMDAIEObjFifoBufferizationPass()); passManager.addPass(createAMDAIETemporaryAllocBufferizationPass()); - passManager.addPass(createAMDAIEConnectionToFlowPass()); passManager.addPass(createAMDAIEGenerateControlOverlayPass()); - passManager.addPass(createCSEPass()); - passManager.addPass(createCanonicalizerPass()); + passManager.addPass(createAMDAIEConnectionToFlowPass()); passManager.addPass(createAMDAIEAssignPacketIdsPass()); passManager.addPass(createAMDAIENpuDmaToHalfDmaCpyNdPass()); diff --git a/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/test/generate_control_overlay.mlir b/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/test/generate_control_overlay.mlir index c5857e7ad..c58e7cebe 100644 --- a/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/test/generate_control_overlay.mlir +++ b/compiler/plugins/target/AMD-AIE/iree-amd-aie/Transforms/test/generate_control_overlay.mlir @@ -1,4 +1,4 @@ -// RUN: iree-opt --pass-pipeline="builtin.module(func.func(iree-amdaie-generate-control-overlay{route-shim-to-tct=true route-shim-to-tile-ctrl=true},canonicalize,cse))" --split-input-file --verify-diagnostics %s | FileCheck %s +// RUN: iree-opt --pass-pipeline="builtin.module(func.func(iree-amdaie-generate-control-overlay{route-shim-to-tct=true route-shim-to-tile-ctrl=true}))" --split-input-file --verify-diagnostics %s | FileCheck %s // Device attribute is required for route-shim-to-tile-ctrl. module { @@ -16,7 +16,7 @@ module { // ----- // Shim tile (0, 0) has two producer (MM2S) channels, -// both of which are already utilized by existing circuit flows. +// both of which are already utilized by existing circuit-mode connections. // No producer DMA channel is available for route-shim-to-tile-ctrl. #executable_target_amdaie_xclbin_fb = #hal.executable.target<"amd-aie", "amdaie-xclbin-fb", {target_device = "npu1_4col", ukernels = "none"}> module attributes {hal.executable.target = #executable_target_amdaie_xclbin_fb} { @@ -27,12 +27,16 @@ module attributes {hal.executable.target = #executable_target_amdaie_xclbin_fb} // expected-error @+1 {{no producer DMA channel available}} %tile_0_0 = amdaie.tile(%c0, %c0) %tile_0_1 = amdaie.tile(%c0, %c1) + %0 = amdaie.logicalobjectfifo.placeholder{%tile_0_0} : !amdaie.logicalobjectfifo<memref<32xi32>> + %1 = amdaie.logicalobjectfifo.placeholder{%tile_0_1} : !amdaie.logicalobjectfifo<memref<32xi32>> + %2 = amdaie.logicalobjectfifo.placeholder{%tile_0_0} : !amdaie.logicalobjectfifo<memref<32xi32>> + %3 = amdaie.logicalobjectfifo.placeholder{%tile_0_1} : !amdaie.logicalobjectfifo<memref<32xi32>> %channel_0 = amdaie.channel(%tile_0_0, 0, port_type = DMA, direction = MM2S) %channel_1 = amdaie.channel(%tile_0_1, 0, port_type = DMA, direction = S2MM) - %flow_0 = amdaie.flow({%channel_0} -> {%channel_1}) {is_packet_flow = false} + %connection_0 = amdaie.connection(%1 {%channel_1}, %0 {%channel_0}) : (!amdaie.logicalobjectfifo<memref<32xi32>>, !amdaie.logicalobjectfifo<memref<32xi32>>) %channel_2 = amdaie.channel(%tile_0_0, 1, port_type = DMA, direction = MM2S) %channel_3 = amdaie.channel(%tile_0_1, 1, port_type = DMA, direction = S2MM) - %flow_1 = amdaie.flow({%channel_2} -> {%channel_3}) {is_packet_flow = false} + %connection_1 = amdaie.connection(%3 {%channel_3}, %2 {%channel_2}) : (!amdaie.logicalobjectfifo<memref<32xi32>>, !amdaie.logicalobjectfifo<memref<32xi32>>) amdaie.controlcode { amdaie.end } @@ -62,21 +66,25 @@ module attributes {hal.executable.target = #executable_target_amdaie_xclbin_fb} // CHECK: %[[TILE_0_5:.*]] = amdaie.tile(%[[C0]], %[[C5]]) // CHECK: %[[CHANNEL_0:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = DMA, direction = MM2S) // CHECK: %[[CHANNEL_1:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = CTRL, direction = S2MM) -// CHECK: %[[FLOW_0:.*]] = amdaie.flow({%[[CHANNEL_0]]} -> {%[[CHANNEL_1]]}) {is_packet_flow = true} +// CHECK: %[[CONNECT_0:.*]] = amdaie.connection(%{{.+}} {%[[CHANNEL_1]]}, %{{.+}} {%[[CHANNEL_0]]}) {connection_type = #amdaie<connection_type Packet>} // CHECK: %[[CHANNEL_2:.*]] = amdaie.channel(%[[TILE_0_0]], 1, port_type = DMA, direction = MM2S) // CHECK: %[[CHANNEL_3:.*]] = amdaie.channel(%[[TILE_0_1]], 0, port_type = CTRL, direction = S2MM) -// CHECK: %[[FLOW_1:.*]] = amdaie.flow({%[[CHANNEL_2]]} -> {%[[CHANNEL_3]]}) {is_packet_flow = true} -// CHECK: %[[CHANNEL_4:.*]] = amdaie.channel(%[[TILE_0_2]], 0, port_type = CTRL, direction = S2MM) -// CHECK: %[[FLOW_2:.*]] = amdaie.flow({%[[CHANNEL_0]]} -> {%[[CHANNEL_4]]}) {is_packet_flow = true} -// CHECK: %[[CHANNEL_5:.*]] = amdaie.channel(%[[TILE_0_3]], 0, port_type = CTRL, direction = S2MM) -// CHECK: %[[FLOW_3:.*]] = amdaie.flow({%[[CHANNEL_2]]} -> {%[[CHANNEL_5]]}) {is_packet_flow = true} -// CHECK: %[[CHANNEL_6:.*]] = amdaie.channel(%[[TILE_0_4]], 0, port_type = CTRL, direction = S2MM) -// CHECK: %[[FLOW_4:.*]] = amdaie.flow({%[[CHANNEL_0]]} -> {%[[CHANNEL_6]]}) {is_packet_flow = true} -// CHECK: %[[CHANNEL_7:.*]] = amdaie.channel(%[[TILE_0_5]], 0, port_type = CTRL, direction = S2MM) -// CHECK: %[[FLOW_5:.*]] = amdaie.flow({%[[CHANNEL_2]]} -> {%[[CHANNEL_7]]}) {is_packet_flow = true} -// CHECK: %[[CHANNEL_8:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = CTRL, direction = MM2S) -// CHECK: %[[CHANNEL_9:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = SOUTH, direction = S2MM) -// CHECK: %[[FLOW_6:.*]] = amdaie.flow({%[[CHANNEL_8]]} -> {%[[CHANNEL_9]]}) {is_packet_flow = false} +// CHECK: %[[CONNECT_1:.*]] = amdaie.connection(%{{.+}} {%[[CHANNEL_3]]}, %{{.+}} {%[[CHANNEL_2]]}) {connection_type = #amdaie<connection_type Packet>} +// CHECK: %[[CHANNEL_4:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = DMA, direction = MM2S) +// CHECK: %[[CHANNEL_5:.*]] = amdaie.channel(%[[TILE_0_2]], 0, port_type = CTRL, direction = S2MM) +// CHECK: %[[CONNECT_2:.*]] = amdaie.connection(%{{.+}} {%[[CHANNEL_5]]}, %{{.+}} {%[[CHANNEL_4]]}) {connection_type = #amdaie<connection_type Packet>} +// CHECK: %[[CHANNEL_6:.*]] = amdaie.channel(%[[TILE_0_0]], 1, port_type = DMA, direction = MM2S) +// CHECK: %[[CHANNEL_7:.*]] = amdaie.channel(%[[TILE_0_3]], 0, port_type = CTRL, direction = S2MM) +// CHECK: %[[CONNECT_3:.*]] = amdaie.connection(%{{.+}} {%[[CHANNEL_7]]}, %{{.+}} {%[[CHANNEL_6]]}) {connection_type = #amdaie<connection_type Packet>} +// CHECK: %[[CHANNEL_8:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = DMA, direction = MM2S) +// CHECK: %[[CHANNEL_9:.*]] = amdaie.channel(%[[TILE_0_4]], 0, port_type = CTRL, direction = S2MM) +// CHECK: %[[CONNECT_4:.*]] = amdaie.connection(%{{.+}} {%[[CHANNEL_9]]}, %{{.+}} {%[[CHANNEL_8]]}) {connection_type = #amdaie<connection_type Packet>} +// CHECK: %[[CHANNEL_10:.*]] = amdaie.channel(%[[TILE_0_0]], 1, port_type = DMA, direction = MM2S) +// CHECK: %[[CHANNEL_11:.*]] = amdaie.channel(%[[TILE_0_5]], 0, port_type = CTRL, direction = S2MM) +// CHECK: %[[CONNECT_5:.*]] = amdaie.connection(%{{.+}} {%[[CHANNEL_11]]}, %{{.+}} {%[[CHANNEL_10]]}) {connection_type = #amdaie<connection_type Packet>} +// CHECK: %[[CHANNEL_12:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = CTRL, direction = MM2S) +// CHECK: %[[CHANNEL_13:.*]] = amdaie.channel(%[[TILE_0_0]], 0, port_type = SOUTH, direction = S2MM) +// CHECK: %[[CONNECT_6:.*]] = amdaie.connection(%{{.+}} {%[[CHANNEL_13]]}, %{{.+}} {%[[CHANNEL_12]]}) {connection_type = #amdaie<connection_type Circuit>} #executable_target_amdaie_xclbin_fb = #hal.executable.target<"amd-aie", "amdaie-xclbin-fb", {target_device = "npu1_4col", ukernels = "none"}> module attributes {hal.executable.target = #executable_target_amdaie_xclbin_fb} { func.func @column_control_overlay() {