@@ -140,52 +140,77 @@ bool VPlanTransforms::tryToConvertVPInstructionsToVPRecipes(
140140 return true ;
141141}
142142
143- // Return true if \p A and \p B are known to not alias for all VFs in the plan,
144- // checked via the distance between the accesses
145- static bool isNoAliasViaDistance (VPReplicateRecipe *A, VPReplicateRecipe *B,
146- ScalarEvolution &SE, const Loop &L,
147- VPTypeAnalysis &TypeInfo) {
148- if (A->getOpcode () != Instruction::Store ||
149- B->getOpcode () != Instruction::Store)
150- return false ;
143+ // / Helper for extra no-alias checks via known-safe recipe and SCEV.
144+ class SinkStoreInfo {
145+ const SmallPtrSetImpl<VPRecipeBase *> &ExcludeRecipes;
146+ VPReplicateRecipe &GroupLeader;
147+ ScalarEvolution &SE;
148+ const Loop &L;
149+ VPTypeAnalysis &TypeInfo;
150+
151+ // Return true if \p A and \p B are known to not alias for all VFs in the
152+ // plan, checked via the distance between the accesses
153+ bool isNoAliasViaDistance (VPReplicateRecipe *A, VPReplicateRecipe *B) const {
154+ if (A->getOpcode () != Instruction::Store ||
155+ B->getOpcode () != Instruction::Store)
156+ return false ;
151157
152- VPValue *AddrA = A->getOperand (1 );
153- const SCEV *SCEVA = vputils::getSCEVExprForVPValue (AddrA, SE, &L);
154- VPValue *AddrB = B->getOperand (1 );
155- const SCEV *SCEVB = vputils::getSCEVExprForVPValue (AddrB, SE, &L);
156- if (isa<SCEVCouldNotCompute>(SCEVA) || isa<SCEVCouldNotCompute>(SCEVB))
157- return false ;
158+ VPValue *AddrA = A->getOperand (1 );
159+ const SCEV *SCEVA = vputils::getSCEVExprForVPValue (AddrA, SE, &L);
160+ VPValue *AddrB = B->getOperand (1 );
161+ const SCEV *SCEVB = vputils::getSCEVExprForVPValue (AddrB, SE, &L);
162+ if (isa<SCEVCouldNotCompute>(SCEVA) || isa<SCEVCouldNotCompute>(SCEVB))
163+ return false ;
158164
159- const APInt *Distance;
160- if (!match (SE.getMinusSCEV (SCEVA, SCEVB), m_scev_APInt (Distance)))
161- return false ;
165+ const APInt *Distance;
166+ if (!match (SE.getMinusSCEV (SCEVA, SCEVB), m_scev_APInt (Distance)))
167+ return false ;
162168
163- const DataLayout &DL = L.getHeader ()->getModule ()->getDataLayout ();
164- Type *TyA = TypeInfo.inferScalarType (A->getOperand (0 ));
165- uint64_t SizeA = DL.getTypeStoreSize (TyA);
166- Type *TyB = TypeInfo.inferScalarType (B->getOperand (0 ));
167- uint64_t SizeB = DL.getTypeStoreSize (TyB);
168- // Use the maximum store size to ensure no overlap from either direction.
169- uint64_t MaxStoreSize = std::max (SizeA, SizeB);
170-
171- auto VFs = B->getParent ()->getPlan ()->vectorFactors ();
172- ElementCount MaxVF = *max_element (VFs, ElementCount::isKnownLT);
173- return Distance->abs ().uge (
174- MaxVF.multiplyCoefficientBy (MaxStoreSize).getFixedValue ());
175- }
169+ const DataLayout &DL = L.getHeader ()->getModule ()->getDataLayout ();
170+ Type *TyA = TypeInfo.inferScalarType (A->getOperand (0 ));
171+ uint64_t SizeA = DL.getTypeStoreSize (TyA);
172+ Type *TyB = TypeInfo.inferScalarType (B->getOperand (0 ));
173+ uint64_t SizeB = DL.getTypeStoreSize (TyB);
174+ // Use the maximum store size to ensure no overlap from either direction.
175+ // Currently only handles fixed sizes, as it is only used for
176+ // replicating VPReplicateRecipes.
177+ uint64_t MaxStoreSize = std::max (SizeA, SizeB);
178+
179+ auto VFs = B->getParent ()->getPlan ()->vectorFactors ();
180+ ElementCount MaxVF = *max_element (VFs, ElementCount::isKnownLT);
181+ return Distance->abs ().uge (
182+ MaxVF.multiplyCoefficientBy (MaxStoreSize).getFixedValue ());
183+ }
184+
185+ public:
186+ SinkStoreInfo (const SmallPtrSetImpl<VPRecipeBase *> &ExcludeRecipes,
187+ VPReplicateRecipe &GroupLeader, ScalarEvolution &SE,
188+ const Loop &L, VPTypeAnalysis &TypeInfo)
189+ : ExcludeRecipes(ExcludeRecipes), GroupLeader(GroupLeader), SE(SE), L(L),
190+ TypeInfo (TypeInfo) {}
191+
192+ // / Return true if \p R should be skipped during alias checking, either
193+ // / because it's in the exclude set or because no-alias can be proven via
194+ // / SCEV.
195+ bool shouldSkip (VPRecipeBase &R) const {
196+ if (ExcludeRecipes.contains (&R))
197+ return true ;
198+ if (auto *Store = dyn_cast<VPReplicateRecipe>(&R))
199+ return isNoAliasViaDistance (Store, &GroupLeader);
200+ return false ;
201+ }
202+ };
176203
177- // Check if a memory operation doesn't alias with memory operations in blocks
178- // between FirstBB and LastBB using scoped noalias metadata. If \p CheckReads is
179- // false, we only check recipes that may write to memory. Otherwise we check
180- // recipes that both read and write memory. If a \p GroupLeader is passed, SCEV
181- // is used to try to prove no-alias between \p GroupLeader and other replicate
182- // recipes.
204+ // / Check if a memory operation doesn't alias with memory operations in blocks
205+ // / between \p FirstBB and \p LastBB using scoped noalias metadata. If
206+ // / \p SinkInfo is std::nullopt, only recipes that may write to memory are
207+ // / checked (for load hoisting). Otherwise recipes that both read and write
208+ // / memory are checked, and SCEV is used to prove no-alias between the group
209+ // / leader and other replicate recipes (for store sinking) .
183210static bool canHoistOrSinkWithNoAliasCheck (
184211 const MemoryLocation &MemLoc, VPBasicBlock *FirstBB, VPBasicBlock *LastBB,
185- bool CheckReads,
186- const SmallPtrSetImpl<VPRecipeBase *> *ExcludeRecipes = nullptr ,
187- VPReplicateRecipe *GroupLeader = nullptr , ScalarEvolution *SE = nullptr ,
188- const Loop *L = nullptr , VPTypeAnalysis *TypeInfo = nullptr ) {
212+ std::optional<SinkStoreInfo> SinkInfo = std::nullopt ) {
213+ bool CheckReads = SinkInfo.has_value ();
189214 if (!MemLoc.AATags .Scope )
190215 return false ;
191216
@@ -197,22 +222,13 @@ static bool canHoistOrSinkWithNoAliasCheck(
197222 " Expected at most one successor in block chain" );
198223 auto *VPBB = cast<VPBasicBlock>(Block);
199224 for (VPRecipeBase &R : *VPBB) {
200- if (ExcludeRecipes && ExcludeRecipes-> contains (& R))
225+ if (SinkInfo && SinkInfo-> shouldSkip ( R))
201226 continue ;
202227
203228 // Skip recipes that don't need checking.
204229 if (!R.mayWriteToMemory () && !(CheckReads && R.mayReadFromMemory ()))
205230 continue ;
206231
207- // For stores, check if we can use SCEV to prove no-alias with the group
208- // leader (all members of the group write to the same address with the
209- // same size).
210- if (auto *Store = dyn_cast<VPReplicateRecipe>(&R)) {
211- if (GroupLeader &&
212- isNoAliasViaDistance (Store, GroupLeader, *SE, *L, *TypeInfo))
213- continue ;
214- }
215-
216232 auto Loc = vputils::getMemoryLocation (R);
217233 if (!Loc)
218234 // Conservatively assume aliasing for memory operations without
@@ -4317,8 +4333,7 @@ void VPlanTransforms::hoistPredicatedLoads(VPlan &Plan, ScalarEvolution &SE,
43174333
43184334 // Check that the load doesn't alias with stores between first and last.
43194335 auto LoadLoc = vputils::getMemoryLocation (*EarliestLoad);
4320- if (!LoadLoc || !canHoistOrSinkWithNoAliasCheck (*LoadLoc, FirstBB, LastBB,
4321- /* CheckReads=*/ false ))
4336+ if (!LoadLoc || !canHoistOrSinkWithNoAliasCheck (*LoadLoc, FirstBB, LastBB))
43224337 continue ;
43234338
43244339 // Collect common metadata from all loads in the group.
@@ -4346,7 +4361,7 @@ void VPlanTransforms::hoistPredicatedLoads(VPlan &Plan, ScalarEvolution &SE,
43464361
43474362static bool
43484363canSinkStoreWithNoAliasCheck (ArrayRef<VPReplicateRecipe *> StoresToSink,
4349- ScalarEvolution * SE, const Loop * L,
4364+ ScalarEvolution & SE, const Loop & L,
43504365 VPTypeAnalysis &TypeInfo) {
43514366 auto StoreLoc = vputils::getMemoryLocation (*StoresToSink.front ());
43524367 if (!StoreLoc || !StoreLoc->AATags .Scope )
@@ -4359,9 +4374,8 @@ canSinkStoreWithNoAliasCheck(ArrayRef<VPReplicateRecipe *> StoresToSink,
43594374
43604375 VPBasicBlock *FirstBB = StoresToSink.front ()->getParent ();
43614376 VPBasicBlock *LastBB = StoresToSink.back ()->getParent ();
4362- return canHoistOrSinkWithNoAliasCheck (*StoreLoc, FirstBB, LastBB,
4363- /* CheckReads=*/ true , &StoresToSinkSet,
4364- StoresToSink[0 ], SE, L, &TypeInfo);
4377+ SinkStoreInfo Info (StoresToSinkSet, *StoresToSink[0 ], SE, L, TypeInfo);
4378+ return canHoistOrSinkWithNoAliasCheck (*StoreLoc, FirstBB, LastBB, Info);
43654379}
43664380
43674381void VPlanTransforms::sinkPredicatedStores (VPlan &Plan, ScalarEvolution &SE,
@@ -4379,7 +4393,7 @@ void VPlanTransforms::sinkPredicatedStores(VPlan &Plan, ScalarEvolution &SE,
43794393 return VPDT.properlyDominates (A, B);
43804394 });
43814395
4382- if (!canSinkStoreWithNoAliasCheck (Group, & SE, L, TypeInfo))
4396+ if (!canSinkStoreWithNoAliasCheck (Group, SE, * L, TypeInfo))
43834397 continue ;
43844398
43854399 // Use the last (most dominated) store's location for the unconditional
0 commit comments