Skip to content

Commit eb2d9cf

Browse files
committed
Update and rename clobber code
1 parent b82d3c4 commit eb2d9cf

File tree

1 file changed

+54
-56
lines changed

1 file changed

+54
-56
lines changed

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 54 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
589589
struct 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.
600598
struct 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.
608605
struct 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.
615612
struct 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

10721066
static 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

Comments
 (0)