@@ -653,8 +653,8 @@ struct Promoter {
653653 Value resolveSlot (Value projectionOrSlot);
654654
655655 void captureAcrossWait ();
656- void captureAcrossWait (ProbeOp probeOp , ArrayRef<WaitOp> waitOps,
657- Liveness &liveness, DominanceInfo &dominance);
656+ void captureValueAcrossWait (Value value , ArrayRef<WaitOp> waitOps,
657+ Liveness &liveness, DominanceInfo &dominance);
658658
659659 void constructLattice ();
660660 void propagateBackward ();
@@ -847,7 +847,9 @@ Value Promoter::resolveSlot(Value projectionOrSlot) {
847847// / Explicitly capture any probes that are live across an `llhd.wait` as block
848848// / arguments and destination operand of that wait. This ensures that replacing
849849// / the probe with a reaching definition later on will capture the value of the
850- // / reaching definition before the wait.
850+ // / reaching definition before the wait. Also capture any extract ops of probes
851+ // / that are live across wait, to allow the extract result (e.g., i1) to be
852+ // / captured instead of the full probe result (e.g., i8).
851853void Promoter::captureAcrossWait () {
852854 if (region.hasOneBlock ())
853855 return ;
@@ -861,53 +863,81 @@ void Promoter::captureAcrossWait() {
861863 Liveness liveness (region.getParentOp ());
862864
863865 SmallVector<WaitOp> crossingWaitOps;
866+
867+ // Capture probes that are live across wait ops.
864868 for (auto &block : region) {
865869 for (auto probeOp : block.getOps <ProbeOp>()) {
866870 for (auto waitOp : waitOps)
867871 if (liveness.getLiveness (waitOp->getBlock ())->isLiveOut (probeOp))
868872 crossingWaitOps.push_back (waitOp);
869873 if (!crossingWaitOps.empty ()) {
870- captureAcrossWait (probeOp, crossingWaitOps, liveness, dominance);
874+ captureValueAcrossWait (probeOp, crossingWaitOps, liveness, dominance);
875+ crossingWaitOps.clear ();
876+ }
877+ }
878+ }
879+
880+ // Capture extract ops of probes that are live across wait ops. This handles
881+ // cases like `@(posedge data[0])` where the extract result (i1) should be
882+ // captured instead of the probe result (i8), enabling the probe to be hoisted.
883+ for (auto &block : region) {
884+ for (auto extractOp : block.getOps <comb::ExtractOp>()) {
885+ // Only handle extracts of probe results.
886+ if (!extractOp.getInput ().getDefiningOp <ProbeOp>())
887+ continue ;
888+ for (auto waitOp : waitOps)
889+ if (liveness.getLiveness (waitOp->getBlock ())->isLiveOut (extractOp))
890+ crossingWaitOps.push_back (waitOp);
891+ if (!crossingWaitOps.empty ()) {
892+ captureValueAcrossWait (extractOp, crossingWaitOps, liveness, dominance);
871893 crossingWaitOps.clear ();
872894 }
873895 }
874896 }
875897}
876898
877- // / Add a probe as block argument to a list of wait ops and update uses of the
878- // / probe to use the added block arguments as appropriate. This may insert
879- // / additional block arguments in case the probe and added block arguments both
899+ // / Add a value as block argument to a list of wait ops and update uses of the
900+ // / value to use the added block arguments as appropriate. This may insert
901+ // / additional block arguments in case the value and added block arguments both
880902// / reach the same block.
881- void Promoter::captureAcrossWait (ProbeOp probeOp, ArrayRef<WaitOp> waitOps,
882- Liveness &liveness, DominanceInfo &dominance) {
903+ void Promoter::captureValueAcrossWait (Value value, ArrayRef<WaitOp> waitOps,
904+ Liveness &liveness,
905+ DominanceInfo &dominance) {
883906 LLVM_DEBUG ({
884- llvm::dbgs () << " Capture " << probeOp << " \n " ;
907+ llvm::dbgs () << " Capture " << value << " \n " ;
885908 for (auto waitOp : waitOps)
886909 llvm::dbgs () << " - Across " << waitOp << " \n " ;
887910 });
888911
889- // Calculate the merge points for this probe once it gets promoted to block
912+ // Get the block where the value is defined.
913+ Block *defBlock = nullptr ;
914+ if (auto *defOp = value.getDefiningOp ())
915+ defBlock = defOp->getBlock ();
916+ else
917+ defBlock = cast<BlockArgument>(value).getOwner ();
918+
919+ // Calculate the merge points for this value once it gets promoted to block
890920 // arguments across the wait ops.
891921 auto &domTree = dominance.getDomTree (®ion);
892922 llvm::IDFCalculatorBase<Block, false > idfCalculator (domTree);
893923
894- // Calculate the set of blocks which will define this probe as a distinct
924+ // Calculate the set of blocks which will define this value as a distinct
895925 // value.
896926 SmallPtrSet<Block *, 4 > definingBlocks;
897- definingBlocks.insert (probeOp-> getBlock () );
927+ definingBlocks.insert (defBlock );
898928 for (auto waitOp : waitOps)
899929 definingBlocks.insert (waitOp.getDest ());
900930 idfCalculator.setDefiningBlocks (definingBlocks);
901931
902- // Calculate where the probe is live.
932+ // Calculate where the value is live.
903933 SmallPtrSet<Block *, 16 > liveInBlocks;
904934 for (auto &block : region)
905- if (liveness.getLiveness (&block)->isLiveIn (probeOp ))
935+ if (liveness.getLiveness (&block)->isLiveIn (value ))
906936 liveInBlocks.insert (&block);
907937 idfCalculator.setLiveInBlocks (liveInBlocks);
908938
909939 // Calculate the merge points where we will have to insert block arguments for
910- // this probe .
940+ // this value .
911941 SmallVector<Block *> mergePointsVec;
912942 idfCalculator.calculate (mergePointsVec);
913943 SmallPtrSet<Block *, 16 > mergePoints (mergePointsVec.begin (),
@@ -916,29 +946,29 @@ void Promoter::captureAcrossWait(ProbeOp probeOp, ArrayRef<WaitOp> waitOps,
916946 mergePoints.insert (waitOp.getDest ());
917947 LLVM_DEBUG (llvm::dbgs () << " - " << mergePoints.size () << " merge points\n " );
918948
919- // Perform a depth-first search starting at the block containing the probe ,
949+ // Perform a depth-first search starting at the block containing the value ,
920950 // which dominates all its uses. When we encounter a block that is a merge
921951 // point, insert a block argument.
922952 struct WorklistItem {
923953 DominanceInfoNode *domNode;
924954 Value reachingDef;
925955 };
926956 SmallVector<WorklistItem> worklist;
927- worklist.push_back ({domTree.getNode (probeOp-> getBlock ()), probeOp });
957+ worklist.push_back ({domTree.getNode (defBlock), value });
928958
929959 while (!worklist.empty ()) {
930960 auto item = worklist.pop_back_val ();
931961 auto *block = item.domNode ->getBlock ();
932962
933- // If this block is a merge point, insert a block argument for the probe .
963+ // If this block is a merge point, insert a block argument for the value .
934964 if (mergePoints.contains (block))
935965 item.reachingDef =
936- block->addArgument (probeOp .getType (), probeOp .getLoc ());
966+ block->addArgument (value .getType (), value .getLoc ());
937967
938- // Replace any uses of the probe in this block with the current reaching
968+ // Replace any uses of the value in this block with the current reaching
939969 // definition.
940970 for (auto &op : *block)
941- op.replaceUsesOfWith (probeOp , item.reachingDef );
971+ op.replaceUsesOfWith (value , item.reachingDef );
942972
943973 // If the terminator of this block branches to a merge point, add the
944974 // current reaching definition as a destination operand.
0 commit comments