diff --git a/llvm/lib/CodeGen/InterleavedAccessPass.cpp b/llvm/lib/CodeGen/InterleavedAccessPass.cpp index 8b6e3180986c3..c6d5533fd2bae 100644 --- a/llvm/lib/CodeGen/InterleavedAccessPass.cpp +++ b/llvm/lib/CodeGen/InterleavedAccessPass.cpp @@ -100,21 +100,21 @@ class InterleavedAccessImpl { /// Transform an interleaved load into target specific intrinsics. bool lowerInterleavedLoad(LoadInst *LI, - SmallVectorImpl &DeadInsts); + SmallSetVector &DeadInsts); /// Transform an interleaved store into target specific intrinsics. bool lowerInterleavedStore(StoreInst *SI, - SmallVectorImpl &DeadInsts); + SmallSetVector &DeadInsts); /// Transform a load and a deinterleave intrinsic into target specific /// instructions. bool lowerDeinterleaveIntrinsic(IntrinsicInst *II, - SmallVectorImpl &DeadInsts); + SmallSetVector &DeadInsts); /// Transform an interleave intrinsic and a store into target specific /// instructions. bool lowerInterleaveIntrinsic(IntrinsicInst *II, - SmallVectorImpl &DeadInsts); + SmallSetVector &DeadInsts); /// Returns true if the uses of an interleaved load by the /// extractelement instructions in \p Extracts can be replaced by uses of the @@ -249,7 +249,7 @@ static bool isReInterleaveMask(ShuffleVectorInst *SVI, unsigned &Factor, } bool InterleavedAccessImpl::lowerInterleavedLoad( - LoadInst *LI, SmallVectorImpl &DeadInsts) { + LoadInst *LI, SmallSetVector &DeadInsts) { if (!LI->isSimple() || isa(LI->getType())) return false; @@ -348,9 +348,9 @@ bool InterleavedAccessImpl::lowerInterleavedLoad( return !Extracts.empty() || BinOpShuffleChanged; } - append_range(DeadInsts, Shuffles); + DeadInsts.insert(Shuffles.begin(), Shuffles.end()); - DeadInsts.push_back(LI); + DeadInsts.insert(LI); return true; } @@ -453,7 +453,7 @@ bool InterleavedAccessImpl::tryReplaceExtracts( } bool InterleavedAccessImpl::lowerInterleavedStore( - StoreInst *SI, SmallVectorImpl &DeadInsts) { + StoreInst *SI, SmallSetVector &DeadInsts) { if (!SI->isSimple()) return false; @@ -473,13 +473,13 @@ bool InterleavedAccessImpl::lowerInterleavedStore( return false; // Already have a new target specific interleaved store. Erase the old store. - DeadInsts.push_back(SI); - DeadInsts.push_back(SVI); + DeadInsts.insert(SI); + DeadInsts.insert(SVI); return true; } bool InterleavedAccessImpl::lowerDeinterleaveIntrinsic( - IntrinsicInst *DI, SmallVectorImpl &DeadInsts) { + IntrinsicInst *DI, SmallSetVector &DeadInsts) { LoadInst *LI = dyn_cast(DI->getOperand(0)); if (!LI || !LI->hasOneUse() || !LI->isSimple()) @@ -488,17 +488,19 @@ bool InterleavedAccessImpl::lowerDeinterleaveIntrinsic( LLVM_DEBUG(dbgs() << "IA: Found a deinterleave intrinsic: " << *DI << "\n"); // Try and match this with target specific intrinsics. - if (!TLI->lowerDeinterleaveIntrinsicToLoad(DI, LI, DeadInsts)) + SmallVector DeinterleaveDeadInsts; + if (!TLI->lowerDeinterleaveIntrinsicToLoad(DI, LI, DeinterleaveDeadInsts)) return false; + DeadInsts.insert(DeinterleaveDeadInsts.begin(), DeinterleaveDeadInsts.end()); // We now have a target-specific load, so delete the old one. - DeadInsts.push_back(DI); - DeadInsts.push_back(LI); + DeadInsts.insert(DI); + DeadInsts.insert(LI); return true; } bool InterleavedAccessImpl::lowerInterleaveIntrinsic( - IntrinsicInst *II, SmallVectorImpl &DeadInsts) { + IntrinsicInst *II, SmallSetVector &DeadInsts) { if (!II->hasOneUse()) return false; @@ -515,16 +517,15 @@ bool InterleavedAccessImpl::lowerInterleaveIntrinsic( return false; // We now have a target-specific store, so delete the old one. - DeadInsts.push_back(SI); - DeadInsts.push_back(II); - DeadInsts.insert(DeadInsts.end(), InterleaveDeadInsts.begin(), - InterleaveDeadInsts.end()); + DeadInsts.insert(SI); + DeadInsts.insert(II); + DeadInsts.insert(InterleaveDeadInsts.begin(), InterleaveDeadInsts.end()); return true; } bool InterleavedAccessImpl::runOnFunction(Function &F) { // Holds dead instructions that will be erased later. - SmallVector DeadInsts; + SmallSetVector DeadInsts; bool Changed = false; for (auto &I : instructions(F)) { diff --git a/llvm/test/Transforms/InterleavedAccess/AArch64/sve-interleave4.ll b/llvm/test/Transforms/InterleavedAccess/AArch64/sve-interleave4.ll index e8d113ae3763d..085089978d8f5 100644 --- a/llvm/test/Transforms/InterleavedAccess/AArch64/sve-interleave4.ll +++ b/llvm/test/Transforms/InterleavedAccess/AArch64/sve-interleave4.ll @@ -55,3 +55,17 @@ define void @mix_interleave4_interleave2(ptr %dst1, ptr %dst2, %interleaved, ptr %dst2, align 4 ret void } + +; This case tests when the interleave is using same parameter twice, +; the dead parameter will not get deleted twice. +define void @duplicate_by_interleave( %A, %B, ptr writeonly %AB_duplicate) { +; CHECK-LABEL: define void @duplicate_by_interleave +; CHECK-SAME: ( [[A:%.*]], [[B:%.*]], ptr writeonly [[AB_DUPLICATE:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: call void @llvm.aarch64.sve.st4.nxv4i32( [[A]], [[A]], [[B]], [[B]], splat (i1 true), ptr [[AB_DUPLICATE]]) +; CHECK-NEXT: ret void +; + %interleave = tail call @llvm.vector.interleave2.nxv8i32( %A, %B) + %duplicate_by_interleave = tail call @llvm.vector.interleave2.nxv16i32( %interleave, %interleave) + store %duplicate_by_interleave, ptr %AB_duplicate, align 4 + ret void +}