167 bool verifyNonZeroTrip) {
181 if (verifyNonZeroTrip) {
182 root->
walk([&](LoopLikeOpInterface loopLike) {
183 std::optional<SmallVector<OpFoldResult>> lbs =
184 loopLike.getLoopLowerBounds();
185 std::optional<SmallVector<OpFoldResult>> ubs =
186 loopLike.getLoopUpperBounds();
194 for (
auto [lb,
ub] : llvm::zip_equal(lbs.value(), ubs.value())) {
195 FailureOr<int64_t> maxLb =
202 FailureOr<int64_t> minUb =
207 if (minUb.value() <= maxLb.value())
209 definiteNonZeroTripCountLoops.insert(loopLike);
217 root->
walk([&](vector::TransferReadOp transferRead) {
218 if (!isa<MemRefType>(transferRead.getShapedType()))
221 LLVM_DEBUG(
DBGS() <<
"Candidate for hoisting: "
222 << *transferRead.getOperation() <<
"\n");
225 Operation *readOrMaskedRead = transferRead;
226 if (
auto mask = dyn_cast<vector::MaskOp>(transferRead->getParentOp()))
227 if (mask.getMaskableOp() == transferRead.getOperation())
228 readOrMaskedRead = mask.getOperation();
230 dyn_cast<LoopLikeOpInterface>(readOrMaskedRead->
getParentOp());
233 if (!isa_and_nonnull<scf::ForOp, affine::AffineForOp>(loop))
236 if (verifyNonZeroTrip && !definiteNonZeroTripCountLoops.contains(loop)) {
237 LLVM_DEBUG(
DBGS() <<
"Loop may have zero trip count: " << *loop
242 LLVM_DEBUG(
DBGS() <<
"Candidate read: " << *transferRead.getOperation()
252 vector::TransferWriteOp transferWrite;
253 for (
auto *sliceOp : llvm::reverse(forwardSlice)) {
254 auto candidateWrite = dyn_cast<vector::TransferWriteOp>(sliceOp);
255 if (!candidateWrite ||
256 candidateWrite.getBase() != transferRead.getBase())
258 transferWrite = candidateWrite;
262 for (
auto operand : transferRead.getOperands())
263 if (!loop.isDefinedOutsideOfLoop(operand))
267 auto readMask = dyn_cast<vector::MaskOp>(readOrMaskedRead);
269 if (!loop.isDefinedOutsideOfLoop(readMask.getMask()))
271 if (readMask.getPassthru() &&
272 !loop.isDefinedOutsideOfLoop(readMask.getPassthru()))
278 if (!transferWrite) {
284 loop.moveOutOfLoop(readOrMaskedRead);
291 Operation *writeOrMaskedWrite = transferWrite;
292 if (
auto mask = dyn_cast<vector::MaskOp>(transferWrite->getParentOp()))
293 if (mask.getMaskableOp() == transferWrite.getOperation())
294 writeOrMaskedWrite = mask.getOperation();
295 auto writeMask = dyn_cast<vector::MaskOp>(writeOrMaskedWrite);
296 if (!!readMask != !!writeMask)
298 if (readMask && readMask.getMask() != writeMask.getMask())
301 LLVM_DEBUG(
DBGS() <<
"Candidate: " << *transferWrite.getOperation()
314 if (transferRead.getIndices() != transferWrite.getIndices() ||
315 transferRead.getVectorType() != transferWrite.getVectorType() ||
316 transferRead.getPermutationMap() != transferWrite.getPermutationMap())
321 auto base = transferRead.getBase();
324 std::optional<bool> viewAliasingIsSafeCache;
325 auto viewAliasingIsSafe = [&]() {
326 if (!viewAliasingIsSafeCache) {
327 Operation *hoistedPair[] = {transferRead, transferWrite};
328 viewAliasingIsSafeCache =
331 return *viewAliasingIsSafeCache;
333 auto *source = base.getDefiningOp();
346 if (
auto assume = dyn_cast<memref::AssumeAlignmentOp>(source)) {
347 Value memPreAlignment = assume.getMemref();
349 llvm::count_if(base.getUses(), [&loop](
OpOperand &use) {
350 return loop->isAncestor(use.getOwner());
353 if (numInLoopUses && memPreAlignment.
hasOneUse())
356 if (isa_and_nonnull<ViewLikeOpInterface>(source) &&
357 !viewAliasingIsSafe())
361 if (llvm::any_of(base.getUsers(), llvm::IsaPred<ViewLikeOpInterface>) &&
362 !viewAliasingIsSafe())
374 for (
auto &use : transferRead.getBase().getUses()) {
375 if (!loop->isAncestor(use.getOwner()))
377 if (use.getOwner() == transferRead.getOperation() ||
378 use.getOwner() == transferWrite.getOperation())
380 if (
auto transferWriteUse =
381 dyn_cast<vector::TransferWriteOp>(use.getOwner())) {
383 cast<VectorTransferOpInterface>(*transferWrite),
384 cast<VectorTransferOpInterface>(*transferWriteUse),
387 }
else if (
auto transferReadUse =
388 dyn_cast<vector::TransferReadOp>(use.getOwner())) {
390 cast<VectorTransferOpInterface>(*transferWrite),
391 cast<VectorTransferOpInterface>(*transferReadUse),
402 loop.moveOutOfLoop(readOrMaskedRead);
410 IRRewriter rewriter(transferRead.getContext());
416 auto maybeNewLoop = loop.replaceWithAdditionalYields(
417 rewriter, readOrMaskedRead->
getResult(0),
419 if (failed(maybeNewLoop))
422 transferWrite.getValueToStoreMutable().assign(
423 maybeNewLoop->getOperation()->getResults().back());
434 if (changed || !verifyNonZeroTrip)
436 root->
walk([&](vector::TransferWriteOp transferWrite) {
437 if (!isa<MemRefType>(transferWrite.getShapedType()))
442 Operation *writeOrMaskedWrite = transferWrite;
443 if (
auto mask = dyn_cast<vector::MaskOp>(transferWrite->getParentOp()))
444 if (mask.getMaskableOp() == transferWrite.getOperation())
445 writeOrMaskedWrite = mask.getOperation();
447 dyn_cast<LoopLikeOpInterface>(writeOrMaskedWrite->
getParentOp());
448 if (!isa_and_nonnull<scf::ForOp, affine::AffineForOp>(loop) ||
449 !definiteNonZeroTripCountLoops.contains(loop))
453 for (
auto operand : transferWrite.getOperands())
454 if (!loop.isDefinedOutsideOfLoop(operand))
458 if (
auto writeMask = dyn_cast<vector::MaskOp>(writeOrMaskedWrite))
459 if (!loop.isDefinedOutsideOfLoop(writeMask.getMask()))
464 Operation *sunkWrite[] = {transferWrite};