@@ -39,8 +39,9 @@ class OperationSideEffects {
39
39
const OperationSideEffects &);
40
40
41
41
public:
42
- OperationSideEffects (const Operation &op, const AliasAnalysis &aliasAnalysis)
43
- : op(op), aliasAnalysis(aliasAnalysis) {
42
+ OperationSideEffects (const Operation &op, const AliasAnalysis &aliasAnalysis,
43
+ const DominanceInfo &domInfo)
44
+ : op(op), aliasAnalysis(aliasAnalysis), domInfo(domInfo) {
44
45
if (auto memEffect = dyn_cast<MemoryEffectOpInterface>(op)) {
45
46
SmallVector<MemoryEffects::EffectInstance, 1 > effects;
46
47
memEffect.getEffects (effects);
@@ -103,6 +104,8 @@ class OperationSideEffects {
103
104
private:
104
105
const Operation &op; // / Operation associated with the side effects.
105
106
const AliasAnalysis &aliasAnalysis; // / Alias Analysis reference.
107
+ const DominanceInfo &domInfo; // / Dominance information reference.
108
+
106
109
// / Side effects associated with reading resources.
107
110
SmallVector<MemoryEffects::EffectInstance> readResources;
108
111
// / Side effects associated with writing resources.
@@ -293,7 +296,7 @@ bool OperationSideEffects::conflictsWith(const Operation &other) const {
293
296
// If the given operation has side effects, check whether they conflict with
294
297
// the side effects summarized in this class.
295
298
if (auto MEI = dyn_cast<MemoryEffectOpInterface>(other)) {
296
- OperationSideEffects sideEffects (other, aliasAnalysis);
299
+ OperationSideEffects sideEffects (other, aliasAnalysis, domInfo );
297
300
298
301
// Checks for a conflicts on the given resource 'res' by applying the
299
302
// supplied predicate function 'hasConflict'.
@@ -313,15 +316,15 @@ bool OperationSideEffects::conflictsWith(const Operation &other) const {
313
316
[[maybe_unused]] auto printConflictingSideEffects =
314
317
[](const MemoryEffects::EffectInstance &EI, AliasResult aliasRes,
315
318
const Operation &other) {
316
- llvm::dbgs () << " Found conflicting side effect: { "
317
- << EI. getResource ()-> getName () << " , " << EI. getValue ()
318
- << " }\n " ;
319
- llvm::dbgs ().indent (2 ) << " with: " << other << " \n " ;
320
- llvm::dbgs ().indent (2 ) << " aliasResult: " << aliasRes << " \n " ;
319
+ llvm::dbgs (). indent ( 2 )
320
+ << " found conflicting side effect: { "
321
+ << EI. getResource ()-> getName () << " , " << EI. getValue () << " }\n " ;
322
+ llvm::dbgs ().indent (4 ) << " with: " << other << " \n " ;
323
+ llvm::dbgs ().indent (4 ) << " aliasResult: " << aliasRes << " \n " ;
321
324
};
322
325
323
- // Check whether the given operation 'other' writes (or allocates, or frees)
324
- // a resource that is read by the operation associated with this class.
326
+ // Check whether the given operation 'other' allocates, writes, or frees a
327
+ // resource that is read by the operation associated with this class.
325
328
if (llvm::any_of (
326
329
readResources, [&](const MemoryEffects::EffectInstance &readRes) {
327
330
auto hasConflict = [&](const MemoryEffects::EffectInstance &EI) {
@@ -346,21 +349,35 @@ bool OperationSideEffects::conflictsWith(const Operation &other) const {
346
349
// Check whether the given operation 'other' allocates, reads, writes or
347
350
// frees a resource that is written by the operation associated with this
348
351
// class.
349
- if (llvm::any_of (
350
- writeResources, [&](const MemoryEffects::EffectInstance &writeRes) {
351
- auto hasConflict = [&](const MemoryEffects::EffectInstance &EI) {
352
- AliasResult aliasRes =
353
- const_cast <AliasAnalysis &>(aliasAnalysis)
354
- .alias (EI.getValue (), writeRes.getValue ());
355
- if (aliasRes.isNo ())
356
- return false ;
352
+ if (llvm::any_of (writeResources, [&](const MemoryEffects::EffectInstance
353
+ &writeRes) {
354
+ auto hasConflict = [&](const MemoryEffects::EffectInstance &EI) {
355
+ AliasResult aliasRes =
356
+ const_cast <AliasAnalysis &>(aliasAnalysis)
357
+ .alias (EI.getValue (), writeRes.getValue ());
358
+ if (aliasRes.isNo ())
359
+ return false ;
360
+
361
+ // An aliased read operation doesn't prevent hoisting if it is
362
+ // dominated by the write operation.
363
+ if (isa<MemoryEffects::Read>(EI.getEffect ()) &&
364
+ domInfo.dominates (const_cast <Operation *>(&op),
365
+ const_cast <Operation *>(&other))) {
366
+ LLVM_DEBUG ({
367
+ printConflictingSideEffects (EI, aliasRes, other);
368
+ llvm::dbgs ().indent (2 )
369
+ << " can be hoisted: aliased write operation dominates the "
370
+ " read operation\n " ;
371
+ });
372
+ return false ;
373
+ }
357
374
358
- LLVM_DEBUG (printConflictingSideEffects (EI, aliasRes, other));
359
- return true ;
360
- };
375
+ LLVM_DEBUG (printConflictingSideEffects (EI, aliasRes, other));
376
+ return true ;
377
+ };
361
378
362
- return checkForConflict (writeRes.getResource (), hasConflict);
363
- })) {
379
+ return checkForConflict (writeRes.getResource (), hasConflict);
380
+ })) {
364
381
return true ;
365
382
}
366
383
@@ -683,8 +700,9 @@ AffineIfOp AffineParallelGuardBuilder::createGuard() const {
683
700
// / conflicts in the loop are given in \p willBeMoved.
684
701
static bool hasConflictsInLoop (Operation &op, LoopLikeOpInterface loop,
685
702
const SmallPtrSetImpl<Operation *> &willBeMoved,
686
- const AliasAnalysis &aliasAnalysis) {
687
- const OperationSideEffects sideEffects (op, aliasAnalysis);
703
+ const AliasAnalysis &aliasAnalysis,
704
+ const DominanceInfo &domInfo) {
705
+ const OperationSideEffects sideEffects (op, aliasAnalysis, domInfo);
688
706
689
707
Optional<Operation *> conflictingOp =
690
708
TypeSwitch<Operation *, Optional<Operation *>>((Operation *)loop)
@@ -704,13 +722,15 @@ static bool hasConflictsInLoop(Operation &op, LoopLikeOpInterface loop,
704
722
if (conflictingOp.has_value ()) {
705
723
if (!willBeMoved.count (*conflictingOp))
706
724
return true ;
707
- LLVM_DEBUG (llvm::dbgs () << " OK: related operation will be hoisted\n " );
725
+ LLVM_DEBUG (llvm::dbgs ().indent (2 )
726
+ << " can be hoisted: conflicting operation will be hoisted\n " );
708
727
}
709
728
710
729
// Check whether the parent operation has conflicts on the loop.
711
730
if (op.getParentOp () == loop)
712
731
return false ;
713
- if (hasConflictsInLoop (*op.getParentOp (), loop, willBeMoved, aliasAnalysis))
732
+ if (hasConflictsInLoop (*op.getParentOp (), loop, willBeMoved, aliasAnalysis,
733
+ domInfo))
714
734
return true ;
715
735
716
736
// If the parent operation is not guaranteed to execute its
@@ -736,7 +756,8 @@ static bool hasConflictsInLoop(Operation &op, LoopLikeOpInterface loop,
736
756
// / to be loop invariant (and therefore will be moved outside of the loop).
737
757
static bool canBeHoisted (Operation &op, LoopLikeOpInterface loop,
738
758
const SmallPtrSetImpl<Operation *> &willBeMoved,
739
- const AliasAnalysis &aliasAnalysis) {
759
+ const AliasAnalysis &aliasAnalysis,
760
+ const DominanceInfo &domInfo) {
740
761
// Returns true if the given value can be moved outside of the loop, and
741
762
// false otherwise. A value cannot be moved outside of the loop if its
742
763
// operands are not defined outside of the loop and cannot themselves be
@@ -783,7 +804,7 @@ static bool canBeHoisted(Operation &op, LoopLikeOpInterface loop,
783
804
}
784
805
785
806
// Do not hoist operations that allocate a resource.
786
- const OperationSideEffects sideEffects (op, aliasAnalysis);
807
+ const OperationSideEffects sideEffects (op, aliasAnalysis, domInfo );
787
808
if (sideEffects.allocatesResource ()) {
788
809
LLVM_DEBUG ({
789
810
llvm::dbgs () << " Operation: " << op << " \n " ;
@@ -799,8 +820,8 @@ static bool canBeHoisted(Operation &op, LoopLikeOpInterface loop,
799
820
// loop prevent hosting it.
800
821
if ((sideEffects.readsFromResource () || sideEffects.writesToResource () ||
801
822
sideEffects.freesResource ()) &&
802
- hasConflictsInLoop (op, loop, willBeMoved, aliasAnalysis)) {
803
- LLVM_DEBUG (llvm::dbgs ()
823
+ hasConflictsInLoop (op, loop, willBeMoved, aliasAnalysis, domInfo )) {
824
+ LLVM_DEBUG (llvm::dbgs (). indent ( 2 )
804
825
<< " cannot be hoisted: found conflicting operation\n " );
805
826
return false ;
806
827
}
@@ -814,31 +835,30 @@ static bool canBeHoisted(Operation &op, LoopLikeOpInterface loop,
814
835
815
836
for (Region ®ion : op.getRegions ()) {
816
837
for (Operation &innerOp : region.getOps ()) {
817
- if (!canBeHoisted (innerOp, loop, willBeMoved2, aliasAnalysis))
838
+ if (!canBeHoisted (innerOp, loop, willBeMoved2, aliasAnalysis, domInfo ))
818
839
return false ;
819
840
willBeMoved2.insert (&innerOp);
820
841
}
821
842
}
822
843
823
- LLVM_DEBUG (llvm::dbgs () << " can be hoisted: no conflicts found\n " );
844
+ LLVM_DEBUG (llvm::dbgs (). indent ( 2 ) << " can be hoisted: no conflicts found\n " );
824
845
825
846
return true ;
826
847
}
827
848
828
849
// Populate \p opsToMove with operations that can be hoisted out of the given
829
850
// loop \p loop.
830
- static void
831
- collectHoistableOperations (LoopLikeOpInterface loop,
832
- const AliasAnalysis &aliasAnalysis,
833
- SmallVectorImpl<Operation *> &opsToMove) {
851
+ static void collectHoistableOperations (
852
+ LoopLikeOpInterface loop, const AliasAnalysis &aliasAnalysis,
853
+ const DominanceInfo &domInfo, SmallVectorImpl<Operation *> &opsToMove) {
834
854
// Do not use walk here, as we do not want to go into nested regions and
835
855
// hoist operations from there. These regions might have semantics unknown
836
856
// to this rewriting. If the nested regions are loops, they will have been
837
857
// processed.
838
858
SmallPtrSet<Operation *, 8 > willBeMoved;
839
859
for (Block &block : loop.getLoopBody ()) {
840
860
for (Operation &op : block.without_terminator ()) {
841
- if (!canBeHoisted (op, loop, willBeMoved, aliasAnalysis))
861
+ if (!canBeHoisted (op, loop, willBeMoved, aliasAnalysis, domInfo ))
842
862
continue ;
843
863
opsToMove.push_back (&op);
844
864
willBeMoved.insert (&op);
@@ -847,13 +867,14 @@ collectHoistableOperations(LoopLikeOpInterface loop,
847
867
}
848
868
849
869
static size_t moveLoopInvariantCode (LoopLikeOpInterface loop,
850
- const AliasAnalysis &aliasAnalysis) {
870
+ const AliasAnalysis &aliasAnalysis,
871
+ const DominanceInfo &domInfo) {
851
872
Operation *loopOp = loop;
852
873
if (!isa<scf::ForOp, scf::ParallelOp, AffineParallelOp, AffineForOp>(loopOp))
853
874
return 0 ;
854
875
855
876
SmallVector<Operation *, 8 > opsToMove;
856
- collectHoistableOperations (loop, aliasAnalysis, opsToMove);
877
+ collectHoistableOperations (loop, aliasAnalysis, domInfo, opsToMove);
857
878
if (opsToMove.empty ())
858
879
return 0 ;
859
880
@@ -870,6 +891,7 @@ static size_t moveLoopInvariantCode(LoopLikeOpInterface loop,
870
891
871
892
void LICM::runOnOperation () {
872
893
AliasAnalysis &aliasAnalysis = getAnalysis<AliasAnalysis>();
894
+ DominanceInfo &domInfo = getAnalysis<DominanceInfo>();
873
895
874
896
[[maybe_unused]] auto getParentFunction = [](LoopLikeOpInterface loop) {
875
897
Operation *parentOp = loop;
@@ -905,7 +927,7 @@ void LICM::runOnOperation() {
905
927
906
928
// Now use this pass to hoist more complex operations.
907
929
{
908
- size_t OpHoisted = moveLoopInvariantCode (loop, aliasAnalysis);
930
+ size_t OpHoisted = moveLoopInvariantCode (loop, aliasAnalysis, domInfo );
909
931
numOpHoisted += OpHoisted;
910
932
911
933
LLVM_DEBUG ({
0 commit comments