From 66c663f534e46428dc287946d9a4754fbab26765 Mon Sep 17 00:00:00 2001 From: abisca Date: Mon, 19 Feb 2024 15:22:49 -0700 Subject: [PATCH 01/12] Changed implementation for L1toL2 1-to-1 support --- mlir/lib/Conversion/AIRToAIEPass.cpp | 103 ++++++++++++++++----------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 2132c232c..293d86912 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1032,10 +1032,10 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { LowerAIRChannelsPattern( MLIRContext *ctx, ShimTileAllocator &shimTileAlloc, std::map &bufferToMemtileMap, - std::map &linksToComplete) + std::map, std::vector>> &linkEnds) : OpRewritePattern(ctx), shimTileAlloc(shimTileAlloc), bufferToMemtileMap(bufferToMemtileMap), - linksToComplete(linksToComplete) {} + linkEnds(linkEnds) {} LogicalResult matchAndRewrite(air::ChannelOp channel, PatternRewriter &rewriter) const override { @@ -1054,11 +1054,10 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { std::vector channelGets = getChannelGetOpThroughSymbol(channel, device); - // keep track of potential LinkOp - bool linkToComplete = - false; // track if objFifo has to be added to linksToComplete - bool linkFound = false; // all ends of a link have been found - Operation *endOfLink; // one end of a link + // variables to track LinkOp, i.e., a put and get using the same AIE.BufferOp + bool linkFound = false; // a link end is found + Operation *endOfLink; // one end of a LinkOp (i.e., a put or get) + int numLinkEnds = 0; // # ends in this link (i.e., # users of AIE.BufferOp) // put/get come in pairs, if one is missing then it's L3 Value producerTile; @@ -1071,22 +1070,25 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { if (res.failed()) return res; - // check if this put is linked to a get from another channel + // check if this put is linked to a get from another channel that... MemRefType memref = channelPuts[0].getMemref().getType().cast(); int mem_space = memref.getMemorySpaceAsInt(); if (mem_space == (int)air::MemorySpace::L2) { - if (linksToComplete.find(channelPuts[0].getOperation()) != - linksToComplete.end()) { + AIE::BufferOp buff = dyn_cast( + channelPuts[0].getMemref().getDefiningOp()); + // ... has already been found in another channel + if (linkEnds.find(buff) != linkEnds.end()) { endOfLink = channelPuts[0].getOperation(); linkFound = true; + + // ... has not been found yet } else { - AIE::BufferOp buff = dyn_cast( - channelPuts[0].getMemref().getDefiningOp()); for (auto user : buff->getUsers()) { + numLinkEnds++; if (auto pairedGet = dyn_cast(user)) { - endOfLink = pairedGet.getOperation(); - linkToComplete = true; + endOfLink = channelPuts[0].getOperation(); + linkFound = true; } } } @@ -1112,20 +1114,24 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { return res; consumers.push_back(consumerTile); - // check if this get is linked to a put from another channel + // check if this get is linked to a put from another channel that... MemRefType memref = get.getMemref().getType().cast(); int mem_space = memref.getMemorySpaceAsInt(); if (mem_space == (int)air::MemorySpace::L2) { - if (linksToComplete.find(get.getOperation()) != linksToComplete.end()) { + AIE::BufferOp buff = dyn_cast( + get.getMemref().getDefiningOp()); + // ... has already been found in another channel + if (linkEnds.find(buff) != linkEnds.end()) { endOfLink = get.getOperation(); linkFound = true; + + // ... has not been found yet } else { - AIE::BufferOp buff = - dyn_cast(get.getMemref().getDefiningOp()); for (auto user : buff->getUsers()) { + numLinkEnds++; if (auto pairedPut = dyn_cast(user)) { - endOfLink = pairedPut.getOperation(); - linkToComplete = true; + endOfLink = get.getOperation(); + linkFound = true; } } } @@ -1148,24 +1154,41 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { rewriter, datatype, producerTile, consumers, channel.getBufferResources(), "air_" + channel.getName().str()); - // if this channel's get is linked with another put, register it - if (linkToComplete) - linksToComplete[endOfLink] = objFifo; - // once the corresponding objFifo has been made, complete the link + // if a link end was found if (linkFound) { - AIE::ObjectFifoCreateOp producerFifo = linksToComplete[endOfLink]; - if (isa(endOfLink)) - rewriter.create( - rewriter.getUnknownLoc(), - rewriter.getArrayAttr({SymbolRefAttr::get(ctx, objFifo.name())}), - rewriter.getArrayAttr( - {SymbolRefAttr::get(ctx, producerFifo.name())})); - else + AIE::BufferOp buff; + // if get: add to input objectFifo vector + if (auto get = dyn_cast(endOfLink)) { + buff = dyn_cast(get.getMemref().getDefiningOp()); + if (linkEnds.find(buff) == linkEnds.end()) { + std::vector input_ofs; + std::vector output_ofs; + linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; + } + std::get<1>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); + + // if put: add to output objectFifo vector + } else if (auto put = dyn_cast(endOfLink)) { + buff = dyn_cast(put.getMemref().getDefiningOp()); + if (linkEnds.find(buff) == linkEnds.end()) { + std::vector input_ofs; + std::vector output_ofs; + linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; + } + std::get<2>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); + } + + // check if all ends have been found + auto numEnds = std::get<0>(linkEnds[buff]); + auto input_ofs = std::get<1>(linkEnds[buff]); + auto output_ofs = std::get<2>(linkEnds[buff]); + // if yes, create ObjectFifoLinkOp + if (input_ofs.size() + output_ofs.size() == numEnds) { rewriter.create( rewriter.getUnknownLoc(), - rewriter.getArrayAttr( - {SymbolRefAttr::get(ctx, producerFifo.name())}), - rewriter.getArrayAttr({SymbolRefAttr::get(ctx, objFifo.name())})); + rewriter.getArrayAttr(ArrayRef(input_ofs)), + rewriter.getArrayAttr(ArrayRef(output_ofs))); + } } // replace put/get and any associated memref alloc/dealloc @@ -1318,7 +1341,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { ShimTileAllocator &shimTileAlloc; std::map &bufferToMemtileMap; - std::map &linksToComplete; + std::map, std::vector>> &linkEnds; // map L2 AIE.BufferOps to pairs of vectors of SymbolRefAttr () }; // This function replaces ChannelPutOp/ChannelGetOp with AIE_CreateObjectFifoOps @@ -1330,9 +1353,9 @@ void lowerAIRChannels( std::map &bufferToMemtileMap) { auto ctx = d->getContext(); RewritePatternSet patterns(ctx); - std::map linksToComplete; + std::map, std::vector>> linkEnds; patterns.insert(ctx, s, bufferToMemtileMap, - linksToComplete); + linkEnds); (void)applyPatternsAndFoldGreedily(d, std::move(patterns)); } @@ -2769,10 +2792,10 @@ class AIRToAIEPass : public air::impl::AIRToAIEBase { builder.getUnknownLoc(), AIE::AIEDeviceAttr::get(builder.getContext(), *device)); ShimTileAllocator shimTileAlloc(deviceOp.getTargetModel()); - std::map linksToComplete; + std::map, std::vector>> linkEnds; if (clTestPatterns.find("lower-air-channels") != std::string::npos) { patterns.insert( - ctx, shimTileAlloc, bufferToMemtileMap, linksToComplete); + ctx, shimTileAlloc, bufferToMemtileMap, linkEnds); } if (clTestPatterns.find("lower-air-ping-pong") != std::string::npos) { patterns.insert(ctx); From 9922622f56b2946e93067b7819a6cdb7d965706f Mon Sep 17 00:00:00 2001 From: abisca Date: Tue, 20 Feb 2024 09:28:51 -0700 Subject: [PATCH 02/12] Added tests for join and distribute. Current errors: join and distribute objectFifos are not ordered according to memref indices, and objectFifos from L1 to L2 in join case don't have correct size. --- mlir/lib/Conversion/AIRToAIEPass.cpp | 143 ++++++++++-------- .../air_channel_to_objectfifo_distribute.mlir | 85 +++++++++++ .../air_channel_to_objectfifo_join.mlir | 82 ++++++++++ 3 files changed, 244 insertions(+), 66 deletions(-) create mode 100755 mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_distribute.mlir create mode 100755 mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_join.mlir diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 293d86912..46a01f0f8 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1055,9 +1055,9 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { getChannelGetOpThroughSymbol(channel, device); // variables to track LinkOp, i.e., a put and get using the same AIE.BufferOp - bool linkFound = false; // a link end is found - Operation *endOfLink; // one end of a LinkOp (i.e., a put or get) - int numLinkEnds = 0; // # ends in this link (i.e., # users of AIE.BufferOp) + bool linkFound = false; // a link end is found + Operation *endOfLink = nullptr; // one end of a LinkOp (i.e., a put or get) + int numLinkEnds = 0; // # ends in this link (i.e., # users of AIE.BufferOp) // put/get come in pairs, if one is missing then it's L3 Value producerTile; @@ -1070,28 +1070,15 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { if (res.failed()) return res; - // check if this put is linked to a get from another channel that... + // check if this put is linked to a get from another channel MemRefType memref = channelPuts[0].getMemref().getType().cast(); int mem_space = memref.getMemorySpaceAsInt(); if (mem_space == (int)air::MemorySpace::L2) { - AIE::BufferOp buff = dyn_cast( - channelPuts[0].getMemref().getDefiningOp()); - // ... has already been found in another channel - if (linkEnds.find(buff) != linkEnds.end()) { + linkFound = detectLinkEnd(rewriter, channelPuts[0], + &numLinkEnds); + if (linkFound) endOfLink = channelPuts[0].getOperation(); - linkFound = true; - - // ... has not been found yet - } else { - for (auto user : buff->getUsers()) { - numLinkEnds++; - if (auto pairedGet = dyn_cast(user)) { - endOfLink = channelPuts[0].getOperation(); - linkFound = true; - } - } - } } } else { // put from L3 @@ -1114,27 +1101,13 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { return res; consumers.push_back(consumerTile); - // check if this get is linked to a put from another channel that... + // check if this get is linked to a put from another channel MemRefType memref = get.getMemref().getType().cast(); int mem_space = memref.getMemorySpaceAsInt(); if (mem_space == (int)air::MemorySpace::L2) { - AIE::BufferOp buff = dyn_cast( - get.getMemref().getDefiningOp()); - // ... has already been found in another channel - if (linkEnds.find(buff) != linkEnds.end()) { + linkFound = detectLinkEnd(rewriter, get, &numLinkEnds); + if (linkFound) endOfLink = get.getOperation(); - linkFound = true; - - // ... has not been found yet - } else { - for (auto user : buff->getUsers()) { - numLinkEnds++; - if (auto pairedPut = dyn_cast(user)) { - endOfLink = get.getOperation(); - linkFound = true; - } - } - } } } for (int i = 0; i < expectedGets - (int)channelGets.size(); i++) { @@ -1160,35 +1133,13 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { // if get: add to input objectFifo vector if (auto get = dyn_cast(endOfLink)) { buff = dyn_cast(get.getMemref().getDefiningOp()); - if (linkEnds.find(buff) == linkEnds.end()) { - std::vector input_ofs; - std::vector output_ofs; - linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; - } - std::get<1>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); - + addLinkEnd(ctx, buff, /* isInput */ true, numLinkEnds, objFifo); // if put: add to output objectFifo vector } else if (auto put = dyn_cast(endOfLink)) { buff = dyn_cast(put.getMemref().getDefiningOp()); - if (linkEnds.find(buff) == linkEnds.end()) { - std::vector input_ofs; - std::vector output_ofs; - linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; - } - std::get<2>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); - } - - // check if all ends have been found - auto numEnds = std::get<0>(linkEnds[buff]); - auto input_ofs = std::get<1>(linkEnds[buff]); - auto output_ofs = std::get<2>(linkEnds[buff]); - // if yes, create ObjectFifoLinkOp - if (input_ofs.size() + output_ofs.size() == numEnds) { - rewriter.create( - rewriter.getUnknownLoc(), - rewriter.getArrayAttr(ArrayRef(input_ofs)), - rewriter.getArrayAttr(ArrayRef(output_ofs))); + addLinkEnd(ctx, buff, /* isInput */ false, numLinkEnds, objFifo); } + createLink(rewriter, buff); } // replace put/get and any associated memref alloc/dealloc @@ -1270,14 +1221,14 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } } - AIE::ObjectFifoCreateOp createObjectFifo(OpBuilder &builder, + AIE::ObjectFifoCreateOp createObjectFifo(PatternRewriter &rewriter, AIE::AIEObjectFifoType datatype, Value prodTile, const std::vector &consTile, int depth, StringRef name) const { - AIE::ObjectFifoCreateOp fifo = builder.create( - builder.getUnknownLoc(), builder.getStringAttr(name), prodTile, - consTile, builder.getIntegerAttr(builder.getI32Type(), depth), + AIE::ObjectFifoCreateOp fifo = rewriter.create( + rewriter.getUnknownLoc(), rewriter.getStringAttr(name), prodTile, + consTile, rewriter.getIntegerAttr(rewriter.getI32Type(), depth), datatype); return fifo; } @@ -1339,6 +1290,66 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } } + template + bool detectLinkEnd(PatternRewriter &rewriter, MyOp op, + int* numLinkEnds) const { + // check if this put is linked to a get from another channel that... + bool found = false; + int numEnds = 0; + AIE::BufferOp buff = dyn_cast( + op.getMemref().getDefiningOp()); + // ... has already been found in another channel + if (linkEnds.find(buff) != linkEnds.end()) { + return true; + // ... has not been found yet + } else { + for (auto user : buff->getUsers()) { + if (isa(op)) { + if (isa(user)) + found = true; + if (isa(user) || isa(user)) + numEnds++; + } else if (isa(op)) { + if (isa(user)) + found = true; + if (isa(user) || isa(user)) + numEnds++; + } + } + } + *numLinkEnds = numEnds; + return found; + } + + void addLinkEnd(MLIRContext *ctx, AIE::BufferOp buff, + bool isInput, int numLinkEnds, + AIE::ObjectFifoCreateOp objFifo) const { + if (linkEnds.find(buff) == linkEnds.end()) { + std::vector input_ofs; + std::vector output_ofs; + linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; + } + if (isInput) + std::get<1>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); + else + std::get<2>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); + } + + void createLink(PatternRewriter &rewriter, + AIE::BufferOp buff) const { + auto numEnds = std::get<0>(linkEnds[buff]); + auto input_ofs = std::get<1>(linkEnds[buff]); + auto output_ofs = std::get<2>(linkEnds[buff]); + // check if all ends have been found + // if yes, create ObjectFifoLinkOp + if ((int)input_ofs.size() + (int)output_ofs.size() == numEnds) { + rewriter.create( + rewriter.getUnknownLoc(), + rewriter.getArrayAttr(ArrayRef(input_ofs)), + rewriter.getArrayAttr(ArrayRef(output_ofs))); + } + } + ShimTileAllocator &shimTileAlloc; std::map &bufferToMemtileMap; std::map, std::vector>> &linkEnds; // map L2 AIE.BufferOps to pairs of vectors of SymbolRefAttr () diff --git a/mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_distribute.mlir b/mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_distribute.mlir new file mode 100755 index 000000000..b78bd8572 --- /dev/null +++ b/mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_distribute.mlir @@ -0,0 +1,85 @@ +//===- air_channel_to_objectfifo_distribute.mlir ----------------*- MLIR -*-===// +// +// Copyright (C) 2024, Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT +// +//===----------------------------------------------------------------------===// + +// RUN: air-opt %s -air-place-herds='num-rows=2 num-cols=2 row-anchor=3 col-anchor=5' --air-to-aie='use-objectfifo=true device=xcve2802' --canonicalize | FileCheck %s + +// CHECK-LABEL: aie.device(xcve2802) { +// CHECK: %[[VAL_0:.*]] = aie.tile(2, 0) +// CHECK: %[[VAL_1:.*]] = aie.tile(1, 1) +// CHECK: %[[VAL_2:.*]] = aie.tile(5, 3) +// CHECK: %[[VAL_3:.*]] = aie.tile(5, 4) +// CHECK: aie.objectfifo @air_channel_3(%[[VAL_1]], {%[[VAL_3]]}, 1 : i32) : !aie.objectfifo> +// CHECK: aie.objectfifo @air_channel_2(%[[VAL_1]], {%[[VAL_2]]}, 1 : i32) : !aie.objectfifo> +// CHECK: aie.objectfifo @air_channel_0(%[[VAL_0]], {%[[VAL_1]]}, 1 : i32) : !aie.objectfifo> +// CHECK: aie.objectfifo.link [@air_channel_0] -> [@air_channel_2, @air_channel_3]() +// CHECK: %[[VAL_4:.*]] = aie.core(%[[VAL_3]]) { +// CHECK: %[[VAL_5:.*]] = aie.objectfifo.acquire @air_channel_3(Consume, 1) : !aie.objectfifosubview> +// CHECK: %[[VAL_6:.*]] = aie.objectfifo.subview.access %[[VAL_5]][0] : !aie.objectfifosubview> -> memref<16xi32> +// CHECK: aie.objectfifo.release @air_channel_3(Consume, 1) +// CHECK: aie.end +// CHECK: } {elf_file = "segment_0_core_5_4.elf"} +// CHECK: %[[VAL_5:.*]] = aie.core(%[[VAL_2]]) { +// CHECK: %[[VAL_6:.*]] = aie.objectfifo.acquire @air_channel_2(Consume, 1) : !aie.objectfifosubview> +// CHECK: %[[VAL_7:.*]] = aie.objectfifo.subview.access %[[VAL_6]][0] : !aie.objectfifosubview> -> memref<16xi32> +// CHECK: aie.objectfifo.release @air_channel_2(Consume, 1) +// CHECK: aie.end +// CHECK: } {elf_file = "segment_0_core_5_3.elf"} +// CHECK: } + +module { + air.channel @channel_0 [1, 1] + air.channel @channel_1 [1, 2] + func.func @L2toL1(%arg0: memref<32xi32>) { + %c1 = arith.constant 1 : index + %c2 = arith.constant 2 : index + + air.launch (%arg1, %arg2) in (%arg3=%c1, %arg4=%c2) args(%arg5=%arg0) : memref<32xi32> attributes {id = 1 : i32} { + %async_token, %results = air.execute -> (memref<32xi32>) { + %alloc = memref.alloc() {alignment = 32 : i64} : memref<32xi32> + air.execute_terminator %alloc : memref<32xi32> + } + %async_token_0 = air.execute [%async_token] { + memref.copy %arg5, %results : memref<32xi32> to memref<32xi32> + } + %0 = air.wait_all async + %1 = air.channel.put async [%async_token_0, %0] @channel_0[] (%results[] [] []) {id = 2 : i32} : (memref<32xi32>) + + %2 = air.segment async args(%arg6=%arg1, %arg7=%arg2) : index, index attributes {id = 3 : i32} { + %3 = air.wait_all async + %async_token_1, %results_1 = air.execute -> (memref<32xi32, 1>) { + %alloc1 = memref.alloc() : memref<32xi32, 1> + air.execute_terminator %alloc1 : memref<32xi32, 1> + } + %c0_2 = arith.constant 0 : index + %c1_2 = arith.constant 1 : index + %c2_2 = arith.constant 2 : index + %c16 = arith.constant 16 : index + %c32 = arith.constant 32 : index + %4 = air.channel.get async [%3] @channel_0[] (%results_1[] [] []) {id = 4 : i32} : (memref<32xi32, 1>) + %5 = air.wait_all async [%4] + %6 = air.channel.put async [%5] @channel_1[%c0_2, %c0_2] (%results_1[%c0_2] [%c16] []) {id = 5 : i32} : (memref<32xi32, 1>) + %7 = air.channel.put async [%5] @channel_1[%c0_2, %c1_2] (%results_1[%c16] [%c16] []) {id = 6 : i32} : (memref<32xi32, 1>) + + %8 = air.herd @herd_0 async [%4] tile (%arg8, %arg9) in (%arg10=%c1_2, %arg11=%c2_2) attributes {id = 7 : i32} { + %9 = air.wait_all async + %async_token_2, %results_2 = air.execute -> (memref<16xi32, 2>) { + %alloc2 = memref.alloc() : memref<16xi32, 2> + air.execute_terminator %alloc2 : memref<16xi32, 2> + } + %10 = air.channel.get async [%async_token_2, %9] @channel_1[%arg8, %arg9] (%results_2[] [] []) {id = 8 : i32} : (memref<16xi32, 2>) + %async_token_3 = air.execute [%10] { + memref.dealloc %results_2 : memref<16xi32, 2> + } + air.herd_terminator + } + air.segment_terminator + } + air.launch_terminator + } + return + } +} diff --git a/mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_join.mlir b/mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_join.mlir new file mode 100755 index 000000000..ba04ae13c --- /dev/null +++ b/mlir/test/Conversion/AIRToAIE/air_channel_to_objectfifo_join.mlir @@ -0,0 +1,82 @@ +//===- air_channel_to_objectfifo_join.mlir ----------------------*- MLIR -*-===// +// +// Copyright (C) 2024, Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT +// +//===----------------------------------------------------------------------===// + +// RUN: air-opt %s -air-place-herds='num-rows=2 num-cols=2 row-anchor=3 col-anchor=5' --air-to-aie='use-objectfifo=true device=xcve2802' --canonicalize | FileCheck %s + +// CHECK-LABEL: aie.device(xcve2802) { +// CHECK: %[[VAL_0:.*]] = aie.tile(2, 0) +// CHECK: %[[VAL_1:.*]] = aie.tile(1, 1) +// CHECK: %[[VAL_2:.*]] = aie.tile(5, 3) +// CHECK: %[[VAL_3:.*]] = aie.tile(5, 4) +// CHECK: aie.objectfifo @air_channel_0(%[[VAL_1]], {%[[VAL_0]]}, 1 : i32) : !aie.objectfifo> +// CHECK: aie.objectfifo @air_channel_3(%[[VAL_3]], {%[[VAL_1]]}, 1 : i32) : !aie.objectfifo> +// CHECK: aie.objectfifo @air_channel_2(%[[VAL_2]], {%[[VAL_1]]}, 1 : i32) : !aie.objectfifo> +// CHECK: aie.objectfifo.link [@air_channel_2, @air_channel_3] -> [@air_channel_0]() +// CHECK: %[[VAL_4:.*]] = aie.core(%[[VAL_3]]) { +// CHECK: %[[VAL_5:.*]] = aie.objectfifo.acquire @air_channel_3(Produce, 1) : !aie.objectfifosubview> +// CHECK: %[[VAL_6:.*]] = aie.objectfifo.subview.access %[[VAL_5]][0] : !aie.objectfifosubview> -> memref<16xi32> +// CHECK: aie.objectfifo.release @air_channel_3(Produce, 1) +// CHECK: aie.end +// CHECK: } {elf_file = "segment_0_core_5_4.elf"} +// CHECK: %[[VAL_5:.*]] = aie.core(%[[VAL_2]]) { +// CHECK: %[[VAL_6:.*]] = aie.objectfifo.acquire @air_channel_2(Produce, 1) : !aie.objectfifosubview> +// CHECK: %[[VAL_7:.*]] = aie.objectfifo.subview.access %[[VAL_6]][0] : !aie.objectfifosubview> -> memref<16xi32> +// CHECK: aie.objectfifo.release @air_channel_2(Produce, 1) +// CHECK: aie.end +// CHECK: } {elf_file = "segment_0_core_5_3.elf"} +// CHECK: } + +module { + air.channel @channel_0 [1, 1] + air.channel @channel_1 [1, 2] + func.func @L1toL2(%arg0: memref<32xi32>) { + %c1 = arith.constant 1 : index + %c2 = arith.constant 2 : index + + air.launch (%arg1, %arg2) in (%arg3=%c1, %arg4=%c2) args(%arg5=%arg0) : memref<32xi32> attributes {id = 1 : i32} { + %async_token, %results = air.execute -> (memref<32xi32>) { + %alloc = memref.alloc() {alignment = 32 : i64} : memref<32xi32> + air.execute_terminator %alloc : memref<32xi32> + } + %0 = air.wait_all async + %1 = air.channel.get async [%async_token, %0] @channel_0[] (%results[] [] []) {id = 2 : i32} : (memref<32xi32>) + + %2 = air.segment async args(%arg6=%arg1, %arg7=%arg2) : index, index attributes {id = 3 : i32} { + %c0_2 = arith.constant 0 : index + %c1_2 = arith.constant 1 : index + %c2_2 = arith.constant 2 : index + %c16 = arith.constant 16 : index + %c32 = arith.constant 32 : index + + %3 = air.herd @herd_0 async tile (%arg8, %arg9) in (%arg10=%c1_2, %arg11=%c2_2) attributes {id = 4 : i32} { + %9 = air.wait_all async + %async_token_2, %results_2 = air.execute -> (memref<16xi32, 2>) { + %alloc2 = memref.alloc() : memref<16xi32, 2> + air.execute_terminator %alloc2 : memref<16xi32, 2> + } + %10 = air.channel.put async [%async_token_2, %9] @channel_1[%arg8, %arg9] (%results_2[] [] []) {id = 5 : i32} : (memref<16xi32, 2>) + %async_token_3 = air.execute [%10] { + memref.dealloc %results_2 : memref<16xi32, 2> + } + air.herd_terminator + } + %4 = air.wait_all async + %async_token_1, %results_1 = air.execute -> (memref<32xi32, 1>) { + %alloc1 = memref.alloc() : memref<32xi32, 1> + air.execute_terminator %alloc1 : memref<32xi32, 1> + } + %5 = air.channel.get async [%4, %async_token_1] @channel_1[%c0_2, %c0_2] (%results_1[%c0_2] [%c16] []) {id = 6 : i32} : (memref<32xi32, 1>) + %6 = air.channel.get async [%4, %async_token_1] @channel_1[%c0_2, %c1_2] (%results_1[%c16] [%c16] []) {id = 7 : i32} : (memref<32xi32, 1>) + %7 = air.wait_all async + %8 = air.channel.put async [%7] @channel_0[] (%results_1[] [] []) {id = 8 : i32} : (memref<32xi32, 1>) + air.segment_terminator + } + air.launch_terminator + } + return + } +} From f4c7cd07dc93d439d85000cb424decfb9918f488 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Tue, 27 Feb 2024 07:33:02 -0700 Subject: [PATCH 03/12] Fix error where objectFifo datatype was not inferred properly for channels that use L2 --- mlir/lib/Conversion/AIRToAIEPass.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 46a01f0f8..4d9442f1b 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1048,7 +1048,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { if (channel.getBundleSize() > 1) return failure(); - AIE::AIEObjectFifoType datatype; + std::pair datatype = {(int)air::MemorySpace::L3, {}}; std::vector channelPuts = getChannelPutOpThroughSymbol(channel, device); std::vector channelGets = @@ -1118,13 +1118,14 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { consumers.push_back(consumerTile); } - if (!datatype) - return failure(); + if (datatype.first == (int)air::MemorySpace::L3) + return channel.emitOpError( + "could not infer datatype of Object FIFO elements"); // create objFifo rewriter.setInsertionPoint(*(device.getOps().begin())); AIE::ObjectFifoCreateOp objFifo = createObjectFifo( - rewriter, datatype, producerTile, consumers, + rewriter, datatype.second, producerTile, consumers, channel.getBufferResources(), "air_" + channel.getName().str()); // if a link end was found @@ -1195,12 +1196,16 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { private: // find AIE cores and their tiles based on memory hierarchy levels template - LogicalResult findChannelPutGetTile(MyOp op, Value *tile, - AIE::AIEObjectFifoType *datatype) const { + LogicalResult + findChannelPutGetTile(MyOp op, Value *tile, + std::pair *datatype) const { MemRefType memref = op.getMemref().getType().template cast(); int mem_space = memref.getMemorySpaceAsInt(); - *datatype = AIE::AIEObjectFifoType::get( - MemRefType::get(memref.getShape(), memref.getElementType())); + // remove mem_space from memref for objFifo datatype + if (datatype->first != (int)air::MemorySpace::L1) { + *datatype = {mem_space, + MemRefType::get(memref.getShape(), memref.getElementType())}; + } if (mem_space == (int)air::MemorySpace::L1) { AIE::CoreOp core = op->template getParentOfType(); if (!core) @@ -1222,14 +1227,13 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } AIE::ObjectFifoCreateOp createObjectFifo(PatternRewriter &rewriter, - AIE::AIEObjectFifoType datatype, - Value prodTile, + MemRefType datatype, Value prodTile, const std::vector &consTile, int depth, StringRef name) const { AIE::ObjectFifoCreateOp fifo = rewriter.create( rewriter.getUnknownLoc(), rewriter.getStringAttr(name), prodTile, consTile, rewriter.getIntegerAttr(rewriter.getI32Type(), depth), - datatype); + AIE::AIEObjectFifoType::get(datatype)); return fifo; } From 4a410a5ab74d6824b12276666a990279f122f971 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Tue, 27 Feb 2024 09:40:54 -0700 Subject: [PATCH 04/12] Clang format --- mlir/lib/Conversion/AIRToAIEPass.cpp | 64 ++++++++++++++++------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 4d9442f1b..d99ae72e4 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1032,10 +1032,11 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { LowerAIRChannelsPattern( MLIRContext *ctx, ShimTileAllocator &shimTileAlloc, std::map &bufferToMemtileMap, - std::map, std::vector>> &linkEnds) + std::map, std::vector>> + &linkEnds) : OpRewritePattern(ctx), shimTileAlloc(shimTileAlloc), - bufferToMemtileMap(bufferToMemtileMap), - linkEnds(linkEnds) {} + bufferToMemtileMap(bufferToMemtileMap), linkEnds(linkEnds) {} LogicalResult matchAndRewrite(air::ChannelOp channel, PatternRewriter &rewriter) const override { @@ -1054,10 +1055,11 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { std::vector channelGets = getChannelGetOpThroughSymbol(channel, device); - // variables to track LinkOp, i.e., a put and get using the same AIE.BufferOp - bool linkFound = false; // a link end is found - Operation *endOfLink = nullptr; // one end of a LinkOp (i.e., a put or get) - int numLinkEnds = 0; // # ends in this link (i.e., # users of AIE.BufferOp) + // variables to track LinkOp, i.e., a put and get using the same + // AIE.BufferOp + bool linkFound = false; // a link end is found + Operation *endOfLink = nullptr; // one end of a LinkOp (i.e., a put or get) + int numLinkEnds = 0; // # ends in this link (i.e., # users of AIE.BufferOp) // put/get come in pairs, if one is missing then it's L3 Value producerTile; @@ -1075,8 +1077,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { channelPuts[0].getMemref().getType().cast(); int mem_space = memref.getMemorySpaceAsInt(); if (mem_space == (int)air::MemorySpace::L2) { - linkFound = detectLinkEnd(rewriter, channelPuts[0], - &numLinkEnds); + linkFound = + detectLinkEnd(rewriter, channelPuts[0], &numLinkEnds); if (linkFound) endOfLink = channelPuts[0].getOperation(); } @@ -1135,7 +1137,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { if (auto get = dyn_cast(endOfLink)) { buff = dyn_cast(get.getMemref().getDefiningOp()); addLinkEnd(ctx, buff, /* isInput */ true, numLinkEnds, objFifo); - // if put: add to output objectFifo vector + // if put: add to output objectFifo vector } else if (auto put = dyn_cast(endOfLink)) { buff = dyn_cast(put.getMemref().getDefiningOp()); addLinkEnd(ctx, buff, /* isInput */ false, numLinkEnds, objFifo); @@ -1296,16 +1298,16 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { template bool detectLinkEnd(PatternRewriter &rewriter, MyOp op, - int* numLinkEnds) const { + int *numLinkEnds) const { // check if this put is linked to a get from another channel that... bool found = false; int numEnds = 0; - AIE::BufferOp buff = dyn_cast( - op.getMemref().getDefiningOp()); + AIE::BufferOp buff = + dyn_cast(op.getMemref().getDefiningOp()); // ... has already been found in another channel if (linkEnds.find(buff) != linkEnds.end()) { return true; - // ... has not been found yet + // ... has not been found yet } else { for (auto user : buff->getUsers()) { if (isa(op)) { @@ -1325,22 +1327,22 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { return found; } - void addLinkEnd(MLIRContext *ctx, AIE::BufferOp buff, - bool isInput, int numLinkEnds, - AIE::ObjectFifoCreateOp objFifo) const { + void addLinkEnd(MLIRContext *ctx, AIE::BufferOp buff, bool isInput, + int numLinkEnds, AIE::ObjectFifoCreateOp objFifo) const { if (linkEnds.find(buff) == linkEnds.end()) { std::vector input_ofs; std::vector output_ofs; linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; } if (isInput) - std::get<1>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); + std::get<1>(linkEnds[buff]) + .push_back(SymbolRefAttr::get(ctx, objFifo.name())); else - std::get<2>(linkEnds[buff]).push_back(SymbolRefAttr::get(ctx, objFifo.name())); + std::get<2>(linkEnds[buff]) + .push_back(SymbolRefAttr::get(ctx, objFifo.name())); } - void createLink(PatternRewriter &rewriter, - AIE::BufferOp buff) const { + void createLink(PatternRewriter &rewriter, AIE::BufferOp buff) const { auto numEnds = std::get<0>(linkEnds[buff]); auto input_ofs = std::get<1>(linkEnds[buff]); auto output_ofs = std::get<2>(linkEnds[buff]); @@ -1348,15 +1350,17 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { // if yes, create ObjectFifoLinkOp if ((int)input_ofs.size() + (int)output_ofs.size() == numEnds) { rewriter.create( - rewriter.getUnknownLoc(), - rewriter.getArrayAttr(ArrayRef(input_ofs)), + rewriter.getUnknownLoc(), rewriter.getArrayAttr(ArrayRef(input_ofs)), rewriter.getArrayAttr(ArrayRef(output_ofs))); } } ShimTileAllocator &shimTileAlloc; std::map &bufferToMemtileMap; - std::map, std::vector>> &linkEnds; // map L2 AIE.BufferOps to pairs of vectors of SymbolRefAttr () + std::map, std::vector>> + &linkEnds; // map L2 AIE.BufferOps to pairs of vectors of SymbolRefAttr + // () }; // This function replaces ChannelPutOp/ChannelGetOp with AIE_CreateObjectFifoOps @@ -1368,7 +1372,9 @@ void lowerAIRChannels( std::map &bufferToMemtileMap) { auto ctx = d->getContext(); RewritePatternSet patterns(ctx); - std::map, std::vector>> linkEnds; + std::map, std::vector>> + linkEnds; patterns.insert(ctx, s, bufferToMemtileMap, linkEnds); (void)applyPatternsAndFoldGreedily(d, std::move(patterns)); @@ -2807,10 +2813,12 @@ class AIRToAIEPass : public air::impl::AIRToAIEBase { builder.getUnknownLoc(), AIE::AIEDeviceAttr::get(builder.getContext(), *device)); ShimTileAllocator shimTileAlloc(deviceOp.getTargetModel()); - std::map, std::vector>> linkEnds; + std::map, std::vector>> + linkEnds; if (clTestPatterns.find("lower-air-channels") != std::string::npos) { - patterns.insert( - ctx, shimTileAlloc, bufferToMemtileMap, linkEnds); + patterns.insert(ctx, shimTileAlloc, + bufferToMemtileMap, linkEnds); } if (clTestPatterns.find("lower-air-ping-pong") != std::string::npos) { patterns.insert(ctx); From b5ee9e1a1d09f3f8f07ca9442d41b57ea0df40d3 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Wed, 28 Feb 2024 10:49:38 -0700 Subject: [PATCH 05/12] Add sorting of objectFifos based on 1DOffset --- mlir/lib/Conversion/AIRToAIEPass.cpp | 49 ++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index d99ae72e4..217447e64 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1033,7 +1033,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { MLIRContext *ctx, ShimTileAllocator &shimTileAlloc, std::map &bufferToMemtileMap, std::map, std::vector>> + std::tuple>, std::vector>>> &linkEnds) : OpRewritePattern(ctx), shimTileAlloc(shimTileAlloc), bufferToMemtileMap(bufferToMemtileMap), linkEnds(linkEnds) {} @@ -1136,11 +1136,19 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { // if get: add to input objectFifo vector if (auto get = dyn_cast(endOfLink)) { buff = dyn_cast(get.getMemref().getDefiningOp()); - addLinkEnd(ctx, buff, /* isInput */ true, numLinkEnds, objFifo); + SmallVector offsets = get.getDstOffsets(); + SmallVector strides = get.getDstStrides(); + int64_t offset = + get1DOffset(offsets, strides, getElementSizeInBytes(get.getMemref().getType().cast())); + addLinkEnd(ctx, buff, /* isInput */ true, numLinkEnds, objFifo, offset); // if put: add to output objectFifo vector } else if (auto put = dyn_cast(endOfLink)) { buff = dyn_cast(put.getMemref().getDefiningOp()); - addLinkEnd(ctx, buff, /* isInput */ false, numLinkEnds, objFifo); + SmallVector offsets = put.getSrcOffsets(); + SmallVector strides = put.getSrcStrides(); + int64_t offset = + get1DOffset(offsets, strides, getElementSizeInBytes(put.getMemref().getType().cast())); + addLinkEnd(ctx, buff, /* isInput */ false, numLinkEnds, objFifo, offset); } createLink(rewriter, buff); } @@ -1328,24 +1336,39 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } void addLinkEnd(MLIRContext *ctx, AIE::BufferOp buff, bool isInput, - int numLinkEnds, AIE::ObjectFifoCreateOp objFifo) const { + int numLinkEnds, AIE::ObjectFifoCreateOp objFifo, + int64_t offset) const { if (linkEnds.find(buff) == linkEnds.end()) { - std::vector input_ofs; - std::vector output_ofs; + std::vector> input_ofs; + std::vector> output_ofs; linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; } if (isInput) std::get<1>(linkEnds[buff]) - .push_back(SymbolRefAttr::get(ctx, objFifo.name())); + .push_back({SymbolRefAttr::get(ctx, objFifo.name()), offset}); else std::get<2>(linkEnds[buff]) - .push_back(SymbolRefAttr::get(ctx, objFifo.name())); + .push_back({SymbolRefAttr::get(ctx, objFifo.name()), offset}); + } + + static bool sortLinkObjectFifos(std::pair op0, + std::pair op1) { + return op0.second < op1.second; } void createLink(PatternRewriter &rewriter, AIE::BufferOp buff) const { auto numEnds = std::get<0>(linkEnds[buff]); - auto input_ofs = std::get<1>(linkEnds[buff]); - auto output_ofs = std::get<2>(linkEnds[buff]); + auto input_pairs = std::get<1>(linkEnds[buff]); + auto output_pairs = std::get<2>(linkEnds[buff]); + std::vector input_ofs; + std::vector output_ofs; + std::sort(input_pairs.begin(), input_pairs.end(), sortLinkObjectFifos); + std::sort(output_pairs.begin(), output_pairs.end(), sortLinkObjectFifos); + // retrieve only objectFifo symbol ref attributes + for (auto p : input_pairs) + input_ofs.push_back(p.first); + for (auto p : output_pairs) + output_ofs.push_back(p.first); // check if all ends have been found // if yes, create ObjectFifoLinkOp if ((int)input_ofs.size() + (int)output_ofs.size() == numEnds) { @@ -1358,7 +1381,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { ShimTileAllocator &shimTileAlloc; std::map &bufferToMemtileMap; std::map, std::vector>> + std::tuple>, std::vector>>> &linkEnds; // map L2 AIE.BufferOps to pairs of vectors of SymbolRefAttr // () }; @@ -1373,7 +1396,7 @@ void lowerAIRChannels( auto ctx = d->getContext(); RewritePatternSet patterns(ctx); std::map, std::vector>> + std::tuple>, std::vector>>> linkEnds; patterns.insert(ctx, s, bufferToMemtileMap, linkEnds); @@ -2814,7 +2837,7 @@ class AIRToAIEPass : public air::impl::AIRToAIEBase { AIE::AIEDeviceAttr::get(builder.getContext(), *device)); ShimTileAllocator shimTileAlloc(deviceOp.getTargetModel()); std::map, std::vector>> + std::tuple>, std::vector>>> linkEnds; if (clTestPatterns.find("lower-air-channels") != std::string::npos) { patterns.insert(ctx, shimTileAlloc, From f90b738f42e42b7a902ba676b51c05c1e2ba5171 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Wed, 28 Feb 2024 12:37:59 -0700 Subject: [PATCH 06/12] Create struct for linkEnds --- mlir/lib/Conversion/AIRToAIEPass.cpp | 39 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 217447e64..a2cb2e3f5 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -56,6 +56,12 @@ struct AIRToAIEConversionOptions { AIE::AIEDevice device; }; +struct link_ends_interface { + int numLinkEnds; + std::vector> input_ofs_with_offsets; + std::vector> output_ofs_with_offsets; +}; + // get memcpy operation volumn (elements) as int int getMemcpySizesAsInt(Value memref, SmallVector sizes) { MemRefType memTy = memref.getType().cast(); @@ -1032,9 +1038,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { LowerAIRChannelsPattern( MLIRContext *ctx, ShimTileAllocator &shimTileAlloc, std::map &bufferToMemtileMap, - std::map>, std::vector>>> - &linkEnds) + std::map &linkEnds) : OpRewritePattern(ctx), shimTileAlloc(shimTileAlloc), bufferToMemtileMap(bufferToMemtileMap), linkEnds(linkEnds) {} @@ -1344,11 +1348,11 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { linkEnds[buff] = {numLinkEnds, input_ofs, output_ofs}; } if (isInput) - std::get<1>(linkEnds[buff]) - .push_back({SymbolRefAttr::get(ctx, objFifo.name()), offset}); + linkEnds[buff].input_ofs_with_offsets.push_back( + {SymbolRefAttr::get(ctx, objFifo.name()), offset}); else - std::get<2>(linkEnds[buff]) - .push_back({SymbolRefAttr::get(ctx, objFifo.name()), offset}); + linkEnds[buff].output_ofs_with_offsets.push_back( + {SymbolRefAttr::get(ctx, objFifo.name()), offset}); } static bool sortLinkObjectFifos(std::pair op0, @@ -1357,9 +1361,9 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } void createLink(PatternRewriter &rewriter, AIE::BufferOp buff) const { - auto numEnds = std::get<0>(linkEnds[buff]); - auto input_pairs = std::get<1>(linkEnds[buff]); - auto output_pairs = std::get<2>(linkEnds[buff]); + auto numEnds = linkEnds[buff].numLinkEnds; + auto input_pairs = linkEnds[buff].input_ofs_with_offsets; + auto output_pairs = linkEnds[buff].output_ofs_with_offsets; std::vector input_ofs; std::vector output_ofs; std::sort(input_pairs.begin(), input_pairs.end(), sortLinkObjectFifos); @@ -1380,10 +1384,9 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { ShimTileAllocator &shimTileAlloc; std::map &bufferToMemtileMap; - std::map>, std::vector>>> - &linkEnds; // map L2 AIE.BufferOps to pairs of vectors of SymbolRefAttr - // () + std::map &linkEnds; + // map L2 AIE.BufferOps to pairs of vectors of SymbolRefAttr + // () }; // This function replaces ChannelPutOp/ChannelGetOp with AIE_CreateObjectFifoOps @@ -1395,9 +1398,7 @@ void lowerAIRChannels( std::map &bufferToMemtileMap) { auto ctx = d->getContext(); RewritePatternSet patterns(ctx); - std::map>, std::vector>>> - linkEnds; + std::map linkEnds; patterns.insert(ctx, s, bufferToMemtileMap, linkEnds); (void)applyPatternsAndFoldGreedily(d, std::move(patterns)); @@ -2836,9 +2837,7 @@ class AIRToAIEPass : public air::impl::AIRToAIEBase { builder.getUnknownLoc(), AIE::AIEDeviceAttr::get(builder.getContext(), *device)); ShimTileAllocator shimTileAlloc(deviceOp.getTargetModel()); - std::map>, std::vector>>> - linkEnds; + std::map linkEnds; if (clTestPatterns.find("lower-air-channels") != std::string::npos) { patterns.insert(ctx, shimTileAlloc, bufferToMemtileMap, linkEnds); From 4ace32c2d5934da4975ebee9a3bb38a71e28ba52 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Thu, 7 Mar 2024 06:05:38 -0700 Subject: [PATCH 07/12] Use 'unroll' label of for loops to determine depth of objectFifos --- mlir/lib/Conversion/AIRToAIEPass.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 50bc7864c..2cd36c2e1 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1083,6 +1083,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { if (res.failed()) return res; + setChannelBufferResources(rewriter, channel, channelPuts[0].getOperation()); + // check if this put is linked to a get from another channel MemRefType memref = channelPuts[0].getMemref().getType().cast(); @@ -1114,6 +1116,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { return res; consumers.push_back(consumerTile); + setChannelBufferResources(rewriter, channel, get.getOperation()); + // check if this get is linked to a put from another channel MemRefType memref = get.getMemref().getType().cast(); int mem_space = memref.getMemorySpaceAsInt(); @@ -1247,6 +1251,20 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } } + void setChannelBufferResources(PatternRewriter &rewriter, + air::ChannelOp channel, + Operation* op) const { + if (channel->hasAttr("buffer_resources")) + return; + auto for_op = op->getParentOfType(); + if (!for_op) + return; + if (for_op->hasAttr("unroll")) { + auto unroll_factor = for_op->getAttrOfType("unroll"); + channel->setAttr("buffer_resources", unroll_factor); + } + } + AIE::ObjectFifoCreateOp createObjectFifo(PatternRewriter &rewriter, MemRefType datatype, Value prodTile, const std::vector &consTile, From 667ce8c101ba058d9a4039bbf2fde9e00d5ddc60 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Tue, 14 May 2024 07:32:57 -0600 Subject: [PATCH 08/12] Add a way to retrieve data layout transformations from channel put/get --- mlir/lib/Conversion/AIRToAIEPass.cpp | 82 ++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 2cd36c2e1..5b939fc2f 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -99,8 +99,7 @@ struct ShimTileAllocator { for (int i = 0, e = aie_target.columns(); i < e; i++) { if (aie_target.isShimNOCTile(i, 0)) { shim_columns.push_back(i); - shim_dma_channels = aie_target.getNumDestSwitchboxConnections( - i, 0, AIE::WireBundle::FIFO); + shim_dma_channels = 2; } } } @@ -1052,6 +1051,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { LogicalResult matchAndRewrite(air::ChannelOp channel, PatternRewriter &rewriter) const override { auto device = channel->getParentOfType(); + const auto &target_model = device.getTargetModel(); + bool isAIE2 = (target_model.getTargetArch() == AIE::AIEArch::AIE2); auto ctx = device->getContext(); if (!device) return failure(); @@ -1072,6 +1073,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { Operation *endOfLink = nullptr; // one end of a LinkOp (i.e., a put or get) int numLinkEnds = 0; // # ends in this link (i.e., # users of AIE.BufferOp) + AIE::BDDimLayoutArrayAttr dimensionsToStream = AIE::BDDimLayoutArrayAttr::get(channel->getContext(), {});; + // put/get come in pairs, if one is missing then it's L3 Value producerTile; if (channelPuts.size() > 0) { @@ -1086,15 +1089,38 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { setChannelBufferResources(rewriter, channel, channelPuts[0].getOperation()); // check if this put is linked to a get from another channel - MemRefType memref = + MemRefType memrefType = channelPuts[0].getMemref().getType().cast(); - int mem_space = memref.getMemorySpaceAsInt(); + int mem_space = memrefType.getMemorySpaceAsInt(); if (mem_space == (int)air::MemorySpace::L2) { linkFound = detectLinkEnd(rewriter, channelPuts[0], &numLinkEnds); if (linkFound) endOfLink = channelPuts[0].getOperation(); } + + // get data layout transformation on channel put + auto ndcpy = cast(channelPuts[0].getOperation()); + SmallVector sizes = isTileInbound(ndcpy, (int)air::MemorySpace::L1) + ? ndcpy.getDstSizes() + : ndcpy.getSrcSizes(); + SmallVector strides = isTileInbound(ndcpy, (int)air::MemorySpace::L1) + ? ndcpy.getDstStrides() + : ndcpy.getSrcStrides(); + if (!strides.empty() && !sizes.empty()) + if (auto const_highest_stride = getConstantIntValue(strides[0])) + if (*const_highest_stride == 0) { + strides.erase(strides.begin()); + sizes.erase(sizes.begin()); + } + std::vector dims = + getWrapsAndStrides(sizes, strides, ndcpy->getContext()); + auto wraps_and_strides = + AIE::BDDimLayoutArrayAttr::get(ndcpy->getContext(), ArrayRef(dims)); + bool useDefaultDataAccessPattern = + isAIE2 ? isDefaultDataAccessPattern(sizes, strides, channelPuts[0].getMemref()) : true; + if (!wraps_and_strides.getValue().empty() && !useDefaultDataAccessPattern) + dimensionsToStream = wraps_and_strides; } else { // put from L3 producerTile = shimTileAlloc.getShimTile( @@ -1102,6 +1128,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { channel.getName().str()); } + std::vector dimsFromStreamPerConsumer; + // put/get come in pairs, if one is missing then it's L3 std::vector consumers; Value consumerTile; @@ -1119,13 +1147,36 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { setChannelBufferResources(rewriter, channel, get.getOperation()); // check if this get is linked to a put from another channel - MemRefType memref = get.getMemref().getType().cast(); - int mem_space = memref.getMemorySpaceAsInt(); + MemRefType memrefType = get.getMemref().getType().cast(); + int mem_space = memrefType.getMemorySpaceAsInt(); if (mem_space == (int)air::MemorySpace::L2) { linkFound = detectLinkEnd(rewriter, get, &numLinkEnds); if (linkFound) endOfLink = get.getOperation(); } + + // get data layout transformation on channel get + auto ndcpy = cast(get.getOperation()); + SmallVector sizes = isTileInbound(ndcpy, (int)air::MemorySpace::L1) + ? ndcpy.getDstSizes() + : ndcpy.getSrcSizes(); + SmallVector strides = isTileInbound(ndcpy, (int)air::MemorySpace::L1) + ? ndcpy.getDstStrides() + : ndcpy.getSrcStrides(); + if (!strides.empty() && !sizes.empty()) + if (auto const_highest_stride = getConstantIntValue(strides[0])) + if (*const_highest_stride == 0) { + strides.erase(strides.begin()); + sizes.erase(sizes.begin()); + } + std::vector dims = + getWrapsAndStrides(sizes, strides, ndcpy->getContext()); + auto wraps_and_strides = + AIE::BDDimLayoutArrayAttr::get(ndcpy->getContext(), ArrayRef(dims)); + bool useDefaultDataAccessPattern = + isAIE2 ? isDefaultDataAccessPattern(sizes, strides, get.getMemref()) : true; + if (!wraps_and_strides.getValue().empty() && !useDefaultDataAccessPattern) + dimsFromStreamPerConsumer.push_back(wraps_and_strides); } for (int i = 0; i < expectedGets - (int)channelGets.size(); i++) { // get from L3 @@ -1141,9 +1192,17 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { // create objFifo rewriter.setInsertionPoint(*(device.getOps().begin())); + AIE::BDDimLayoutArrayAttr emptyDims = + AIE::BDDimLayoutArrayAttr::get(channel->getContext(), {}); + auto dimensionsFromStreamPerConsumer = + AIE::BDDimLayoutArrayArrayAttr::get(channel->getContext(), ArrayRef(emptyDims)); + if (dimsFromStreamPerConsumer.size() > 0) + dimensionsFromStreamPerConsumer = + AIE::BDDimLayoutArrayArrayAttr::get(channel->getContext(), ArrayRef(dimsFromStreamPerConsumer)); AIE::ObjectFifoCreateOp objFifo = createObjectFifo( rewriter, datatype.second, producerTile, consumers, - channel.getBufferResources(), "air_" + channel.getName().str()); + channel.getBufferResources(), "air_" + channel.getName().str(), + dimensionsToStream, dimensionsFromStreamPerConsumer); // if a link end was found if (linkFound) { @@ -1268,12 +1327,13 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { AIE::ObjectFifoCreateOp createObjectFifo(PatternRewriter &rewriter, MemRefType datatype, Value prodTile, const std::vector &consTile, - int depth, StringRef name) const { - AIE::ObjectFifoCreateOp fifo = rewriter.create( + int depth, StringRef name, + AIE::BDDimLayoutArrayAttr dimensionsToStream, + AIE::BDDimLayoutArrayArrayAttr dimensionsFromStreamPerConsumer) const { + return rewriter.create( rewriter.getUnknownLoc(), rewriter.getStringAttr(name), prodTile, consTile, rewriter.getIntegerAttr(rewriter.getI32Type(), depth), - AIE::AIEObjectFifoType::get(datatype)); - return fifo; + AIE::AIEObjectFifoType::get(datatype), dimensionsToStream, dimensionsFromStreamPerConsumer); } template From fa6d24fa1872a55e0ffaad73f48aa1463e9a6159 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Tue, 21 May 2024 10:56:29 -0600 Subject: [PATCH 09/12] Resolve merge conflicts --- mlir/lib/Conversion/AIRToAIEPass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index a17328c03..17c9c6675 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1333,7 +1333,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { SmallVector offsets = get.getDstOffsets(); SmallVector strides = get.getDstStrides(); int64_t offset = - get1DOffset(offsets, strides, getElementSizeInBytes(get.getMemref().getType().cast())); + get1DOffset(offsets, strides); addLinkEnd(ctx, buff, /* isInput */ true, numLinkEnds, objFifo, offset); // if put: add to output objectFifo vector } else if (auto put = dyn_cast(endOfLink)) { @@ -1341,7 +1341,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { SmallVector offsets = put.getSrcOffsets(); SmallVector strides = put.getSrcStrides(); int64_t offset = - get1DOffset(offsets, strides, getElementSizeInBytes(put.getMemref().getType().cast())); + get1DOffset(offsets, strides); addLinkEnd(ctx, buff, /* isInput */ false, numLinkEnds, objFifo, offset); } createLink(rewriter, buff); @@ -1401,7 +1401,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { // find AIE cores and their tiles based on memory hierarchy levels template LogicalResult findChannelPutGetTile(MyOp op, Value *tile, - AIE::AIEObjectFifoType *datatype) const { + std::pair *datatype) const { MemRefType memref = llvm::cast(op.getMemref().getType()); int mem_space = memref.getMemorySpaceAsInt(); // remove mem_space from memref for objFifo datatype From 19cc6f7337e02c07b97d11f4d6d9cbff0a7e2b9c Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Mon, 3 Jun 2024 14:43:02 -0600 Subject: [PATCH 10/12] Clang format --- mlir/lib/Conversion/AIRToAIEPass.cpp | 77 +++++++++++++++------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 17c9c6675..33dbbc10b 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1193,7 +1193,9 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { Operation *endOfLink = nullptr; // one end of a LinkOp (i.e., a put or get) int numLinkEnds = 0; // # ends in this link (i.e., # users of AIE.BufferOp) - AIE::BDDimLayoutArrayAttr dimensionsToStream = AIE::BDDimLayoutArrayAttr::get(channel->getContext(), {});; + AIE::BDDimLayoutArrayAttr dimensionsToStream = + AIE::BDDimLayoutArrayAttr::get(channel->getContext(), {}); + ; // put/get come in pairs, if one is missing then it's L3 Value producerTile; @@ -1206,7 +1208,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { if (res.failed()) return res; - setChannelBufferResources(rewriter, channel, channelPuts[0].getOperation()); + setChannelBufferResources(rewriter, channel, + channelPuts[0].getOperation()); // check if this put is linked to a get from another channel MemRefType memrefType = @@ -1222,11 +1225,12 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { // get data layout transformation on channel put auto ndcpy = cast(channelPuts[0].getOperation()); SmallVector sizes = isTileInbound(ndcpy, (int)air::MemorySpace::L1) - ? ndcpy.getDstSizes() - : ndcpy.getSrcSizes(); - SmallVector strides = isTileInbound(ndcpy, (int)air::MemorySpace::L1) - ? ndcpy.getDstStrides() - : ndcpy.getSrcStrides(); + ? ndcpy.getDstSizes() + : ndcpy.getSrcSizes(); + SmallVector strides = + isTileInbound(ndcpy, (int)air::MemorySpace::L1) + ? ndcpy.getDstStrides() + : ndcpy.getSrcStrides(); if (!strides.empty() && !sizes.empty()) if (auto const_highest_stride = getConstantIntValue(strides[0])) if (*const_highest_stride == 0) { @@ -1238,7 +1242,9 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { auto wraps_and_strides = AIE::BDDimLayoutArrayAttr::get(ndcpy->getContext(), ArrayRef(dims)); bool useDefaultDataAccessPattern = - isAIE2 ? isDefaultDataAccessPattern(sizes, strides, channelPuts[0].getMemref()) : true; + isAIE2 ? isDefaultDataAccessPattern(sizes, strides, + channelPuts[0].getMemref()) + : true; if (!wraps_and_strides.getValue().empty() && !useDefaultDataAccessPattern) dimensionsToStream = wraps_and_strides; } else { @@ -1278,11 +1284,12 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { // get data layout transformation on channel get auto ndcpy = cast(get.getOperation()); SmallVector sizes = isTileInbound(ndcpy, (int)air::MemorySpace::L1) - ? ndcpy.getDstSizes() - : ndcpy.getSrcSizes(); - SmallVector strides = isTileInbound(ndcpy, (int)air::MemorySpace::L1) - ? ndcpy.getDstStrides() - : ndcpy.getSrcStrides(); + ? ndcpy.getDstSizes() + : ndcpy.getSrcSizes(); + SmallVector strides = + isTileInbound(ndcpy, (int)air::MemorySpace::L1) + ? ndcpy.getDstStrides() + : ndcpy.getSrcStrides(); if (!strides.empty() && !sizes.empty()) if (auto const_highest_stride = getConstantIntValue(strides[0])) if (*const_highest_stride == 0) { @@ -1294,7 +1301,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { auto wraps_and_strides = AIE::BDDimLayoutArrayAttr::get(ndcpy->getContext(), ArrayRef(dims)); bool useDefaultDataAccessPattern = - isAIE2 ? isDefaultDataAccessPattern(sizes, strides, get.getMemref()) : true; + isAIE2 ? isDefaultDataAccessPattern(sizes, strides, get.getMemref()) + : true; if (!wraps_and_strides.getValue().empty() && !useDefaultDataAccessPattern) dimsFromStreamPerConsumer.push_back(wraps_and_strides); } @@ -1314,11 +1322,11 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { rewriter.setInsertionPoint(*(device.getOps().begin())); AIE::BDDimLayoutArrayAttr emptyDims = AIE::BDDimLayoutArrayAttr::get(channel->getContext(), {}); - auto dimensionsFromStreamPerConsumer = - AIE::BDDimLayoutArrayArrayAttr::get(channel->getContext(), ArrayRef(emptyDims)); + auto dimensionsFromStreamPerConsumer = AIE::BDDimLayoutArrayArrayAttr::get( + channel->getContext(), ArrayRef(emptyDims)); if (dimsFromStreamPerConsumer.size() > 0) - dimensionsFromStreamPerConsumer = - AIE::BDDimLayoutArrayArrayAttr::get(channel->getContext(), ArrayRef(dimsFromStreamPerConsumer)); + dimensionsFromStreamPerConsumer = AIE::BDDimLayoutArrayArrayAttr::get( + channel->getContext(), ArrayRef(dimsFromStreamPerConsumer)); AIE::ObjectFifoCreateOp objFifo = createObjectFifo( rewriter, datatype.second, producerTile, consumers, channel.getBufferResources(), "air_" + channel.getName().str(), @@ -1332,17 +1340,16 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { buff = dyn_cast(get.getMemref().getDefiningOp()); SmallVector offsets = get.getDstOffsets(); SmallVector strides = get.getDstStrides(); - int64_t offset = - get1DOffset(offsets, strides); + int64_t offset = get1DOffset(offsets, strides); addLinkEnd(ctx, buff, /* isInput */ true, numLinkEnds, objFifo, offset); // if put: add to output objectFifo vector } else if (auto put = dyn_cast(endOfLink)) { buff = dyn_cast(put.getMemref().getDefiningOp()); SmallVector offsets = put.getSrcOffsets(); SmallVector strides = put.getSrcStrides(); - int64_t offset = - get1DOffset(offsets, strides); - addLinkEnd(ctx, buff, /* isInput */ false, numLinkEnds, objFifo, offset); + int64_t offset = get1DOffset(offsets, strides); + addLinkEnd(ctx, buff, /* isInput */ false, numLinkEnds, objFifo, + offset); } createLink(rewriter, buff); } @@ -1400,8 +1407,9 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { private: // find AIE cores and their tiles based on memory hierarchy levels template - LogicalResult findChannelPutGetTile(MyOp op, Value *tile, - std::pair *datatype) const { + LogicalResult + findChannelPutGetTile(MyOp op, Value *tile, + std::pair *datatype) const { MemRefType memref = llvm::cast(op.getMemref().getType()); int mem_space = memref.getMemorySpaceAsInt(); // remove mem_space from memref for objFifo datatype @@ -1432,8 +1440,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } void setChannelBufferResources(PatternRewriter &rewriter, - air::ChannelOp channel, - Operation* op) const { + air::ChannelOp channel, Operation *op) const { if (channel->hasAttr("buffer_resources")) return; auto for_op = op->getParentOfType(); @@ -1445,16 +1452,16 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { } } - AIE::ObjectFifoCreateOp createObjectFifo(PatternRewriter &rewriter, - MemRefType datatype, Value prodTile, - const std::vector &consTile, - int depth, StringRef name, - AIE::BDDimLayoutArrayAttr dimensionsToStream, - AIE::BDDimLayoutArrayArrayAttr dimensionsFromStreamPerConsumer) const { + AIE::ObjectFifoCreateOp createObjectFifo( + PatternRewriter &rewriter, MemRefType datatype, Value prodTile, + const std::vector &consTile, int depth, StringRef name, + AIE::BDDimLayoutArrayAttr dimensionsToStream, + AIE::BDDimLayoutArrayArrayAttr dimensionsFromStreamPerConsumer) const { return rewriter.create( rewriter.getUnknownLoc(), rewriter.getStringAttr(name), prodTile, consTile, rewriter.getIntegerAttr(rewriter.getI32Type(), depth), - AIE::AIEObjectFifoType::get(datatype), dimensionsToStream, dimensionsFromStreamPerConsumer); + AIE::AIEObjectFifoType::get(datatype), dimensionsToStream, + dimensionsFromStreamPerConsumer); } template @@ -1561,7 +1568,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { {SymbolRefAttr::get(ctx, objFifo.name()), offset}); } - static bool sortLinkObjectFifos(std::pair op0, + static bool sortLinkObjectFifos(std::pair op0, std::pair op1) { return op0.second < op1.second; } From b9d3170e83e9c1c41b0e4885c244b1d2a6e3cc27 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Mon, 3 Jun 2024 15:36:11 -0600 Subject: [PATCH 11/12] Fix error where broadcast tiles where being duplicated --- mlir/lib/Conversion/AIRToAIEPass.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 33dbbc10b..6430a6290 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1195,7 +1195,6 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { AIE::BDDimLayoutArrayAttr dimensionsToStream = AIE::BDDimLayoutArrayAttr::get(channel->getContext(), {}); - ; // put/get come in pairs, if one is missing then it's L3 Value producerTile; @@ -1257,7 +1256,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { std::vector dimsFromStreamPerConsumer; // put/get come in pairs, if one is missing then it's L3 - std::vector consumers; + std::set consumers; Value consumerTile; if (channelGets.size() > 1 && !channel.isBroadcast()) return channel.emitOpError("has multiple gets but no broadcast shape"); @@ -1268,7 +1267,7 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { findChannelPutGetTile(get, &consumerTile, &datatype); if (res.failed()) return res; - consumers.push_back(consumerTile); + consumers.insert(consumerTile.getDefiningOp()); setChannelBufferResources(rewriter, channel, get.getOperation()); @@ -1311,8 +1310,11 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { consumerTile = shimTileAlloc.getShimTile( device, (int)air::MemorySpace::L1, (int)air::MemorySpace::L3, channel.getName().str()); - consumers.push_back(consumerTile); + consumers.insert(consumerTile.getDefiningOp()); } + if ((int)consumers.size() != expectedGets) + return channel.emitOpError( + "number of channel gets does not match broadcast shape"); if (datatype.first == (int)air::MemorySpace::L3) return channel.emitOpError( @@ -1327,8 +1329,11 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { if (dimsFromStreamPerConsumer.size() > 0) dimensionsFromStreamPerConsumer = AIE::BDDimLayoutArrayArrayAttr::get( channel->getContext(), ArrayRef(dimsFromStreamPerConsumer)); + std::vector consumerTiles; + for (auto tile : consumers) + consumerTiles.push_back(tile); AIE::ObjectFifoCreateOp objFifo = createObjectFifo( - rewriter, datatype.second, producerTile, consumers, + rewriter, datatype.second, producerTile, consumerTiles, channel.getBufferResources(), "air_" + channel.getName().str(), dimensionsToStream, dimensionsFromStreamPerConsumer); From fe1d8444ef86d41096bfc6462654b6ff5a0bb7f1 Mon Sep 17 00:00:00 2001 From: AndraBisca Date: Tue, 4 Jun 2024 11:00:50 -0600 Subject: [PATCH 12/12] Experimental srcOffsets and dstOffsets in ObjFifo Link --- mlir/lib/Conversion/AIRToAIEPass.cpp | 31 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/mlir/lib/Conversion/AIRToAIEPass.cpp b/mlir/lib/Conversion/AIRToAIEPass.cpp index 6430a6290..02b4e2bdb 100644 --- a/mlir/lib/Conversion/AIRToAIEPass.cpp +++ b/mlir/lib/Conversion/AIRToAIEPass.cpp @@ -1183,9 +1183,9 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { std::vector channelGets = getChannelGetOpThroughSymbol(channel, device); - channel->print(llvm::outs()); - llvm::outs() << "channelPuts" << channelPuts.size() << "\n"; - llvm::outs() << "channelGets" << channelGets.size() << "\n"; + // channel->print(llvm::outs()); + // llvm::outs() << "channelPuts" << channelPuts.size() << "\n"; + // llvm::outs() << "channelGets" << channelGets.size() << "\n"; // variables to track LinkOp, i.e., a put and get using the same // AIE.BufferOp @@ -1419,8 +1419,8 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { int mem_space = memref.getMemorySpaceAsInt(); // remove mem_space from memref for objFifo datatype if (datatype->first != (int)air::MemorySpace::L1) { - *datatype = {mem_space, - MemRefType::get(memref.getShape(), memref.getElementType())}; + *datatype = {mem_space, memref}; + //MemRefType::get(memref.getShape(), memref.getElementType())}; } if (mem_space == (int)air::MemorySpace::L1) { AIE::CoreOp core = op->template getParentOfType(); @@ -1584,19 +1584,30 @@ struct LowerAIRChannelsPattern : public OpRewritePattern { auto output_pairs = linkEnds[buff].output_ofs_with_offsets; std::vector input_ofs; std::vector output_ofs; - std::sort(input_pairs.begin(), input_pairs.end(), sortLinkObjectFifos); - std::sort(output_pairs.begin(), output_pairs.end(), sortLinkObjectFifos); + //std::sort(input_pairs.begin(), input_pairs.end(), sortLinkObjectFifos); + //std::sort(output_pairs.begin(), output_pairs.end(), sortLinkObjectFifos); // retrieve only objectFifo symbol ref attributes - for (auto p : input_pairs) + std::vector srcOffsets; + std::vector dstOffsets; + for (auto p : input_pairs) { input_ofs.push_back(p.first); - for (auto p : output_pairs) + auto offset = rewriter.create( + rewriter.getUnknownLoc(), rewriter.getIndexAttr(p.second)); + srcOffsets.push_back(offset->getResult(0)); + } + for (auto p : output_pairs) { output_ofs.push_back(p.first); + auto offset = rewriter.create( + rewriter.getUnknownLoc(), rewriter.getIndexAttr(p.second)); + dstOffsets.push_back(offset->getResult(0)); + } // check if all ends have been found // if yes, create ObjectFifoLinkOp if ((int)input_ofs.size() + (int)output_ofs.size() == numEnds) { rewriter.create( rewriter.getUnknownLoc(), rewriter.getArrayAttr(ArrayRef(input_ofs)), - rewriter.getArrayAttr(ArrayRef(output_ofs))); + rewriter.getArrayAttr(ArrayRef(output_ofs)), + srcOffsets, dstOffsets); } }