-
Notifications
You must be signed in to change notification settings - Fork 38
infer pipe init nosplit from split-0 users #452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,6 +55,7 @@ struct PipeInitInfo { | |
| Operation *op = nullptr; | ||
| func::FuncOp funcOp; | ||
| int8_t dirMask = 0; | ||
| bool inferredNoSplit = false; | ||
| }; | ||
|
|
||
| template <typename InitOpT> static Value getLocalAddrOperand(InitOpT op) { | ||
|
|
@@ -72,6 +73,35 @@ static void setFlagBaseAttr(InitOpT op, IntegerAttr attr) { | |
| op->setAttr("flag_base", attr); | ||
| } | ||
|
|
||
| template <typename InitOpT> | ||
| static void setNoSplitAttr(InitOpT op, BoolAttr attr) { | ||
| op->setAttr("nosplit", attr); | ||
| } | ||
|
|
||
| template <typename InitOpT> static Value getPipeResult(InitOpT op) { | ||
| return op.getPipe(); | ||
| } | ||
|
|
||
| static bool inferNoSplitFromPipeUsers(Value pipe) { | ||
| for (Operation *user : pipe.getUsers()) { | ||
| if (auto pushOp = dyn_cast<TPushOp>(user)) { | ||
| if (pushOp.getSplit() == 0) | ||
| return true; | ||
| continue; | ||
| } | ||
| if (auto popOp = dyn_cast<TPopOp>(user)) { | ||
| if (popOp.getSplit() == 0) | ||
| return true; | ||
| continue; | ||
| } | ||
| if (auto freeOp = dyn_cast<TFreeOp>(user)) { | ||
| if (freeOp.getSplit() == 0) | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| static ReserveBufferOp findReserveBufferByName(func::FuncOp funcOp, | ||
| StringRef name) { | ||
| // Reserve-buffer lookup is name-based because import_reserved_buffer only | ||
|
|
@@ -140,6 +170,7 @@ struct PTOResolveReservedBuffersPass | |
| info.op = initOp.getOperation(); | ||
| info.funcOp = initOp->template getParentOfType<func::FuncOp>(); | ||
| info.dirMask = initOp.getDirMask(); | ||
| info.inferredNoSplit = inferNoSplitFromPipeUsers(getPipeResult(initOp)); | ||
|
|
||
| // Record one address into the keyed maps. Returns true when the | ||
| // address comes from reserve_buffer / import_reserved_buffer. | ||
|
|
@@ -187,6 +218,7 @@ struct PTOResolveReservedBuffersPass | |
| } | ||
|
|
||
| OpBuilder builder(moduleOp.getContext()); | ||
| std::set<Operation *> groupedNoSplitResolved; | ||
| for (const auto &it : keyedInits) { | ||
| const auto &inits = it.second; | ||
| // flag_base is always 0: single-direction pipes use flag pair 0/1; | ||
|
|
@@ -221,18 +253,44 @@ struct PTOResolveReservedBuffersPass | |
| chosenBase = desiredBase; | ||
|
|
||
| auto flagBaseAttr = builder.getI32IntegerAttr(*chosenBase); | ||
| bool groupNoSplit = false; | ||
| for (const PipeInitInfo &info : inits) { | ||
| if (info.inferredNoSplit) { | ||
| groupNoSplit = true; | ||
| break; | ||
| } | ||
| } | ||
| for (const PipeInitInfo &info : inits) { | ||
| if (auto initOp = dyn_cast<InitializeL2LPipeOp>(info.op)) { | ||
| if (!getFlagBaseAttr(initOp)) | ||
| setFlagBaseAttr(initOp, flagBaseAttr); | ||
| if (groupNoSplit) | ||
| setNoSplitAttr(initOp, builder.getBoolAttr(true)); | ||
| groupedNoSplitResolved.insert(info.op); | ||
| continue; | ||
| } | ||
| auto initOp = cast<InitializeL2G2LPipeOp>(info.op); | ||
| if (!getFlagBaseAttr(initOp)) | ||
| setFlagBaseAttr(initOp, flagBaseAttr); | ||
| if (groupNoSplit) | ||
| setNoSplitAttr(initOp, builder.getBoolAttr(true)); | ||
| groupedNoSplitResolved.insert(info.op); | ||
| } | ||
| } | ||
|
|
||
| moduleOp.walk([&](InitializeL2LPipeOp initOp) { | ||
| if (groupedNoSplitResolved.count(initOp.getOperation())) | ||
| return; | ||
| if (inferNoSplitFromPipeUsers(initOp.getPipe())) | ||
| setNoSplitAttr(initOp, builder.getBoolAttr(true)); | ||
| }); | ||
| moduleOp.walk([&](InitializeL2G2LPipeOp initOp) { | ||
| if (groupedNoSplitResolved.count(initOp.getOperation())) | ||
| return; | ||
| if (inferNoSplitFromPipeUsers(initOp.getPipe())) | ||
| setNoSplitAttr(initOp, builder.getBoolAttr(true)); | ||
| }); | ||
|
Comment on lines
+281
to
+292
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic inside the two For example, you could define a helper function: template <typename InitOpT>
void resolveStandaloneNoSplit(InitOpT initOp,
const std::set<Operation *> &resolvedOps,
OpBuilder &builder) {
if (resolvedOps.count(initOp.getOperation())) {
return;
}
if (inferNoSplitFromPipeUsers(getPipeResult(initOp))) {
setNoSplitAttr(initOp, builder.getBoolAttr(true));
}
}And then call it from the moduleOp.walk([&](InitializeL2LPipeOp initOp) {
resolveStandaloneNoSplit(initOp, groupedNoSplitResolved, builder);
});
moduleOp.walk([&](InitializeL2G2LPipeOp initOp) {
resolveStandaloneNoSplit(initOp, groupedNoSplitResolved, builder);
}); |
||
|
|
||
| return success(); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // RUN: ptoas --pto-arch=a5 %s 2>&1 | FileCheck %s --check-prefix=A5 | ||
|
|
||
| module { | ||
| func.func @cube_kernel() attributes {pto.kernel_kind = #pto.kernel_kind<cube>} { | ||
| %v2c_local = pto.reserve_buffer { | ||
| name = "v2c_fifo", | ||
| size = 4096, | ||
| location = #pto.address_space<mat>, | ||
| auto = true | ||
| } -> i32 | ||
| %c2v_import = pto.import_reserved_buffer { | ||
| name = "c2v_fifo", | ||
| peer_func = @vector_kernel | ||
| } -> i32 | ||
| pto.aic_initialize_pipe {dir_mask = 3, slot_size = 1024} | ||
| (c2v_consumer_buf = %c2v_import : i32, | ||
| v2c_consumer_buf = %v2c_local : i32) | ||
|
|
||
| %acc_tile = pto.alloc_tile : !pto.tile_buf<loc=acc, dtype=f32, rows=16, cols=16, v_row=16, v_col=16, blayout=col_major, slayout=row_major, fractal=1024, pad=0> | ||
| pto.tpush_to_aiv(%acc_tile : !pto.tile_buf<loc=acc, dtype=f32, rows=16, cols=16, v_row=16, v_col=16, blayout=col_major, slayout=row_major, fractal=1024, pad=0>) {split = 1} | ||
| return | ||
| } | ||
|
|
||
| func.func @vector_kernel() attributes {pto.kernel_kind = #pto.kernel_kind<vector>} { | ||
| %c2v_local = pto.reserve_buffer { | ||
| name = "c2v_fifo", | ||
| size = 4096, | ||
| location = #pto.address_space<vec>, | ||
| auto = true | ||
| } -> i32 | ||
| %v2c_import = pto.import_reserved_buffer { | ||
| name = "v2c_fifo", | ||
| peer_func = @cube_kernel | ||
| } -> i32 | ||
| pto.aiv_initialize_pipe {dir_mask = 3, slot_size = 1024} | ||
| (c2v_consumer_buf = %c2v_local : i32, | ||
| v2c_consumer_buf = %v2c_import : i32) | ||
|
|
||
| %recv_tile = pto.tpop_from_aic {split = 0} | ||
| -> !pto.tile_buf<loc=vec, dtype=f32, rows=16, cols=16, v_row=16, v_col=16, blayout=row_major, slayout=none_box, fractal=512, pad=0> | ||
| pto.tfree_from_aic {split = 1} | ||
| return | ||
| } | ||
| } | ||
|
|
||
| // A5-LABEL: AICORE void cube_kernel( | ||
| // A5: auto {{v[0-9]+}} = TPipe<0, Direction::DIR_BOTH, 1024, 4, true>( | ||
| // A5: TPUSH<TPipe<0, Direction::DIR_BOTH, 1024, 4, true> | ||
|
|
||
| // A5-LABEL: AICORE void vector_kernel( | ||
| // A5: auto {{v[0-9]+}} = TPipe<0, Direction::DIR_BOTH, 1024, 4, true>( | ||
| // A5: TPOP<TPipe<0, Direction::DIR_BOTH, 1024, 4, true>, Tile<TileType::Vec, float, 16, 16, BLayout::RowMajor, 16, 16, SLayout::NoneBox, 512, PadValue::Null>, TileSplitAxis::TILE_NO_SPLIT>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The series of
ifstatements withcontinuecan be refactored into a more conciseif-else ifchain. This improves readability and is slightly more efficient as it avoids redundant checks. Thecontinuestatements are also unnecessary since theifblocks return immediately.