@@ -583,42 +583,39 @@ struct ArgumentUsesTracker : public CaptureTracker {
583583 const SCCNodeSet &SCCNodes;
584584};
585585
586- // A struct of argument use: a Use and the offset it accesses. This struct
587- // is to track uses inside function via GEP. If GEP has a non-constant index,
588- // the Offset field is nullopt.
586+ // / A struct of argument use: a Use and the offset it accesses. This struct
587+ // / is to track uses inside function via GEP. If GEP has a non-constant index,
588+ // / the Offset field is nullopt.
589589struct ArgumentUse {
590590 Use *U;
591591 std::optional<int64_t > Offset;
592592};
593593
594- // A struct of argument access info. "Unknown" accesses are the cases like
595- // unrecognized instructions, instructions that have more than one use of
596- // the argument, or volatile memory accesses. "Unknown" implies "IsClobber"
597- // and an empty access range.
598- // Write or Read accesses can be clobbers as well for example, a Load with
599- // scalable type.
594+ // / A struct of argument access info. "Unknown" accesses are the cases like
595+ // / unrecognized instructions, instructions that have more than one use of
596+ // / the argument, or volatile memory accesses. "WriteWithSideEffect" are call
597+ // / instructions that not only write an argument but also capture it.
600598struct ArgumentAccessInfo {
601- enum class AccessType : uint8_t { Write, Read, Unknown };
599+ enum class AccessType : uint8_t { Write, WriteWithSideEffect, Read, Unknown };
602600 AccessType ArgAccessType;
603- bool IsClobber = false ;
604601 ConstantRangeList AccessRanges;
605602};
606603
607- // A struct to wrap the argument use info per block.
604+ // / A struct to wrap the argument use info per block.
608605struct UsesPerBlockInfo {
609606 SmallDenseMap<Instruction *, ArgumentAccessInfo, 4 > Insts;
610607 bool HasWrites = false ;
611- bool HasClobber = false ;
608+ bool HasUnknownAccess = false ;
612609};
613610
614- // A struct to summarize the argument use info in a function.
611+ // / A struct to summarize the argument use info in a function.
615612struct ArgumentUsesSummary {
616613 bool HasAnyWrite = false ;
617614 bool HasWriteOutsideEntryBB = false ;
618615 SmallDenseMap<const BasicBlock *, UsesPerBlockInfo, 16 > UsesPerBlock;
619616};
620617
621- ArgumentAccessInfo GetArgmentAccessInfo (const Instruction *I,
618+ ArgumentAccessInfo getArgmentAccessInfo (const Instruction *I,
622619 const ArgumentUse &ArgUse,
623620 const DataLayout &DL) {
624621 auto GetTypeAccessRange =
@@ -643,38 +640,33 @@ ArgumentAccessInfo GetArgmentAccessInfo(const Instruction *I,
643640 return std::nullopt ;
644641 };
645642 if (auto *SI = dyn_cast<StoreInst>(I)) {
646- if (! SI->isVolatile () && &SI->getOperandUse (1 ) == ArgUse.U ) {
643+ if (SI->isSimple () && &SI->getOperandUse (1 ) == ArgUse.U ) {
647644 // Get the fixed type size of "SI". Since the access range of a write
648645 // will be unioned, if "SI" doesn't have a fixed type size, we just set
649646 // the access range to empty.
650647 ConstantRangeList AccessRanges;
651648 if (auto TypeAccessRange =
652649 GetTypeAccessRange (SI->getAccessType (), ArgUse.Offset ))
653650 AccessRanges.insert (*TypeAccessRange);
654- return {ArgumentAccessInfo::AccessType::Write,
655- /* IsClobber=*/ false , AccessRanges};
651+ return {ArgumentAccessInfo::AccessType::Write, std::move (AccessRanges)};
656652 }
657653 } else if (auto *LI = dyn_cast<LoadInst>(I)) {
658- if (! LI->isVolatile ()) {
654+ if (LI->isSimple ()) {
659655 assert (&LI->getOperandUse (0 ) == ArgUse.U );
660656 // Get the fixed type size of "LI". Different from Write, if "LI"
661657 // doesn't have a fixed type size, we conservatively set as a clobber
662658 // with an empty access range.
663659 if (auto TypeAccessRange =
664660 GetTypeAccessRange (LI->getAccessType (), ArgUse.Offset ))
665- return {ArgumentAccessInfo::AccessType::Read,
666- /* IsClobber=*/ false ,
667- {*TypeAccessRange}};
668- return {ArgumentAccessInfo::AccessType::Read, /* IsClobber=*/ true , {}};
661+ return {ArgumentAccessInfo::AccessType::Read, {*TypeAccessRange}};
669662 }
670663 } else if (auto *MemSet = dyn_cast<MemSetInst>(I)) {
671664 if (!MemSet->isVolatile ()) {
672665 ConstantRangeList AccessRanges;
673666 if (auto AccessRange =
674667 GetConstantIntRange (MemSet->getLength (), ArgUse.Offset ))
675668 AccessRanges.insert (*AccessRange);
676- return {ArgumentAccessInfo::AccessType::Write,
677- /* IsClobber=*/ false , AccessRanges};
669+ return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
678670 }
679671 } else if (auto *MTI = dyn_cast<MemTransferInst>(I)) {
680672 if (!MTI->isVolatile ()) {
@@ -683,44 +675,42 @@ ArgumentAccessInfo GetArgmentAccessInfo(const Instruction *I,
683675 if (auto AccessRange =
684676 GetConstantIntRange (MTI->getLength (), ArgUse.Offset ))
685677 AccessRanges.insert (*AccessRange);
686- return {ArgumentAccessInfo::AccessType::Write,
687- /* IsClobber=*/ false , AccessRanges};
678+ return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
688679 } else if (&MTI->getOperandUse (1 ) == ArgUse.U ) {
689680 if (auto AccessRange =
690681 GetConstantIntRange (MTI->getLength (), ArgUse.Offset ))
691- return {ArgumentAccessInfo::AccessType::Read,
692- /* IsClobber=*/ false ,
693- {*AccessRange}};
694- return {ArgumentAccessInfo::AccessType::Read, /* IsClobber=*/ true , {}};
682+ return {ArgumentAccessInfo::AccessType::Read, {*AccessRange}};
695683 }
696684 }
697685 } else if (auto *CB = dyn_cast<CallBase>(I)) {
698686 if (CB->isArgOperand (ArgUse.U )) {
699687 unsigned ArgNo = CB->getArgOperandNo (ArgUse.U );
700688 bool IsInitialize = CB->paramHasAttr (ArgNo, Attribute::Initializes);
701- // Argument is only not clobbered when parameter is writeonly/readnone
702- // and nocapture.
703- bool IsClobber = !(CB->onlyWritesMemory (ArgNo) &&
704- CB->paramHasAttr (ArgNo, Attribute::NoCapture));
689+ // Argument is a Write when parameter is writeonly/readnone
690+ // and nocapture. Otherwise, it's a WriteWithSideEffect.
691+ auto Access = CB->onlyWritesMemory (ArgNo) &&
692+ CB->paramHasAttr (ArgNo, Attribute::NoCapture)
693+ ? ArgumentAccessInfo::AccessType::Write
694+ : ArgumentAccessInfo::AccessType::WriteWithSideEffect;
705695 ConstantRangeList AccessRanges;
706696 if (IsInitialize && ArgUse.Offset ) {
707697 Attribute Attr = CB->getParamAttr (ArgNo, Attribute::Initializes);
708698 ConstantRangeList CBCRL = Attr.getValueAsConstantRangeList ();
709699 for (ConstantRange &CR : CBCRL)
710700 AccessRanges.insert (ConstantRange (CR.getLower () + *ArgUse.Offset ,
711701 CR.getUpper () + *ArgUse.Offset ));
712- return {ArgumentAccessInfo::AccessType::Write, IsClobber , AccessRanges};
702+ return {Access , AccessRanges};
713703 }
714704 }
715705 }
716- // Unrecognized instructions are considered clobbers .
717- return {ArgumentAccessInfo::AccessType::Unknown, /* IsClobber= */ true , {}};
706+ // Other unrecognized instructions are considered as unknown .
707+ return {ArgumentAccessInfo::AccessType::Unknown, {}};
718708}
719709
720710// Collect the uses of argument "A" in "F".
721- ArgumentUsesSummary CollectArgumentUsesPerBlock (Argument &A, Function &F) {
711+ ArgumentUsesSummary collectArgumentUsesPerBlock (Argument &A, Function &F) {
722712 auto &DL = F.getParent ()->getDataLayout ();
723- auto PointerSize =
713+ unsigned PointerSize =
724714 DL.getIndexSizeInBits (A.getType ()->getPointerAddressSpace ());
725715 ArgumentUsesSummary Result;
726716
@@ -733,22 +723,25 @@ ArgumentUsesSummary CollectArgumentUsesPerBlock(Argument &A, Function &F) {
733723 // Return true if the block of "I" has write accesses after updating.
734724 auto UpdateUseInfo = [&Result](Instruction *I, ArgumentAccessInfo Info) {
735725 auto *BB = I->getParent ();
736- auto &BBInfo = Result.UsesPerBlock . getOrInsertDefault (BB) ;
726+ auto &BBInfo = Result.UsesPerBlock [BB] ;
737727 bool AlreadyVisitedInst = BBInfo.Insts .contains (I);
738728 auto &IInfo = BBInfo.Insts [I];
739729
740730 // Instructions that have more than one use of the argument are considered
741731 // as clobbers.
742732 if (AlreadyVisitedInst) {
743- IInfo = {ArgumentAccessInfo::AccessType::Unknown, /* IsClobber= */ true , {}};
744- BBInfo.HasClobber = true ;
733+ IInfo = {ArgumentAccessInfo::AccessType::Unknown, {}};
734+ BBInfo.HasUnknownAccess = true ;
745735 return false ;
746736 }
747737
748- IInfo = Info;
749- BBInfo.HasClobber |= IInfo.IsClobber ;
738+ IInfo = std::move (Info);
739+ BBInfo.HasUnknownAccess |=
740+ IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown;
750741 bool InfoHasWrites =
751- IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Write &&
742+ (IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
743+ IInfo.ArgAccessType ==
744+ ArgumentAccessInfo::AccessType::WriteWithSideEffect) &&
752745 !IInfo.AccessRanges .empty ();
753746 BBInfo.HasWrites |= InfoHasWrites;
754747 return InfoHasWrites;
@@ -762,18 +755,19 @@ ArgumentUsesSummary CollectArgumentUsesPerBlock(Argument &A, Function &F) {
762755 // Add GEP uses to worklist.
763756 // If the GEP is not a constant GEP, set the ArgumentUse::Offset to nullopt.
764757 if (auto *GEP = dyn_cast<GEPOperator>(U)) {
765- APInt Offset (PointerSize, 0 , /* isSigned=*/ true );
766- bool IsConstGEP = GEP->accumulateConstantOffset (DL, Offset);
767758 std::optional<int64_t > NewOffset = std::nullopt ;
768- if (IsConstGEP && ArgUse.Offset )
769- NewOffset = *ArgUse.Offset + Offset.getSExtValue ();
759+ if (ArgUse.Offset ) {
760+ APInt Offset (PointerSize, 0 );
761+ if (GEP->accumulateConstantOffset (DL, Offset))
762+ NewOffset = *ArgUse.Offset + Offset.getSExtValue ();
763+ }
770764 for (Use &U : GEP->uses ())
771765 Worklist.push_back ({&U, NewOffset});
772766 continue ;
773767 }
774768
775769 auto *I = cast<Instruction>(U);
776- bool HasWrite = UpdateUseInfo (I, GetArgmentAccessInfo (I, ArgUse, DL));
770+ bool HasWrite = UpdateUseInfo (I, getArgmentAccessInfo (I, ArgUse, DL));
777771
778772 Result.HasAnyWrite |= HasWrite;
779773
@@ -1070,7 +1064,7 @@ static bool addAccessAttr(Argument *A, Attribute::AttrKind R) {
10701064}
10711065
10721066static bool inferInitializes (Argument &A, Function &F) {
1073- auto ArgumentUses = CollectArgumentUsesPerBlock (A, F);
1067+ auto ArgumentUses = collectArgumentUsesPerBlock (A, F);
10741068 // No write anywhere in the function, bail.
10751069 if (!ArgumentUses.HasAnyWrite )
10761070 return false ;
@@ -1091,7 +1085,7 @@ static bool inferInitializes(Argument &A, Function &F) {
10911085 // If this block has any clobbering use, we're going to clear out the
10921086 // ranges at some point in this block anyway, so don't bother looking at
10931087 // successors.
1094- if (UPB == UsesPerBlock.end () || !UPB->second .HasClobber ) {
1088+ if (UPB == UsesPerBlock.end () || !UPB->second .HasUnknownAccess ) {
10951089 bool HasAddedSuccessor = false ;
10961090 for (auto *Succ : successors (BB)) {
10971091 if (auto SuccI = Initialized.find (Succ); SuccI != Initialized.end ()) {
@@ -1120,10 +1114,14 @@ static bool inferInitializes(Argument &A, Function &F) {
11201114 // From the end of the block to the beginning of the block, set
11211115 // initializes ranges.
11221116 for (auto &[_, Info] : reverse (Insts)) {
1123- if (Info.IsClobber )
1117+ if (Info.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown ||
1118+ Info.ArgAccessType ==
1119+ ArgumentAccessInfo::AccessType::WriteWithSideEffect)
11241120 CRL = ConstantRangeList ();
11251121 if (!Info.AccessRanges .empty ()) {
1126- if (Info.ArgAccessType == ArgumentAccessInfo::AccessType::Write) {
1122+ if (Info.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
1123+ Info.ArgAccessType ==
1124+ ArgumentAccessInfo::AccessType::WriteWithSideEffect) {
11271125 CRL = CRL.unionWith (Info.AccessRanges );
11281126 } else {
11291127 assert (Info.ArgAccessType == ArgumentAccessInfo::AccessType::Read);
@@ -1143,7 +1141,7 @@ static bool inferInitializes(Argument &A, Function &F) {
11431141 if (!OnlyScanEntryBlock)
11441142 if (auto EntryUPB = UsesPerBlock.find (&EntryBB);
11451143 EntryUPB != UsesPerBlock.end ())
1146- OnlyScanEntryBlock = EntryUPB->second .HasClobber ;
1144+ OnlyScanEntryBlock = EntryUPB->second .HasUnknownAccess ;
11471145 if (OnlyScanEntryBlock) {
11481146 EntryCRL = VisitBlock (&EntryBB);
11491147 if (EntryCRL.empty ())
0 commit comments