Optimize bufferization

This commit is contained in:
ilgeco
2026-07-30 18:43:43 +02:00
parent c12f69133d
commit 1e7699f3e5
7 changed files with 78 additions and 9 deletions
+5 -2
View File
@@ -620,10 +620,13 @@ void PimCodeGen::codeGenLmvOp(pim::PimMemCopyOp lmvOp, const StaticValueKnowledg
}
void PimCodeGen::codeGenReceiveOp(pim::PimReceiveOp receiveOp, const StaticValueKnowledge& knowledge) const {
auto outputOffset = indexOf(receiveOp.getOutputOffset(), knowledge);
auto sourceCoreId = indexOf(receiveOp.getSourceCoreId(), knowledge);
assert(succeeded(sourceCoreId) && "pim.receive source core id must be statically resolvable during codegen");
assert(succeeded(outputOffset) && succeeded(sourceCoreId)
&& "pim.receive offset and source core id must be statically resolvable during codegen");
emitCommunicationOp(
pim_binary::Opcode::recv, addressOf(receiveOp.getOutputBuffer(), knowledge), *sourceCoreId, receiveOp.getSize());
pim_binary::Opcode::recv, addressOf(receiveOp.getOutputBuffer(), knowledge) + *outputOffset,
*sourceCoreId, receiveOp.getSize());
}
void PimCodeGen::codeGenSendOp(pim::PimSendOp sendOp, const StaticValueKnowledge& knowledge) const {
@@ -348,7 +348,9 @@ LogicalResult raptor::SpatialToPimPass::lowerComputeOp(spatial::SpatScheduledCom
return failure();
Value received =
PimReceiveOp::create(
rewriter, receiveOp.getLoc(), outputBuffer.getType(), outputBuffer, *sizeAttr, receiveOp.getSourceCoreId())
rewriter, receiveOp.getLoc(), outputBuffer.getType(), outputBuffer,
arith::ConstantIndexOp::create(rewriter, receiveOp.getLoc(), 0),
*sizeAttr, receiveOp.getSourceCoreId())
.getOutput();
blockArg->replaceAllUsesWith(received);
markOpToRemove(receiveOp);
@@ -85,8 +85,9 @@ struct ChannelReceiveLowering : OpRewritePattern<spatial::SpatChannelReceiveOp>
auto sizeAttr = getTensorSizeInBytesAttr(rewriter, op.getOperation(), op.getResult());
if (failed(sizeAttr))
return failure();
Value zero = arith::ConstantIndexOp::create(rewriter, op.getLoc(), 0);
auto receive = pim::PimReceiveOp::create(
rewriter, op.getLoc(), op.getResult().getType(), outputBuffer, *sizeAttr, op.getSourceCoreId());
rewriter, op.getLoc(), op.getResult().getType(), outputBuffer, zero, *sizeAttr, op.getSourceCoreId());
copyRaptorDebugAttrs(op.getOperation(), receive.getOperation());
Value received = receive.getOutput();
if (!destinationInsert) {
@@ -96,7 +97,6 @@ struct ChannelReceiveLowering : OpRewritePattern<spatial::SpatChannelReceiveOp>
rewriter.setInsertionPoint(destinationInsert);
Value targetOffset = createDestinationByteOffset(rewriter, destinationInsert);
Value zero = arith::ConstantIndexOp::create(rewriter, op.getLoc(), 0);
auto copy = pim::PimMemCopyOp::create(
rewriter, op.getLoc(), destinationInsert.getDestType(), targetOffset, zero,
destinationInsert.getDest(), received, *sizeAttr);
+3 -1
View File
@@ -97,6 +97,7 @@ def PimReceiveOp : PimOp<"receive", [DestinationStyleOpInterface]> {
let arguments = (ins
PimTensor:$outputBuffer,
Index:$outputOffset,
I32Attr:$size,
Index:$sourceCoreId
);
@@ -112,7 +113,8 @@ def PimReceiveOp : PimOp<"receive", [DestinationStyleOpInterface]> {
}];
let assemblyFormat = [{
`(` $outputBuffer `,` $sourceCoreId `)` attr-dict `:` type($outputBuffer) `->` type($output)
`[` $outputOffset `]` `(` $outputBuffer `,` $sourceCoreId `)` attr-dict
`:` type($outputBuffer) `->` type($output)
}];
}
@@ -189,7 +189,8 @@ struct ReceiveOpInterface : DstBufferizableOpInterfaceExternalModel<ReceiveOpInt
Value contiguousOutput = allocateContiguousResultMemRefLike(*outputBufferOpt, op->getLoc(), rewriter);
replaceOpWithNewBufferizedOp<PimReceiveOp>(
rewriter, op, contiguousOutput.getType(), contiguousOutput, receiveOp.getSizeAttr(), receiveOp.getSourceCoreId());
rewriter, op, contiguousOutput.getType(), contiguousOutput, receiveOp.getOutputOffset(),
receiveOp.getSizeAttr(), receiveOp.getSourceCoreId());
return success();
}
};
@@ -9,6 +9,7 @@
#include "mlir/IR/Dominance.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Interfaces/DestinationStyleOpInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
@@ -177,12 +178,22 @@ static void forwardSingleConsumerContiguousInputCopies(func::FuncOp funcOp) {
if (hasOtherUse || !consumerUse)
continue;
Value output = getForwardedInputConsumerOutput(*consumerUse);
Value source = copy.getSource();
if (!output || !isDeviceLocalPimAddress(source)
if (!isDeviceLocalPimAddress(source)
|| (failed(resolveContiguousAddress(source)) && failed(compileContiguousAddressExpr(source))))
continue;
if (isa<PimSendOp>(consumerUse->getOwner())) {
consumerUse->set(source);
copy.erase();
targetAlloc.erase();
continue;
}
Value output = getForwardedInputConsumerOutput(*consumerUse);
if (!output)
continue;
FailureOr<Value> sourceBase = getPimAddressBase(source);
FailureOr<Value> outputBase = getPimAddressBase(output);
if (failed(sourceBase) || failed(outputBase) || *sourceBase == *outputBase)
@@ -251,6 +262,46 @@ static void forwardSingleConsumerPimOutputCopies(func::FuncOp funcOp) {
}
}
static void forwardSingleConsumerReceiveCopies(func::FuncOp funcOp) {
SmallVector<PimMemCopyOp> copies;
funcOp.walk([&](PimMemCopyOp copy) { copies.push_back(copy); });
for (PimMemCopyOp copy : copies) {
auto receive = copy.getSource().getDefiningOp<PimReceiveOp>();
auto outputAlloc = receive
? receive.getOutputBuffer().getDefiningOp<memref::AllocOp>()
: memref::AllocOp();
auto sourceOffset = getConstantIntValue(copy.getSourceOffset());
if (!receive || !outputAlloc || !receive.getOutput().hasOneUse()
|| !outputAlloc.getResult().hasOneUse()
|| !sourceOffset || *sourceOffset != 0
|| copy.getSize() != receive.getSize()
|| receive->getBlock() != copy->getBlock())
continue;
bool canSinkReceive = true;
for (Operation* between = receive->getNextNode(); between != copy;
between = between->getNextNode()) {
if (!isMemoryEffectFree(between)) {
canSinkReceive = false;
break;
}
}
if (!canSinkReceive)
continue;
OpBuilder builder(copy);
auto forwarded = PimReceiveOp::create(
builder, receive.getLoc(), copy.getOutput().getType(), copy.getTarget(),
copy.getTargetOffset(), receive.getSizeAttr(), receive.getSourceCoreId());
forwarded->setAttrs(receive->getAttrs());
copy.getOutput().replaceAllUsesWith(forwarded.getOutput());
copy.erase();
receive.erase();
outputAlloc.erase();
}
}
enum class ExpectedPimCopyDirection { HostToDevice, DeviceToHost, DeviceToDevice };
static LogicalResult verifyPimCopyEndpoints(Operation* copy,
@@ -406,6 +457,7 @@ void PimBufferizationPass::runOnOperation() {
return;
}
forwardSingleConsumerReceiveCopies(funcOp);
forwardSingleConsumerContiguousInputCopies(funcOp);
forwardSingleConsumerPimOutputCopies(funcOp);
@@ -990,6 +990,15 @@ private:
hasFailure = true;
}
}
if (auto receiveOp = dyn_cast<pim::PimReceiveOp>(op);
receiveOp
&& failed(resolveIndexValue(receiveOp.getOutputOffset(), knowledge))) {
diagnostics.report(&op, [](Operation* illegalOp) {
illegalOp->emitOpError(
"output offset must be statically evaluable for PIM codegen");
});
hasFailure = true;
}
return success(!hasFailure);
});
}