@@ -229,6 +229,8 @@ class BCECmpBlock {
229229 InstructionSet BlockInsts;
230230 // The block requires splitting.
231231 bool RequireSplit = false ;
232+ // Original order of this block in the chain.
233+ unsigned OrigOrder = 0 ;
232234
233235private:
234236 BCECmp Cmp;
@@ -380,39 +382,83 @@ static inline void enqueueBlock(std::vector<BCECmpBlock> &Comparisons,
380382 << Comparison.Rhs ().BaseId << " + "
381383 << Comparison.Rhs ().Offset << " \n " );
382384 LLVM_DEBUG (dbgs () << " \n " );
385+ Comparison.OrigOrder = Comparisons.size ();
383386 Comparisons.push_back (std::move (Comparison));
384387}
385388
386389// A chain of comparisons.
387390class BCECmpChain {
388- public:
389- BCECmpChain (const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
390- AliasAnalysis &AA);
391-
392- int size () const { return Comparisons_.size (); }
391+ public:
392+ using ContiguousBlocks = std::vector<BCECmpBlock>;
393393
394- #ifdef MERGEICMPS_DOT_ON
395- void dump () const ;
396- #endif // MERGEICMPS_DOT_ON
394+ BCECmpChain (const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
395+ AliasAnalysis &AA);
397396
398397 bool simplify (const TargetLibraryInfo &TLI, AliasAnalysis &AA,
399398 DomTreeUpdater &DTU);
400399
401- private:
402- static bool IsContiguous (const BCECmpBlock &First,
403- const BCECmpBlock &Second) {
404- return First.Lhs ().BaseId == Second.Lhs ().BaseId &&
405- First.Rhs ().BaseId == Second.Rhs ().BaseId &&
406- First.Lhs ().Offset + First.SizeBits () / 8 == Second.Lhs ().Offset &&
407- First.Rhs ().Offset + First.SizeBits () / 8 == Second.Rhs ().Offset ;
400+ bool atLeastOneMerged () const {
401+ return any_of (MergedBlocks_,
402+ [](const auto &Blocks) { return Blocks.size () > 1 ; });
408403 }
409404
405+ private:
410406 PHINode &Phi_;
411- std::vector<BCECmpBlock> Comparisons_;
407+ // The list of all blocks in the chain, grouped by contiguity.
408+ std::vector<ContiguousBlocks> MergedBlocks_;
412409 // The original entry block (before sorting);
413410 BasicBlock *EntryBlock_;
414411};
415412
413+ static bool areContiguous (const BCECmpBlock &First, const BCECmpBlock &Second) {
414+ return First.Lhs ().BaseId == Second.Lhs ().BaseId &&
415+ First.Rhs ().BaseId == Second.Rhs ().BaseId &&
416+ First.Lhs ().Offset + First.SizeBits () / 8 == Second.Lhs ().Offset &&
417+ First.Rhs ().Offset + First.SizeBits () / 8 == Second.Rhs ().Offset ;
418+ }
419+
420+ static unsigned getMinOrigOrder (const BCECmpChain::ContiguousBlocks &Blocks) {
421+ unsigned MinOrigOrder = std::numeric_limits<unsigned >::max ();
422+ for (const BCECmpBlock &Block : Blocks)
423+ MinOrigOrder = std::min (MinOrigOrder, Block.OrigOrder );
424+ return MinOrigOrder;
425+ }
426+
427+ // / Given a chain of comparison blocks, groups the blocks into contiguous
428+ // / ranges that can be merged together into a single comparison.
429+ static std::vector<BCECmpChain::ContiguousBlocks>
430+ mergeBlocks (std::vector<BCECmpBlock> &&Blocks) {
431+ std::vector<BCECmpChain::ContiguousBlocks> MergedBlocks;
432+
433+ // Sort to detect continuous offsets.
434+ llvm::sort (Blocks,
435+ [](const BCECmpBlock &LhsBlock, const BCECmpBlock &RhsBlock) {
436+ return std::tie (LhsBlock.Lhs (), LhsBlock.Rhs ()) <
437+ std::tie (RhsBlock.Lhs (), RhsBlock.Rhs ());
438+ });
439+
440+ BCECmpChain::ContiguousBlocks *LastMergedBlock = nullptr ;
441+ for (BCECmpBlock &Block : Blocks) {
442+ if (!LastMergedBlock || !areContiguous (LastMergedBlock->back (), Block)) {
443+ MergedBlocks.emplace_back ();
444+ LastMergedBlock = &MergedBlocks.back ();
445+ } else {
446+ LLVM_DEBUG (dbgs () << " Merging block " << Block.BB ->getName () << " into "
447+ << LastMergedBlock->back ().BB ->getName () << " \n " );
448+ }
449+ LastMergedBlock->push_back (std::move (Block));
450+ }
451+
452+ // While we allow reordering for merging, do not reorder unmerged comparisons.
453+ // Doing so may introduce branch on poison.
454+ llvm::sort (MergedBlocks, [](const BCECmpChain::ContiguousBlocks &LhsBlocks,
455+ const BCECmpChain::ContiguousBlocks &RhsBlocks) {
456+ return getMinOrigOrder (LhsBlocks) < getMinOrigOrder (RhsBlocks);
457+ });
458+
459+ return MergedBlocks;
460+ }
461+
416462BCECmpChain::BCECmpChain (const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
417463 AliasAnalysis &AA)
418464 : Phi_(Phi) {
@@ -492,46 +538,8 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
492538 return ;
493539 }
494540 EntryBlock_ = Comparisons[0 ].BB ;
495- Comparisons_ = std::move (Comparisons);
496- #ifdef MERGEICMPS_DOT_ON
497- errs () << " BEFORE REORDERING:\n\n " ;
498- dump ();
499- #endif // MERGEICMPS_DOT_ON
500- // Reorder blocks by LHS. We can do that without changing the
501- // semantics because we are only accessing dereferencable memory.
502- llvm::sort (Comparisons_,
503- [](const BCECmpBlock &LhsBlock, const BCECmpBlock &RhsBlock) {
504- return std::tie (LhsBlock.Lhs (), LhsBlock.Rhs ()) <
505- std::tie (RhsBlock.Lhs (), RhsBlock.Rhs ());
506- });
507- #ifdef MERGEICMPS_DOT_ON
508- errs () << " AFTER REORDERING:\n\n " ;
509- dump ();
510- #endif // MERGEICMPS_DOT_ON
511- }
512-
513- #ifdef MERGEICMPS_DOT_ON
514- void BCECmpChain::dump () const {
515- errs () << " digraph dag {\n " ;
516- errs () << " graph [bgcolor=transparent];\n " ;
517- errs () << " node [color=black,style=filled,fillcolor=lightyellow];\n " ;
518- errs () << " edge [color=black];\n " ;
519- for (size_t I = 0 ; I < Comparisons_.size (); ++I) {
520- const auto &Comparison = Comparisons_[I];
521- errs () << " \" " << I << " \" [label=\" %"
522- << Comparison.Lhs ().Base ()->getName () << " + "
523- << Comparison.Lhs ().Offset << " == %"
524- << Comparison.Rhs ().Base ()->getName () << " + "
525- << Comparison.Rhs ().Offset << " (" << (Comparison.SizeBits () / 8 )
526- << " bytes)\" ];\n " ;
527- const Value *const Val = Phi_.getIncomingValueForBlock (Comparison.BB );
528- if (I > 0 ) errs () << " \" " << (I - 1 ) << " \" -> \" " << I << " \" ;\n " ;
529- errs () << " \" " << I << " \" -> \" Phi\" [label=\" " << *Val << " \" ];\n " ;
530- }
531- errs () << " \" Phi\" [label=\" Phi\" ];\n " ;
532- errs () << " }\n\n " ;
541+ MergedBlocks_ = mergeBlocks (std::move (Comparisons));
533542}
534- #endif // MERGEICMPS_DOT_ON
535543
536544namespace {
537545
@@ -655,47 +663,20 @@ static BasicBlock *mergeComparisons(ArrayRef<BCECmpBlock> Comparisons,
655663
656664bool BCECmpChain::simplify (const TargetLibraryInfo &TLI, AliasAnalysis &AA,
657665 DomTreeUpdater &DTU) {
658- assert (Comparisons_.size () >= 2 && " simplifying trivial BCECmpChain" );
659- // First pass to check if there is at least one merge. If not, we don't do
660- // anything and we keep analysis passes intact.
661- const auto AtLeastOneMerged = [this ]() {
662- for (size_t I = 1 ; I < Comparisons_.size (); ++I) {
663- if (IsContiguous (Comparisons_[I - 1 ], Comparisons_[I]))
664- return true ;
665- }
666- return false ;
667- };
668- if (!AtLeastOneMerged ())
669- return false ;
670-
666+ assert (atLeastOneMerged () && " simplifying trivial BCECmpChain" );
671667 LLVM_DEBUG (dbgs () << " Simplifying comparison chain starting at block "
672668 << EntryBlock_->getName () << " \n " );
673669
674670 // Effectively merge blocks. We go in the reverse direction from the phi block
675671 // so that the next block is always available to branch to.
676- const auto mergeRange = [this , &TLI, &AA, &DTU](int I, int Num,
677- BasicBlock *InsertBefore,
678- BasicBlock *Next) {
679- return mergeComparisons (makeArrayRef (Comparisons_).slice (I, Num),
680- InsertBefore, Next, Phi_, TLI, AA, DTU);
681- };
682672 int NumMerged = 1 ;
673+ BasicBlock *InsertBefore = EntryBlock_;
683674 BasicBlock *NextCmpBlock = Phi_.getParent ();
684- for (int I = static_cast <int >(Comparisons_.size ()) - 2 ; I >= 0 ; --I) {
685- if (IsContiguous (Comparisons_[I], Comparisons_[I + 1 ])) {
686- LLVM_DEBUG (dbgs () << " Merging block " << Comparisons_[I].BB ->getName ()
687- << " into " << Comparisons_[I + 1 ].BB ->getName ()
688- << " \n " );
689- ++NumMerged;
690- } else {
691- NextCmpBlock = mergeRange (I + 1 , NumMerged, NextCmpBlock, NextCmpBlock);
692- NumMerged = 1 ;
693- }
675+ for (const auto &Blocks : reverse (MergedBlocks_)) {
676+ NumMerged += Blocks.size () - 1 ;
677+ InsertBefore = NextCmpBlock = mergeComparisons (
678+ Blocks, InsertBefore, NextCmpBlock, Phi_, TLI, AA, DTU);
694679 }
695- // Insert the entry block for the new chain before the old entry block.
696- // If the old entry block was the function entry, this ensures that the new
697- // entry can become the function entry.
698- NextCmpBlock = mergeRange (0 , NumMerged, EntryBlock_, NextCmpBlock);
699680
700681 // Replace the original cmp chain with the new cmp chain by pointing all
701682 // predecessors of EntryBlock_ to NextCmpBlock instead. This makes all cmp
@@ -723,13 +704,16 @@ bool BCECmpChain::simplify(const TargetLibraryInfo &TLI, AliasAnalysis &AA,
723704
724705 // Delete merged blocks. This also removes incoming values in phi.
725706 SmallVector<BasicBlock *, 16 > DeadBlocks;
726- for (auto &Cmp : Comparisons_) {
727- LLVM_DEBUG (dbgs () << " Deleting merged block " << Cmp.BB ->getName () << " \n " );
728- DeadBlocks.push_back (Cmp.BB );
707+ for (const auto &Blocks : MergedBlocks_) {
708+ for (const BCECmpBlock &Block : Blocks) {
709+ LLVM_DEBUG (dbgs () << " Deleting merged block " << Block.BB ->getName ()
710+ << " \n " );
711+ DeadBlocks.push_back (Block.BB );
712+ }
729713 }
730714 DeleteDeadBlocks (DeadBlocks, &DTU);
731715
732- Comparisons_ .clear ();
716+ MergedBlocks_ .clear ();
733717 return true ;
734718}
735719
@@ -829,8 +813,8 @@ bool processPhi(PHINode &Phi, const TargetLibraryInfo &TLI, AliasAnalysis &AA,
829813 if (Blocks.empty ()) return false ;
830814 BCECmpChain CmpChain (Blocks, Phi, AA);
831815
832- if (CmpChain.size () < 2 ) {
833- LLVM_DEBUG (dbgs () << " skip: only one compare block \n " );
816+ if (! CmpChain.atLeastOneMerged () ) {
817+ LLVM_DEBUG (dbgs () << " skip: nothing merged \n " );
834818 return false ;
835819 }
836820
0 commit comments