From b8cc3802fb00b38c1e83d3881c3678a61ae92017 Mon Sep 17 00:00:00 2001 From: likai00 Date: Tue, 23 Jun 2026 14:32:01 +0800 Subject: [PATCH] clear residual op in vpto emit --- lib/PTO/Transforms/FoldTileBufIntrinsics.cpp | 74 ++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/lib/PTO/Transforms/FoldTileBufIntrinsics.cpp b/lib/PTO/Transforms/FoldTileBufIntrinsics.cpp index 37cdc785d..4520d249a 100644 --- a/lib/PTO/Transforms/FoldTileBufIntrinsics.cpp +++ b/lib/PTO/Transforms/FoldTileBufIntrinsics.cpp @@ -394,6 +394,7 @@ struct FoldTileBufIntrinsicsPass SmallVector tvAddrOps; SmallVector tvDimOps; SmallVector tvStrideOps; + SmallVector getValidShapeOps; func.walk([&](Operation *op) { if (auto addr = dyn_cast(op)) @@ -408,9 +409,50 @@ struct FoldTileBufIntrinsicsPass tvDimOps.push_back(tvDim); else if (auto tvStride = dyn_cast(op)) tvStrideOps.push_back(tvStride); + else if (auto gvs = dyn_cast(op)) + getValidShapeOps.push_back(gvs); }); if (shouldFoldAddrFamily(*mode)) { + // Fold pto.get_validshape into the materialized tile handle + // valid_row / valid_col. This must precede tile_buf_addr and + // tile_valid_{rows,cols} folding: set_validshape operands are usually + // produced by get_validshape, so resolving them first lets + // resolveTileHandle observe the overridden valid shape carried by a + // treshape + set_validshape pair. + for (auto gvsOp : getValidShapeOps) { + if (!isa(gvsOp.getSource().getType())) + continue; + + auto handleInfo = resolveTileHandle(gvsOp.getSource(), gvsOp); + if (!handleInfo) + return signalPassFailure(); + + builder.setInsertionPoint(gvsOp); + auto tileTy = cast(gvsOp.getSource().getType()); + auto validShape = tileTy.getValidShape(); + + Value rowReplacement = handleInfo->validRow; + if (!validShape.empty() && validShape[0] != ShapedType::kDynamic) + rowReplacement = + builder.create(gvsOp.getLoc(), validShape[0]); + + Value colReplacement = handleInfo->validCol; + if (validShape.size() >= 2 && validShape[1] != ShapedType::kDynamic) + colReplacement = + builder.create(gvsOp.getLoc(), validShape[1]); + + if (!rowReplacement || !colReplacement) { + gvsOp.emitError("FoldTileBufIntrinsics: pto.get_validshape could not " + "resolve a concrete valid_row / valid_col"); + return signalPassFailure(); + } + + gvsOp.getValidRow().replaceAllUsesWith(rowReplacement); + gvsOp.getValidCol().replaceAllUsesWith(colReplacement); + gvsOp.erase(); + } + // Fold pto.tile_buf_addr by recovering the active materialized tile // handle contract: // - pto.materialize_tile → use the source memref directly @@ -714,6 +756,38 @@ struct FoldTileBufIntrinsicsPass op->erase(); } + // Erase pto.set_validshape ops. Every valid-shape reader + // (get_validshape / tile_valid_{rows,cols} / tile_buf_addr) has been + // folded above, so the runtime metadata writes have no remaining + // observer and have no LLVM lowering. + SmallVector setValidShapeOps; + func.walk([&](pto::SetValidShapeOp op) { setValidShapeOps.push_back(op); }); + for (auto op : llvm::reverse(setValidShapeOps)) + op.erase(); + + // DCE tile-handle view / alloc ops left behind after valid-shape + // folding (treshape / materialize_tile / alloc_tile / bridging casts). + bool tileDceChanged = true; + while (tileDceChanged) { + tileDceChanged = false; + SmallVector deadTileOps; + func.walk([&](Operation *op) { + if (!op->use_empty()) + return; + if (isa(op)) + deadTileOps.push_back(op); + else if (auto castOp = dyn_cast(op)) { + if (castOp.getNumOperands() == 1 && + isa(castOp.getResult(0).getType())) + deadTileOps.push_back(op); + } + }); + for (auto *op : llvm::reverse(deadTileOps)) { + op->erase(); + tileDceChanged = true; + } + } + eraseDeadAllocTileOps(func); } };