78#define DEBUG_TYPE "rewrite-statepoints-for-gc"
98#ifdef EXPENSIVE_CHECKS
135 bool Changed =
false;
139 if (
F.isDeclaration() ||
F.empty())
168struct GCPtrLivenessData {
199using RematerializedValueMapTy =
202struct PartiallyConstructedSafepointRecord {
204 StatepointLiveSetTy LiveSet;
217 RematerializedValueMapTy RematerializedValues;
220struct RematerizlizationCandidateRecord {
233 std::optional<OperandBundleUse> DeoptBundle =
238 "Found non-leaf call without deopt info!");
242 return DeoptBundle->Inputs;
255 assert(GC &&
"GC Strategy for isGCPointerType cannot be null");
257 if (!isa<PointerType>(
T))
261 return GC->isGCManagedPointer(
T).value_or(
true);
274 if (
auto VT = dyn_cast<VectorType>(
T))
286 if (
VectorType *VT = dyn_cast<VectorType>(Ty))
288 if (
ArrayType *AT = dyn_cast<ArrayType>(Ty))
290 if (
StructType *ST = dyn_cast<StructType>(Ty))
292 [GC](
Type *Ty) { return containsGCPtrType(Ty, GC); });
308 return V->hasName() ? (V->getName() + Suffix).str() : DefaultName.
str();
317 PartiallyConstructedSafepointRecord &Result,
GCStrategy *GC) {
318 StatepointLiveSetTy LiveSet;
322 dbgs() <<
"Live Variables:\n";
323 for (
Value *V : LiveSet)
324 dbgs() <<
" " << V->getName() <<
" " << *V <<
"\n";
327 dbgs() <<
"Safepoint For: " << Call->getCalledOperand()->getName() <<
"\n";
328 dbgs() <<
"Number live values: " << LiveSet.size() <<
"\n";
330 Result.LiveSet = LiveSet;
339 IsKnownBaseMapTy &KnownBases);
342 IsKnownBaseMapTy &KnownBases);
354 IsKnownBaseMapTy &KnownBases) {
358 auto Cached = Cache.find(
I);
359 if (Cached != Cache.end())
360 return Cached->second;
362 if (isa<Argument>(
I)) {
369 if (isa<Constant>(
I)) {
378 if (isa<LoadInst>(
I)) {
384 if (isa<InsertElementInst>(
I)) {
393 if (isa<ShuffleVectorInst>(
I)) {
406 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(
I)) {
415 if (
auto *Freeze = dyn_cast<FreezeInst>(
I)) {
423 if (
auto *BC = dyn_cast<BitCastInst>(
I)) {
432 if (isa<CallInst>(
I) || isa<InvokeInst>(
I)) {
440 assert((isa<SelectInst>(
I) || isa<PHINode>(
I)) &&
441 "unknown vector instruction - no base found for vector element");
452 IsKnownBaseMapTy &KnownBases) {
453 assert(
I->getType()->isPtrOrPtrVectorTy() &&
454 "Illegal to ask for the base pointer of a non-pointer type");
455 auto Cached = Cache.find(
I);
456 if (Cached != Cache.end())
457 return Cached->second;
459 if (
I->getType()->isVectorTy())
462 if (isa<Argument>(
I)) {
470 if (isa<Constant>(
I)) {
492 if (isa<IntToPtrInst>(
I)) {
498 if (
CastInst *CI = dyn_cast<CastInst>(
I)) {
499 Value *Def = CI->stripPointerCasts();
502 assert(cast<PointerType>(Def->getType())->getAddressSpace() ==
503 cast<PointerType>(CI->getType())->getAddressSpace() &&
504 "unsupported addrspacecast");
508 assert(!isa<CastInst>(Def) &&
"shouldn't find another cast here");
514 if (isa<LoadInst>(
I)) {
529 if (
auto *Freeze = dyn_cast<FreezeInst>(
I)) {
536 switch (
II->getIntrinsicID()) {
540 case Intrinsic::experimental_gc_statepoint:
542 case Intrinsic::experimental_gc_relocate:
547 case Intrinsic::gcroot:
552 "interaction with the gcroot mechanism is not supported");
553 case Intrinsic::experimental_gc_get_pointer_base:
562 if (isa<CallInst>(
I) || isa<InvokeInst>(
I)) {
570 assert(!isa<LandingPadInst>(
I) &&
"Landing Pad is unimplemented");
572 if (isa<AtomicCmpXchgInst>(
I)) {
581 assert(!isa<AtomicRMWInst>(
I) &&
"Xchg handled above, all others are "
582 "binary ops which don't apply to pointers");
587 if (isa<ExtractValueInst>(
I)) {
595 assert(!isa<InsertValueInst>(
I) &&
596 "Base pointer for a struct is meaningless");
601 isa<Instruction>(
I) && cast<Instruction>(
I)->getMetadata(
"is_base_value");
609 if (isa<ExtractElementInst>(
I))
619 assert((isa<SelectInst>(
I) || isa<PHINode>(
I)) &&
620 "missing instruction case in findBaseDefiningValue");
626 IsKnownBaseMapTy &KnownBases) {
627 if (!Cache.contains(
I)) {
631 << Cache[
I]->getName() <<
", is known base = "
632 << KnownBases[
I] <<
"\n");
635 assert(KnownBases.contains(Cache[
I]) &&
636 "Cached value must be present in known bases map");
643 IsKnownBaseMapTy &KnownBases) {
645 auto Found = Cache.find(Def);
646 if (Found != Cache.end()) {
648 return Found->second;
659 return !isa<PHINode>(V) && !isa<SelectInst>(V) &&
660 !isa<ExtractElementInst>(V) && !isa<InsertElementInst>(V) &&
661 !isa<ShuffleVectorInst>(V);
666 auto It = KnownBases.find(V);
667 assert(It != KnownBases.end() &&
"Value not present in the map");
672 IsKnownBaseMapTy &KnownBases) {
674 auto It = KnownBases.find(V);
675 if (It != KnownBases.end())
676 assert(It->second == IsKnownBase &&
"Changing already present value");
678 KnownBases[V] = IsKnownBase;
683 return isa<VectorType>(
First->getType()) ==
684 isa<VectorType>(Second->
getType());
709 explicit BDVState(
Value *OriginalValue)
710 : OriginalValue(OriginalValue) {}
711 explicit BDVState(
Value *OriginalValue, StatusTy
Status,
Value *BaseValue =
nullptr)
712 : OriginalValue(OriginalValue),
Status(
Status), BaseValue(BaseValue) {
716 StatusTy getStatus()
const {
return Status; }
717 Value *getOriginalValue()
const {
return OriginalValue; }
718 Value *getBaseValue()
const {
return BaseValue; }
720 bool isBase()
const {
return getStatus() ==
Base; }
721 bool isUnknown()
const {
return getStatus() ==
Unknown; }
722 bool isConflict()
const {
return getStatus() == Conflict; }
727 void meet(
const BDVState &
Other) {
728 auto markConflict = [&]() {
729 Status = BDVState::Conflict;
738 BaseValue =
Other.getBaseValue();
742 assert(isBase() &&
"Unknown state");
744 if (
Other.isUnknown())
747 if (
Other.isConflict())
748 return markConflict();
752 if (getBaseValue() !=
Other.getBaseValue())
753 return markConflict();
758 return OriginalValue ==
Other.OriginalValue && BaseValue ==
Other.BaseValue &&
762 bool operator!=(
const BDVState &other)
const {
return !(*
this == other); }
771 switch (getStatus()) {
782 OS <<
" (base " << getBaseValue() <<
" - "
783 << (getBaseValue() ? getBaseValue()->getName() :
"nullptr") <<
")"
784 <<
" for " << OriginalValue->getName() <<
":";
807 IsKnownBaseMapTy &KnownBases) {
836 auto isExpectedBDVType = [](
Value *BDV) {
837 return isa<PHINode>(BDV) || isa<SelectInst>(BDV) ||
838 isa<ExtractElementInst>(BDV) || isa<InsertElementInst>(BDV) ||
839 isa<ShuffleVectorInst>(BDV);
851 auto VerifyStates = [&]() {
852 for (
auto &Entry : States) {
853 assert(Entry.first == Entry.second.getOriginalValue());
858 auto visitBDVOperands = [](
Value *BDV, std::function<void (
Value*)>
F) {
859 if (
PHINode *PN = dyn_cast<PHINode>(BDV)) {
860 for (
Value *InVal : PN->incoming_values())
862 }
else if (
SelectInst *SI = dyn_cast<SelectInst>(BDV)) {
863 F(SI->getTrueValue());
864 F(SI->getFalseValue());
865 }
else if (
auto *EE = dyn_cast<ExtractElementInst>(BDV)) {
866 F(EE->getVectorOperand());
867 }
else if (
auto *IE = dyn_cast<InsertElementInst>(BDV)) {
868 F(IE->getOperand(0));
869 F(IE->getOperand(1));
870 }
else if (
auto *SV = dyn_cast<ShuffleVectorInst>(BDV)) {
873 F(SV->getOperand(0));
874 if (!SV->isZeroEltSplat())
875 F(SV->getOperand(1));
887 States.
insert({Def, BDVState(Def)});
888 while (!Worklist.
empty()) {
892 auto visitIncomingValue = [&](
Value *InVal) {
901 assert(isExpectedBDVType(
Base) &&
"the only non-base values "
902 "we see should be base defining values");
907 visitBDVOperands(Current, visitIncomingValue);
914 for (
const auto &Pair : States) {
915 LLVM_DEBUG(
dbgs() <<
" " << Pair.second <<
" for " << *Pair.first <<
"\n");
927 for (
auto Pair : States) {
928 Value *BDV = Pair.first;
929 auto canPruneInput = [&](
Value *V) {
932 if (V->stripPointerCasts() == BDV)
935 if (V->stripPointerCasts() != VBDV)
939 return States.count(VBDV) == 0;
942 bool CanPrune =
true;
943 visitBDVOperands(BDV, [&](
Value *
Op) {
944 CanPrune = CanPrune && canPruneInput(
Op);
957 if (!States.
count(Def))
962 auto GetStateForBDV = [&](
Value *BaseValue,
Value *Input) {
963 auto I = States.
find(BaseValue);
964 if (
I != States.
end())
967 return BDVState(BaseValue, BDVState::Base, BaseValue);
990 if (isa<InsertElementInst>(
I) || isa<ExtractElementInst>(
I))
994 if (isa<ShuffleVectorInst>(
I))
1008 bool Progress =
true;
1011 const size_t OldSize = States.
size();
1018 for (
auto Pair : States) {
1019 Value *BDV = Pair.first;
1025 "why did it get added?");
1027 BDVState NewState(BDV);
1028 visitBDVOperands(BDV, [&](
Value *
Op) {
1030 auto OpState = GetStateForBDV(BDV,
Op);
1031 NewState.meet(OpState);
1037 auto I = cast<Instruction>(BDV);
1038 auto BV = NewState.getBaseValue();
1039 if (BV && MarkConflict(
I, BV))
1040 NewState = BDVState(
I, BDVState::Conflict);
1042 BDVState OldState = Pair.second;
1043 if (OldState != NewState) {
1045 States[BDV] = NewState;
1049 assert(OldSize == States.size() &&
1050 "fixed point shouldn't be adding any new nodes to state");
1056 for (
const auto &Pair : States) {
1057 LLVM_DEBUG(
dbgs() <<
" " << Pair.second <<
" for " << *Pair.first <<
"\n");
1062 for (
auto Pair : States) {
1064 BDVState State = Pair.second;
1065 auto *BaseValue = State.getBaseValue();
1071 "why did it get added?");
1072 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1078 for (
auto Pair : States) {
1080 BDVState State = Pair.second;
1086 "why did it get added?");
1087 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1092 assert(!isa<InsertElementInst>(
I) || State.isConflict());
1094 if (!State.isConflict())
1097 auto getMangledName = [](
Instruction *
I) -> std::string {
1098 if (isa<PHINode>(
I)) {
1100 }
else if (isa<SelectInst>(
I)) {
1102 }
else if (isa<ExtractElementInst>(
I)) {
1104 }
else if (isa<InsertElementInst>(
I)) {
1113 BaseInst->
setName(getMangledName(
I));
1116 States[
I] = BDVState(
I, BDVState::Conflict, BaseInst);
1135 if (!States.
count(BDV)) {
1141 Base = States[BDV].getBaseValue();
1145 if (
Base->getType() != Input->
getType() && InsertPt)
1147 InsertPt->getIterator());
1154 for (
auto Pair : States) {
1156 BDVState State = Pair.second;
1163 "why did it get added?");
1164 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1165 if (!State.isConflict())
1168 if (
PHINode *BasePHI = dyn_cast<PHINode>(State.getBaseValue())) {
1169 PHINode *PN = cast<PHINode>(BDV);
1177 for (
unsigned i = 0; i < NumPHIValues; i++) {
1180 if (!BlockToValue.
count(InBB))
1181 BlockToValue[InBB] = getBaseForInput(InVal, InBB->
getTerminator());
1184 Value *OldBase = BlockToValue[InBB];
1185 Value *
Base = getBaseForInput(InVal,
nullptr);
1189 auto StripBitCasts = [](
Value *V) ->
Value * {
1190 while (
auto *BC = dyn_cast<BitCastInst>(V))
1191 V = BC->getOperand(0);
1200 assert(StripBitCasts(
Base) == StripBitCasts(OldBase) &&
1201 "findBaseOrBDV should be pure!");
1205 BasePHI->setIncomingValue(i,
Base);
1208 dyn_cast<SelectInst>(State.getBaseValue())) {
1213 BaseSI->setTrueValue(getBaseForInput(SI->getTrueValue(), BaseSI));
1214 BaseSI->setFalseValue(getBaseForInput(SI->getFalseValue(), BaseSI));
1215 }
else if (
auto *BaseEE =
1216 dyn_cast<ExtractElementInst>(State.getBaseValue())) {
1217 Value *InVal = cast<ExtractElementInst>(BDV)->getVectorOperand();
1220 BaseEE->setOperand(0, getBaseForInput(InVal, BaseEE));
1221 }
else if (
auto *BaseIE = dyn_cast<InsertElementInst>(State.getBaseValue())){
1222 auto *BdvIE = cast<InsertElementInst>(BDV);
1223 auto UpdateOperand = [&](
int OperandIdx) {
1224 Value *InVal = BdvIE->getOperand(OperandIdx);
1225 Value *
Base = getBaseForInput(InVal, BaseIE);
1226 BaseIE->setOperand(OperandIdx,
Base);
1231 auto *BaseSV = cast<ShuffleVectorInst>(State.getBaseValue());
1232 auto *BdvSV = cast<ShuffleVectorInst>(BDV);
1233 auto UpdateOperand = [&](
int OperandIdx) {
1234 Value *InVal = BdvSV->getOperand(OperandIdx);
1235 Value *
Base = getBaseForInput(InVal, BaseSV);
1236 BaseSV->setOperand(OperandIdx,
Base);
1239 if (!BdvSV->isZeroEltSplat())
1243 Value *InVal = BdvSV->getOperand(1);
1254 [[maybe_unused]]
auto &
DL =
1255 cast<llvm::Instruction>(Def)->getDataLayout();
1259 for (
auto Pair : States) {
1260 auto *BDV = Pair.first;
1261 Value *
Base = Pair.second.getBaseValue();
1266 DL.getTypeAllocSize(
Base->getType()) &&
1267 "Derived and base values should have same size");
1273 "why did it get added?");
1276 dbgs() <<
"Updating base value cache"
1277 <<
" for: " << BDV->
getName() <<
" from: "
1278 << (Cache.count(BDV) ? Cache[BDV]->getName().str() :
"none")
1279 <<
" to: " <<
Base->getName() <<
"\n");
1283 assert(Cache.count(Def));
1304 DefiningValueMapTy &DVCache,
1305 IsKnownBaseMapTy &KnownBases) {
1308 assert(base &&
"failed to find base pointer");
1309 PointerToBase[ptr] = base;
1310 assert((!isa<Instruction>(base) || !isa<Instruction>(ptr) ||
1311 DT->
dominates(cast<Instruction>(base)->getParent(),
1312 cast<Instruction>(ptr)->getParent())) &&
1313 "The base we found better dominate the derived pointer");
1321 PartiallyConstructedSafepointRecord &result,
1322 PointerToBaseTy &PointerToBase,
1323 IsKnownBaseMapTy &KnownBases) {
1324 StatepointLiveSetTy PotentiallyDerivedPointers = result.LiveSet;
1331 for (
Value *V : Opt->Inputs) {
1332 if (!PotentiallyDerivedPointers.count(V))
1334 PotentiallyDerivedPointers.remove(V);
1335 PointerToBase[V] = V;
1345 PartiallyConstructedSafepointRecord &result,
1346 PointerToBaseTy &PointerToBase,
1352 PointerToBaseTy &PointerToBase,
GCStrategy *GC) {
1355 GCPtrLivenessData RevisedLivenessData;
1357 for (
size_t i = 0; i < records.
size(); i++) {
1358 struct PartiallyConstructedSafepointRecord &
info = records[i];
1370 Value *AlternateLiveBase) {
1380 assert(isa<GetElementPtrInst>(Instr) || isa<CastInst>(Instr));
1384 ClonedValue->
setName(Instr->getName() +
".remat");
1388 if (LastClonedValue) {
1396 "incorrect use in rematerialization chain");
1399 assert(OpValue != RootOfChain && OpValue != AlternateLiveBase);
1408 if (RootOfChain != AlternateLiveBase)
1412 LastClonedValue = ClonedValue;
1416 return LastClonedValue;
1435 assert(!isa<PHINode>(Ret->begin()) &&
1436 "All PHI nodes should have been removed!");
1449 {Attribute::Memory, Attribute::NoSync, Attribute::NoFree};
1457 return StatepointAL;
1476 return StatepointAL;
1481 for (
unsigned I :
llvm::seq(Call->arg_size()))
1487 return StatepointAL;
1507 assert(ValIt != LiveVec.
end() &&
"Val not found in LiveVec!");
1508 size_t Index = std::distance(LiveVec.
begin(), ValIt);
1521 auto getGCRelocateDecl = [&](
Type *Ty) {
1523 auto AS = Ty->getScalarType()->getPointerAddressSpace();
1525 if (
auto *VT = dyn_cast<VectorType>(Ty))
1543 if (!TypeToDeclMap.
count(Ty))
1544 TypeToDeclMap[Ty] = getGCRelocateDecl(Ty);
1545 Function *GCRelocateDecl = TypeToDeclMap[Ty];
1549 GCRelocateDecl, {StatepointToken, BaseIdx, LiveIdx},
1561class DeferredReplacement {
1564 bool IsDeoptimize =
false;
1566 DeferredReplacement() =
default;
1570 assert(Old != New && Old && New &&
1571 "Cannot RAUW equal values or to / from null!");
1573 DeferredReplacement
D;
1579 static DeferredReplacement createDelete(
Instruction *ToErase) {
1580 DeferredReplacement
D;
1585 static DeferredReplacement createDeoptimizeReplacement(
Instruction *Old) {
1587 auto *
F = cast<CallInst>(Old)->getCalledFunction();
1588 assert(
F &&
F->getIntrinsicID() == Intrinsic::experimental_deoptimize &&
1589 "Only way to construct a deoptimize deferred replacement");
1591 DeferredReplacement
D;
1593 D.IsDeoptimize =
true;
1598 void doReplacement() {
1602 assert(OldI != NewI &&
"Disallowed at construction?!");
1603 assert((!IsDeoptimize || !New) &&
1604 "Deoptimize intrinsics are not replaced!");
1615 auto *RI = cast<ReturnInst>(OldI->
getParent()->getTerminator());
1617 RI->eraseFromParent();
1627 const char *DeoptLowering =
"deopt-lowering";
1628 if (Call->hasFnAttr(DeoptLowering)) {
1634 Function *
F = Call->getCalledFunction();
1635 assert(
F &&
F->hasFnAttribute(DeoptLowering));
1636 return F->getFnAttribute(DeoptLowering).getValueAsString();
1638 return "live-through";
1645 PartiallyConstructedSafepointRecord &Result,
1646 std::vector<DeferredReplacement> &Replacements,
1647 const PointerToBaseTy &PointerToBase,
1663 std::optional<ArrayRef<Use>> DeoptArgs;
1665 DeoptArgs = Bundle->Inputs;
1666 std::optional<ArrayRef<Use>> TransitionArgs;
1668 TransitionArgs = Bundle->Inputs;
1676 bool IsDeoptimize =
false;
1677 bool IsMemIntrinsic =
false;
1688 if (DeoptLowering ==
"live-in")
1691 assert(DeoptLowering ==
"live-through" &&
"Unsupported value!");
1694 FunctionCallee CallTarget(Call->getFunctionType(), Call->getCalledOperand());
1696 auto IID =
F->getIntrinsicID();
1697 if (IID == Intrinsic::experimental_deoptimize) {
1703 for (
Value *Arg : CallArgs)
1712 CallTarget =
F->getParent()
1713 ->getOrInsertFunction(
"__llvm_deoptimize", FTy);
1715 IsDeoptimize =
true;
1716 }
else if (IID == Intrinsic::memcpy_element_unordered_atomic ||
1717 IID == Intrinsic::memmove_element_unordered_atomic) {
1718 IsMemIntrinsic =
true;
1736 auto &Context = Call->getContext();
1737 auto &
DL = Call->getDataLayout();
1738 auto GetBaseAndOffset = [&](
Value *Derived) {
1744 if (isa<Constant>(Derived))
1748 assert(PointerToBase.count(Derived));
1749 Base = PointerToBase.find(Derived)->second;
1751 unsigned AddressSpace = Derived->getType()->getPointerAddressSpace();
1757 return std::make_pair(
Base, Builder.
CreateSub(Derived_int, Base_int));
1760 auto *Dest = CallArgs[0];
1761 Value *DestBase, *DestOffset;
1762 std::tie(DestBase, DestOffset) = GetBaseAndOffset(Dest);
1764 auto *Source = CallArgs[1];
1765 Value *SourceBase, *SourceOffset;
1766 std::tie(SourceBase, SourceOffset) = GetBaseAndOffset(Source);
1768 auto *LengthInBytes = CallArgs[2];
1769 auto *ElementSizeCI = cast<ConstantInt>(CallArgs[3]);
1779 for (
Value *Arg : CallArgs)
1785 uint64_t ElementSize = ElementSizeCI->getZExtValue();
1786 if (IID == Intrinsic::memcpy_element_unordered_atomic) {
1787 switch (ElementSize) {
1789 return "__llvm_memcpy_element_unordered_atomic_safepoint_1";
1791 return "__llvm_memcpy_element_unordered_atomic_safepoint_2";
1793 return "__llvm_memcpy_element_unordered_atomic_safepoint_4";
1795 return "__llvm_memcpy_element_unordered_atomic_safepoint_8";
1797 return "__llvm_memcpy_element_unordered_atomic_safepoint_16";
1802 assert(IID == Intrinsic::memmove_element_unordered_atomic);
1803 switch (ElementSize) {
1805 return "__llvm_memmove_element_unordered_atomic_safepoint_1";
1807 return "__llvm_memmove_element_unordered_atomic_safepoint_2";
1809 return "__llvm_memmove_element_unordered_atomic_safepoint_4";
1811 return "__llvm_memmove_element_unordered_atomic_safepoint_8";
1813 return "__llvm_memmove_element_unordered_atomic_safepoint_16";
1821 ->getOrInsertFunction(GetFunctionName(IID, ElementSizeCI), FTy);
1827 if (
auto *CI = dyn_cast<CallInst>(Call)) {
1829 StatepointID, NumPatchBytes, CallTarget, Flags, CallArgs,
1830 TransitionArgs, DeoptArgs, GCArgs,
"safepoint_token");
1840 Token = cast<GCStatepointInst>(SPCall);
1844 assert(CI->getNextNode() &&
"Not a terminator, must have next!");
1848 auto *
II = cast<InvokeInst>(Call);
1854 StatepointID, NumPatchBytes, CallTarget,
II->getNormalDest(),
1855 II->getUnwindDest(), Flags, CallArgs, TransitionArgs, DeoptArgs, GCArgs,
1856 "statepoint_token");
1865 Token = cast<GCStatepointInst>(SPInvoke);
1871 "can't safely insert in this block!");
1878 Result.UnwindToken = ExceptionalToken;
1886 "can't safely insert in this block!");
1893 assert(Token &&
"Should be set in one of the above branches!");
1899 Replacements.push_back(
1900 DeferredReplacement::createDeoptimizeReplacement(Call));
1902 Token->
setName(
"statepoint_token");
1903 if (!Call->getType()->isVoidTy() && !Call->use_empty()) {
1908 Call->getAttributes().getRetAttrs()));
1916 Replacements.emplace_back(
1917 DeferredReplacement::createRAUW(Call, GCResult));
1919 Replacements.emplace_back(DeferredReplacement::createDelete(Call));
1923 Result.StatepointToken = Token;
1936 PartiallyConstructedSafepointRecord &Result,
1937 std::vector<DeferredReplacement> &Replacements,
1938 const PointerToBaseTy &PointerToBase,
GCStrategy *GC) {
1939 const auto &LiveSet = Result.LiveSet;
1943 LiveVec.
reserve(LiveSet.size());
1944 BaseVec.
reserve(LiveSet.size());
1945 for (
Value *L : LiveSet) {
1947 assert(PointerToBase.count(L));
1948 Value *
Base = PointerToBase.find(L)->second;
1968 for (
User *U : GCRelocs) {
1975 Value *Alloca = AllocaMap[OriginalValue];
1979 "Should always have one since it's not a terminator");
1983 VisitedLiveValues.
insert(OriginalValue);
1991 const RematerializedValueMapTy &RematerializedValues,
1994 for (
auto RematerializedValuePair: RematerializedValues) {
1995 Instruction *RematerializedValue = RematerializedValuePair.first;
1996 Value *OriginalValue = RematerializedValuePair.second;
1999 "Can not find alloca for rematerialized value");
2000 Value *Alloca = AllocaMap[OriginalValue];
2002 new StoreInst(RematerializedValue, Alloca,
2006 VisitedLiveValues.
insert(OriginalValue);
2018 int InitialAllocaNum = 0;
2020 if (isa<AllocaInst>(
I))
2028 std::size_t NumRematerializedValues = 0;
2034 auto emitAllocaFor = [&](
Value *LiveValue) {
2036 new AllocaInst(LiveValue->getType(),
DL.getAllocaAddrSpace(),
"",
2037 F.getEntryBlock().getFirstNonPHIIt());
2038 AllocaMap[LiveValue] = Alloca;
2047 for (
const auto &
Info : Records)
2048 for (
auto RematerializedValuePair :
Info.RematerializedValues) {
2049 Value *OriginalValue = RematerializedValuePair.second;
2050 if (AllocaMap.
contains(OriginalValue))
2053 emitAllocaFor(OriginalValue);
2054 ++NumRematerializedValues;
2066 for (
const auto &
Info : Records) {
2067 Value *Statepoint =
Info.StatepointToken;
2077 if (isa<InvokeInst>(Statepoint)) {
2093 for (
auto Pair : AllocaMap) {
2094 Value *Def = Pair.first;
2098 if (VisitedLiveValues.
count(Def)) {
2105 for (
auto *AI : ToClobber) {
2106 auto AT = AI->getAllocatedType();
2108 if (AT->isVectorTy())
2118 if (
auto II = dyn_cast<InvokeInst>(Statepoint)) {
2119 InsertClobbersAt(
II->getNormalDest()->getFirstInsertionPt());
2120 InsertClobbersAt(
II->getUnwindDest()->getFirstInsertionPt());
2123 std::next(cast<Instruction>(Statepoint)->getIterator()));
2129 for (
auto Pair : AllocaMap) {
2130 Value *Def = Pair.first;
2138 Uses.reserve(Def->getNumUses());
2139 for (
User *U : Def->users()) {
2140 if (!isa<ConstantExpr>(U)) {
2146 Uses.push_back(cast<Instruction>(U));
2155 if (isa<PHINode>(
Use)) {
2157 for (
unsigned i = 0; i < Phi->getNumIncomingValues(); i++) {
2158 if (Def == Phi->getIncomingValue(i)) {
2161 Phi->getIncomingBlock(i)->getTerminator()->getIterator());
2162 Phi->setIncomingValue(i, Load);
2167 Use->getIterator());
2168 Use->replaceUsesOfWith(Def, Load);
2176 DL.getABITypeAlign(Def->getType()));
2177 if (
Instruction *Inst = dyn_cast<Instruction>(Def)) {
2178 if (
InvokeInst *Invoke = dyn_cast<InvokeInst>(Inst)) {
2181 BasicBlock *NormalDest = Invoke->getNormalDest();
2184 assert(!Inst->isTerminator() &&
2185 "The only terminator that can produce a value is "
2186 "InvokeInst which is handled above.");
2187 Store->insertAfter(Inst);
2190 assert(isa<Argument>(Def));
2191 Store->insertAfter(cast<Instruction>(Alloca));
2195 assert(PromotableAllocas.
size() ==
Live.size() + NumRematerializedValues &&
2196 "we must have the same allocas with lives");
2197 (void) NumRematerializedValues;
2198 if (!PromotableAllocas.
empty()) {
2204 for (
auto &
I :
F.getEntryBlock())
2205 if (isa<AllocaInst>(
I))
2207 assert(InitialAllocaNum == 0 &&
"We must not introduce any extra allocas");
2227 Module *M = Call->getModule();
2231 if (isa<CallInst>(Call)) {
2239 auto *
II = cast<InvokeInst>(Call);
2241 Func, Values,
"",
II->getNormalDest()->getFirstInsertionPt()));
2243 Func, Values,
"",
II->getUnwindDest()->getFirstInsertionPt()));
2250 GCPtrLivenessData OriginalLivenessData;
2252 for (
size_t i = 0; i < records.
size(); i++) {
2253 struct PartiallyConstructedSafepointRecord &
info = records[i];
2266 Value *CurrentValue) {
2270 GEP->getPointerOperand());
2273 if (
CastInst *CI = dyn_cast<CastInst>(CurrentValue)) {
2274 if (!CI->isNoopCast(CI->getDataLayout()))
2284 return CurrentValue;
2295 if (
CastInst *CI = dyn_cast<CastInst>(Instr)) {
2296 assert(CI->isNoopCast(CI->getDataLayout()) &&
2297 "non noop cast is found during rematerialization");
2299 Type *SrcTy = CI->getOperand(0)->getType();
2306 Type *ValTy =
GEP->getSourceElementType();
2312 if (!
GEP->hasAllConstantIndices())
2331 for (
unsigned i = 0; i < PhiNum; i++)
2337 for (
unsigned i = 0; i < PhiNum; i++) {
2340 if (CIVI == CurrentIncomingValues.
end())
2342 BasicBlock *CurrentIncomingBB = CIVI->second;
2353 RematCandTy &RematerizationCandidates,
2355 const unsigned int ChainLengthThreshold = 10;
2357 for (
auto P2B : PointerToBase) {
2358 auto *Derived = P2B.first;
2359 auto *
Base = P2B.second;
2361 if (Derived ==
Base)
2366 Value *RootOfChain =
2370 if ( ChainToBase.
size() == 0 ||
2371 ChainToBase.
size() > ChainLengthThreshold)
2376 if (RootOfChain != PointerToBase[Derived]) {
2377 PHINode *OrigRootPhi = dyn_cast<PHINode>(RootOfChain);
2378 PHINode *AlternateRootPhi = dyn_cast<PHINode>(PointerToBase[Derived]);
2379 if (!OrigRootPhi || !AlternateRootPhi)
2401 RematerizlizationCandidateRecord
Record;
2402 Record.ChainToBase = ChainToBase;
2403 Record.RootOfChain = RootOfChain;
2405 RematerizationCandidates.insert({ Derived,
Record });
2414 RematCandTy &RematerizationCandidates,
2416 PointerToBaseTy &PointerToBase) {
2423 <<
"Num statepoints: " << Records.size() <<
'\n');
2425 for (
auto &It : RematerizationCandidates) {
2427 auto &
Record = It.second;
2437 if (U->getParent() == Cand->
getParent())
2442 [](
const auto *U) { return isa<PHINode>(U); }))
2454 Records, [Cand](
const auto &R) {
return R.LiveSet.contains(Cand); });
2457 LLVM_DEBUG(
dbgs() <<
"Num uses: " << NumUses <<
" Num live statepoints: "
2458 << NumLiveStatepoints <<
" ");
2460 if (NumLiveStatepoints < NumUses) {
2468 if (NumLiveStatepoints == NumUses &&
Record.Cost > 0) {
2480 if (
Record.ChainToBase.size() > 1) {
2481 Record.ChainToBase.clear();
2497 Record.ChainToBase, UserI,
Record.RootOfChain, PointerToBase[Cand]);
2499 PointerToBase[RematChain] = PointerToBase[Cand];
2505 <<
" derived pointers\n");
2506 for (
auto *Cand : LiveValuesToBeDeleted) {
2507 assert(Cand->use_empty() &&
"Unexpected user remain");
2508 RematerizationCandidates.erase(Cand);
2509 for (
auto &R : Records) {
2510 assert(!R.LiveSet.contains(Cand) ||
2511 R.LiveSet.contains(PointerToBase[Cand]));
2512 R.LiveSet.remove(Cand);
2518 if (!LiveValuesToBeDeleted.
empty()) {
2519 for (
auto &
P : RematerizationCandidates) {
2521 if (R.ChainToBase.size() > 1) {
2522 R.ChainToBase.clear();
2534 PartiallyConstructedSafepointRecord &
Info,
2535 PointerToBaseTy &PointerToBase,
2536 RematCandTy &RematerizationCandidates,
2543 auto It = RematerizationCandidates.find(LiveValue);
2544 if (It == RematerizationCandidates.end())
2547 RematerizlizationCandidateRecord &
Record = It->second;
2552 if (isa<InvokeInst>(Call))
2560 LiveValuesToBeDeleted.
push_back(LiveValue);
2566 if (isa<CallInst>(Call)) {
2571 Record.RootOfChain, PointerToBase[LiveValue]);
2572 Info.RematerializedValues[RematerializedValue] = LiveValue;
2574 auto *Invoke = cast<InvokeInst>(Call);
2577 &*Invoke->getNormalDest()->getFirstInsertionPt();
2579 &*Invoke->getUnwindDest()->getFirstInsertionPt();
2583 Record.RootOfChain, PointerToBase[LiveValue]);
2586 Record.RootOfChain, PointerToBase[LiveValue]);
2588 Info.RematerializedValues[NormalRematerializedValue] = LiveValue;
2589 Info.RematerializedValues[UnwindRematerializedValue] = LiveValue;
2594 for (
auto *LiveValue: LiveValuesToBeDeleted) {
2595 Info.LiveSet.remove(LiveValue);
2601 DefiningValueMapTy &DVCache,
2602 IsKnownBaseMapTy &KnownBases) {
2603 auto &Context =
F.getContext();
2604 auto &
DL =
F.getDataLayout();
2605 bool Changed =
false;
2607 for (
auto *Callsite : Intrinsics)
2608 switch (Callsite->getIntrinsicID()) {
2609 case Intrinsic::experimental_gc_get_pointer_base: {
2613 assert(!DVCache.count(Callsite));
2614 Callsite->replaceAllUsesWith(
Base);
2615 if (!
Base->hasName())
2616 Base->takeName(Callsite);
2617 Callsite->eraseFromParent();
2620 case Intrinsic::experimental_gc_get_pointer_offset: {
2622 Value *Derived = Callsite->getOperand(0);
2624 assert(!DVCache.count(Callsite));
2636 Offset->takeName(Callsite);
2637 Callsite->eraseFromParent();
2650 DefiningValueMapTy &DVCache,
2651 IsKnownBaseMapTy &KnownBases) {
2656 std::set<CallBase *> Uniqued;
2657 Uniqued.insert(ToUpdate.
begin(), ToUpdate.
end());
2658 assert(Uniqued.size() == ToUpdate.
size() &&
"no duplicates please!");
2661 assert(Call->getFunction() == &
F);
2669 auto *
II = dyn_cast<InvokeInst>(Call);
2689 "support for FCA unimplemented");
2704 PointerToBaseTy PointerToBase;
2707 for (
size_t i = 0; i < Records.size(); i++) {
2708 PartiallyConstructedSafepointRecord &
info = Records[i];
2712 errs() <<
"Base Pairs (w/o Relocation):\n";
2713 for (
auto &Pair : PointerToBase) {
2714 errs() <<
" derived ";
2715 Pair.first->printAsOperand(
errs(),
false);
2717 Pair.second->printAsOperand(
errs(),
false);
2737 for (
size_t i = 0; i < Records.size(); i++) {
2738 PartiallyConstructedSafepointRecord &
Info = Records[i];
2741 for (
auto *Derived :
Info.LiveSet) {
2742 assert(PointerToBase.count(Derived) &&
"Missed base for derived pointer");
2743 Bases.
push_back(PointerToBase[Derived]);
2755 errs() <<
"Base Pairs: (w/Relocation)\n";
2756 for (
auto Pair : PointerToBase) {
2757 errs() <<
" derived ";
2758 Pair.first->printAsOperand(
errs(),
false);
2760 Pair.second->printAsOperand(
errs(),
false);
2773 for (
auto &
Info : Records) {
2774 Info.LiveSet.remove_if([&](
Value *LiveV) {
2775 assert(PointerToBase.count(LiveV) &&
"Missed base for derived pointer");
2776 return isa<Constant>(PointerToBase[LiveV]);
2781 CI->eraseFromParent();
2786 RematCandTy RematerizationCandidates;
2795 for (
size_t i = 0; i < Records.size(); i++)
2797 RematerizationCandidates,
TTI);
2802 std::vector<DeferredReplacement> Replacements;
2810 for (
size_t i = 0; i < Records.size(); i++)
2812 PointerToBase, GC.get());
2816 for (
auto &PR : Replacements)
2819 Replacements.clear();
2821 for (
auto &
Info : Records) {
2830 Info.LiveSet.clear();
2832 PointerToBase.clear();
2836 for (
const PartiallyConstructedSafepointRecord &
Info : Records) {
2849 "statepoint must be reachable or liveness is meaningless");
2850 for (
Value *V :
Info.StatepointToken->gc_args()) {
2851 if (!isa<Instruction>(V))
2854 auto *LiveInst = cast<Instruction>(V);
2856 "unreachable values should never be live");
2858 "basic SSA liveness expectation violated by liveness analysis");
2868 "must be a gc pointer type");
2872 return !Records.empty();
2880 R.addAttribute(Attribute::Dereferenceable);
2881 R.addAttribute(Attribute::DereferenceableOrNull);
2882 R.addAttribute(Attribute::ReadNone);
2883 R.addAttribute(Attribute::ReadOnly);
2884 R.addAttribute(Attribute::WriteOnly);
2885 R.addAttribute(Attribute::NoAlias);
2886 R.addAttribute(Attribute::NoFree);
2905 if (isa<PointerType>(
A.getType()))
2906 F.removeParamAttrs(
A.getArgNo(), R);
2908 if (isa<PointerType>(
F.getReturnType()))
2909 F.removeRetAttrs(R);
2912 F.removeFnAttr(Attr);
2919 if (!isa<LoadInst>(
I) && !isa<StoreInst>(
I))
2934 unsigned ValidMetadataAfterRS4GC[] = {LLVMContext::MD_tbaa,
2935 LLVMContext::MD_range,
2936 LLVMContext::MD_alias_scope,
2937 LLVMContext::MD_nontemporal,
2938 LLVMContext::MD_nonnull,
2939 LLVMContext::MD_align,
2940 LLVMContext::MD_type};
2943 I.dropUnknownNonDebugMetadata(ValidMetadataAfterRS4GC);
2964 if (
auto *
II = dyn_cast<IntrinsicInst>(&
I))
2965 if (
II->getIntrinsicID() == Intrinsic::invariant_start) {
2970 if (
MDNode *
Tag =
I.getMetadata(LLVMContext::MD_tbaa)) {
2972 I.setMetadata(LLVMContext::MD_tbaa, MutableTBAA);
2978 if (
auto *Call = dyn_cast<CallBase>(&
I)) {
2979 for (
int i = 0, e = Call->arg_size(); i != e; i++)
2980 if (isa<PointerType>(Call->getArgOperand(i)->getType()))
2981 Call->removeParamAttrs(i, R);
2982 if (isa<PointerType>(Call->getType()))
2983 Call->removeRetAttrs(R);
2988 for (
auto *
II : InvariantStartInstructions) {
2990 II->eraseFromParent();
3011 assert(Strategy &&
"GC strategy is required by function, but was not found");
3013 return Strategy->useRS4GC();
3031 assert(!
F.isDeclaration() && !
F.empty() &&
3032 "need function body to rewrite statepoints in");
3036 if (
const auto *Call = dyn_cast<CallBase>(&
I)) {
3037 if (isa<GCStatepointInst>(Call))
3050 assert((isa<AtomicMemCpyInst>(Call) || isa<AtomicMemMoveInst>(Call)) &&
3051 "Don't expect any other calls here!");
3074 if (NeedsRewrite(
I)) {
3080 "no unreachable blocks expected");
3081 ParsePointNeeded.
push_back(cast<CallBase>(&
I));
3083 if (
auto *CI = dyn_cast<CallInst>(&
I))
3084 if (CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_base ||
3085 CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_offset)
3090 if (ParsePointNeeded.
empty() && Intrinsics.
empty())
3098 if (BB.getUniquePredecessor())
3115 if (
auto *BI = dyn_cast<BranchInst>(TI))
3116 if (BI->isConditional())
3117 return dyn_cast<Instruction>(BI->getCondition());
3123 if (
auto *
Cond = getConditionInst(TI))
3126 if (isa<ICmpInst>(
Cond) &&
Cond->hasOneUse()) {
3128 Cond->moveBefore(TI);
3138 if (!isa<GetElementPtrInst>(
I))
3142 for (
unsigned i = 0; i <
I.getNumOperands(); i++)
3143 if (
auto *OpndVTy = dyn_cast<VectorType>(
I.getOperand(i)->getType())) {
3146 VF = cast<FixedVectorType>(OpndVTy)->getNumElements();
3151 if (!
I.getOperand(0)->getType()->isVectorTy() && VF != 0) {
3153 auto *
Splat =
B.CreateVectorSplat(VF,
I.getOperand(0));
3163 DefiningValueMapTy DVCache;
3167 IsKnownBaseMapTy KnownBases;
3169 if (!Intrinsics.
empty())
3174 if (!ParsePointNeeded.
empty())
3198 if (isa<PHINode>(
I))
3202 for (
Value *V :
I.operands()) {
3204 "support for FCA unimplemented");
3225 for (
auto &
I : *Succ) {
3226 PHINode *PN = dyn_cast<PHINode>(&
I);
3232 "support for FCA unimplemented");
3253 if (
auto *
I = dyn_cast<Instruction>(V)) {
3257 if (TermOkay && TI ==
I)
3260 "basic SSA liveness expectation violated by liveness analysis");
3283 Data.LiveSet[&BB].clear();
3288 assert(!
Data.LiveSet[&BB].count(Kill) &&
"live set contains kill");
3293 Data.LiveIn[&BB] =
Data.LiveSet[&BB];
3294 Data.LiveIn[&BB].set_union(
Data.LiveOut[&BB]);
3295 Data.LiveIn[&BB].set_subtract(
Data.KillSet[&BB]);
3296 if (!
Data.LiveIn[&BB].empty())
3301 while (!Worklist.
empty()) {
3307 const auto OldLiveOutSize = LiveOut.
size();
3313 if (OldLiveOutSize == LiveOut.
size()) {
3319 Data.LiveOut[BB] = LiveOut;
3329 if (OldLiveIn.
size() != LiveTmp.
size()) {
3330 Data.LiveIn[BB] = LiveTmp;
3358 Out.insert(LiveOut.
begin(), LiveOut.
end());
3363 PartiallyConstructedSafepointRecord &
Info,
3364 PointerToBaseTy &PointerToBase,
3366 StatepointLiveSetTy Updated;
3371 for (
auto *V : Updated)
3372 PointerToBase.insert({ V, V });
3374 Info.LiveSet = Updated;
ReachingDefAnalysis InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
Expand Atomic instructions
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
Analysis containing CSE Info
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Checks Use for liveness in LiveValues If Use is not live
Looks at all the uses of the given value Returns the Liveness deduced from the uses of this value Adds all uses that cause the result to be MaybeLive to MaybeLiveRetUses If the result is Live
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
std::optional< std::vector< StOtherPiece > > Other
Rewrite Partial Register Uses
This file implements a map that provides insertion order iteration.
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
const SmallVectorImpl< MachineOperand > & Cond
static void makeStatepointExplicitImpl(CallBase *Call, const SmallVectorImpl< Value * > &BasePtrs, const SmallVectorImpl< Value * > &LiveVariables, PartiallyConstructedSafepointRecord &Result, std::vector< DeferredReplacement > &Replacements, const PointerToBaseTy &PointerToBase, GCStrategy *GC)
static void rematerializeLiveValues(CallBase *Call, PartiallyConstructedSafepointRecord &Info, PointerToBaseTy &PointerToBase, RematCandTy &RematerizationCandidates, TargetTransformInfo &TTI)
static void findRematerializationCandidates(PointerToBaseTy PointerToBase, RematCandTy &RematerizationCandidates, TargetTransformInfo &TTI)
static std::unique_ptr< GCStrategy > findGCStrategy(Function &F)
Looks up the GC strategy for a given function, returning null if the function doesn't have a GC tag.
static Instruction * rematerializeChain(ArrayRef< Instruction * > ChainToBase, Instruction *InsertBefore, Value *RootOfChain, Value *AlternateLiveBase)
static void unique_unsorted(SmallVectorImpl< T > &Vec)
Implement a unique function which doesn't require we sort the input vector.
static void stripNonValidDataFromBody(Function &F)
static bool isKnownBase(Value *V, const IsKnownBaseMapTy &KnownBases)
Returns true if V is a known base.
static Value * findBasePointer(Value *I, DefiningValueMapTy &Cache, IsKnownBaseMapTy &KnownBases)
For a given value or instruction, figure out what base ptr its derived from.
static cl::opt< bool, true > ClobberNonLiveOverride("rs4gc-clobber-non-live", cl::location(ClobberNonLive), cl::Hidden)
static void insertRelocationStores(iterator_range< Value::user_iterator > GCRelocs, DenseMap< Value *, AllocaInst * > &AllocaMap, DenseSet< Value * > &VisitedLiveValues)
static BasicBlock * normalizeForInvokeSafepoint(BasicBlock *BB, BasicBlock *InvokeParent, DominatorTree &DT)
static void analyzeParsePointLiveness(DominatorTree &DT, GCPtrLivenessData &OriginalLivenessData, CallBase *Call, PartiallyConstructedSafepointRecord &Result, GCStrategy *GC)
static void computeLiveOutSeed(BasicBlock *BB, SetVector< Value * > &LiveTmp, GCStrategy *GC)
static void relocationViaAlloca(Function &F, DominatorTree &DT, ArrayRef< Value * > Live, ArrayRef< PartiallyConstructedSafepointRecord > Records)
Do all the relocation update via allocas and mem2reg.
static bool AreEquivalentPhiNodes(PHINode &OrigRootPhi, PHINode &AlternateRootPhi)
static cl::opt< unsigned > RematerializationThreshold("spp-rematerialization-threshold", cl::Hidden, cl::init(6))
static Value * findBaseOrBDV(Value *I, DefiningValueMapTy &Cache, IsKnownBaseMapTy &KnownBases)
Return a base pointer for this value if known.
static Value * findBaseDefiningValueCached(Value *I, DefiningValueMapTy &Cache, IsKnownBaseMapTy &KnownBases)
Returns the base defining value for this value.
static void insertUseHolderAfter(CallBase *Call, const ArrayRef< Value * > Values, SmallVectorImpl< CallInst * > &Holders)
Insert holders so that each Value is obviously live through the entire lifetime of the call.
static AttributeList legalizeCallAttributes(CallBase *Call, bool IsMemIntrinsic, AttributeList StatepointAL)
static void insertRematerializationStores(const RematerializedValueMapTy &RematerializedValues, DenseMap< Value *, AllocaInst * > &AllocaMap, DenseSet< Value * > &VisitedLiveValues)
static bool insertParsePoints(Function &F, DominatorTree &DT, TargetTransformInfo &TTI, SmallVectorImpl< CallBase * > &ToUpdate, DefiningValueMapTy &DVCache, IsKnownBaseMapTy &KnownBases)
static void findBasePointers(const StatepointLiveSetTy &live, PointerToBaseTy &PointerToBase, DominatorTree *DT, DefiningValueMapTy &DVCache, IsKnownBaseMapTy &KnownBases)
static bool shouldRewriteStatepointsIn(Function &F)
Returns true if this function should be rewritten by this pass.
static cl::opt< bool > RematDerivedAtUses("rs4gc-remat-derived-at-uses", cl::Hidden, cl::init(true))
static ArrayRef< Use > GetDeoptBundleOperands(const CallBase *Call)
static void stripNonValidAttributesFromPrototype(Function &F)
static void findLiveSetAtInst(Instruction *inst, GCPtrLivenessData &Data, StatepointLiveSetTy &out, GCStrategy *GC)
Given results from the dataflow liveness computation, find the set of live Values at a particular ins...
static void computeLiveInValues(DominatorTree &DT, Function &F, GCPtrLivenessData &Data, GCStrategy *GC)
Compute the live-in set for every basic block in the function.
static void stripInvalidMetadataFromInstruction(Instruction &I)
Certain metadata on instructions are invalid after running RS4GC.
static constexpr Attribute::AttrKind FnAttrsToStrip[]
static bool areBothVectorOrScalar(Value *First, Value *Second)
static void rematerializeLiveValuesAtUses(RematCandTy &RematerizationCandidates, MutableArrayRef< PartiallyConstructedSafepointRecord > Records, PointerToBaseTy &PointerToBase)
static bool isHandledGCPointerType(Type *T, GCStrategy *GC)
static Value * findRematerializableChainToBasePointer(SmallVectorImpl< Instruction * > &ChainToBase, Value *CurrentValue)
static cl::opt< bool > PrintLiveSetSize("spp-print-liveset-size", cl::Hidden, cl::init(false))
static Value * findBaseDefiningValueOfVector(Value *I, DefiningValueMapTy &Cache, IsKnownBaseMapTy &KnownBases)
Return a base defining value for the 'Index' element of the given vector instruction 'I'.
static void stripNonValidData(Module &M)
The IR fed into RewriteStatepointsForGC may have had attributes and metadata implying dereferenceabil...
static InstructionCost chainToBasePointerCost(SmallVectorImpl< Instruction * > &Chain, TargetTransformInfo &TTI)
static bool isUnhandledGCPointerType(Type *Ty, GCStrategy *GC)
static SetVector< Value * > computeKillSet(BasicBlock *BB, GCStrategy *GC)
static bool ClobberNonLive
static cl::opt< bool > PrintBasePointers("spp-print-base-pointers", cl::Hidden, cl::init(false))
static bool isOriginalBaseResult(Value *V)
This value is a base pointer that is not generated by RS4GC, i.e.
static cl::opt< bool > PrintLiveSet("spp-print-liveset", cl::Hidden, cl::init(false))
static void setKnownBase(Value *V, bool IsKnownBase, IsKnownBaseMapTy &KnownBases)
Caches the IsKnownBase flag for a value and asserts that it wasn't present in the cache before.
static cl::opt< bool > AllowStatepointWithNoDeoptInfo("rs4gc-allow-statepoint-with-no-deopt-info", cl::Hidden, cl::init(true))
static void makeStatepointExplicit(DominatorTree &DT, CallBase *Call, PartiallyConstructedSafepointRecord &Result, std::vector< DeferredReplacement > &Replacements, const PointerToBaseTy &PointerToBase, GCStrategy *GC)
static std::string suffixed_name_or(Value *V, StringRef Suffix, StringRef DefaultName)
static void CreateGCRelocates(ArrayRef< Value * > LiveVariables, ArrayRef< Value * > BasePtrs, Instruction *StatepointToken, IRBuilder<> &Builder, GCStrategy *GC)
Helper function to place all gc relocates necessary for the given statepoint.
static void checkBasicSSA(DominatorTree &DT, SetVector< Value * > &Live, Instruction *TI, bool TermOkay=false)
Check that the items in 'Live' dominate 'TI'.
static StringRef getDeoptLowering(CallBase *Call)
static void findLiveReferences(Function &F, DominatorTree &DT, ArrayRef< CallBase * > toUpdate, MutableArrayRef< struct PartiallyConstructedSafepointRecord > records, GCStrategy *GC)
static AttributeMask getParamAndReturnAttributesToRemove()
static bool inlineGetBaseAndOffset(Function &F, SmallVectorImpl< CallInst * > &Intrinsics, DefiningValueMapTy &DVCache, IsKnownBaseMapTy &KnownBases)
static Value * findBaseDefiningValue(Value *I, DefiningValueMapTy &Cache, IsKnownBaseMapTy &KnownBases)
Helper function for findBasePointer - Will return a value which either a) defines the base pointer fo...
static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData, CallBase *Call, PartiallyConstructedSafepointRecord &result, PointerToBaseTy &PointerToBase, GCStrategy *GC)
Given an updated version of the dataflow liveness results, update the liveset and base pointer maps f...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static unsigned getNumElements(Type *Ty)
verify safepoint Safepoint IR static false bool isGCPointerType(Type *T)
static bool containsGCPtrType(Type *Ty)
Provides some synthesis utilities to produce sequences of values.
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallSet class.
This file defines the SmallVector class.
an instruction to allocate memory on the stack
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This class represents an incoming formal argument to a Function.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
reverse_iterator rend() const
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
reverse_iterator rbegin() const
Value handle that asserts if the Value is deleted.
AttrBuilder & removeAttribute(Attribute::AttrKind Val)
Remove an attribute from the builder.
AttributeSet getFnAttrs() const
The function attributes are returned.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
bool isEmpty() const
Return true if there are no attributes.
AttributeList addFnAttributes(LLVMContext &C, const AttrBuilder &B) const
Add function attribute to the list.
bool hasFnAttr(Attribute::AttrKind Kind) const
Return true if the attribute exists for the function.
Attribute getFnAttr(Attribute::AttrKind Kind) const
Return the attribute object that exists for the function.
AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
AttributeList addParamAttributes(LLVMContext &C, unsigned ArgNo, const AttrBuilder &B) const
Add an argument attribute to the list.
StringRef getValueAsString() const
Return the attribute's value as a string.
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
const LandingPadInst * getLandingPadInst() const
Return the landingpad instruction associated with the landing pad.
const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
reverse_iterator rbegin()
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
InstListType::reverse_iterator reverse_iterator
const BasicBlock * getUniquePredecessor() const
Return the predecessor of this block if it has a unique predecessor block.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
This class represents a no-op cast from one type to another.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
AttributeList getAttributes() const
Return the parameter attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCallKind(TailCallKind TCK)
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
This is the base class for all instructions that perform data casts.
static ConstantAggregateZero * get(Type *Ty)
This is the shared class of boolean and integer constants.
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Implements a dense probed hash-table based set.
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
static FixedVectorType * get(Type *ElementType, unsigned NumElts)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Represents calls to the gc.relocate intrinsic.
Value * getDerivedPtr() const
Represents a gc.statepoint intrinsic call.
GCStrategy describes a garbage collector algorithm's code generation requirements,...
DomTreeT & getDomTree()
Flush DomTree updates and return DomTree.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
CallInst * CreateGCStatepointCall(uint64_t ID, uint32_t NumPatchBytes, FunctionCallee ActualCallee, ArrayRef< Value * > CallArgs, std::optional< ArrayRef< Value * > > DeoptArgs, ArrayRef< Value * > GCArgs, const Twine &Name="")
Create a call to the experimental.gc.statepoint intrinsic to start a new statepoint sequence.
void SetCurrentDebugLocation(DebugLoc L)
Set location information used by debugging information.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
CallInst * CreateGCResult(Instruction *Statepoint, Type *ResultType, const Twine &Name="")
Create a call to the experimental.gc.result intrinsic to extract the result from a call wrapped in a ...
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
InvokeInst * CreateGCStatepointInvoke(uint64_t ID, uint32_t NumPatchBytes, FunctionCallee ActualInvokee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef< Value * > InvokeArgs, std::optional< ArrayRef< Value * > > DeoptArgs, ArrayRef< Value * > GCArgs, const Twine &Name="")
Create an invoke to the experimental.gc.statepoint intrinsic to start a new statepoint sequence.
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args=std::nullopt, const Twine &Name="", MDNode *FPMathTag=nullptr)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction.
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
MDNode * createMutableTBAAAccessTag(MDNode *Tag)
Return mutable version of the given mutable or immutable TBAA access tag.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
This class implements a map that also provides access to all stored values in a deterministic order.
size_type count(const KeyT &Key) const
iterator find(const KeyT &Key)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
A Module instance is used to store all the information related to an LLVM module.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Value * getIncomingValueForBlock(const BasicBlock *BB) const
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserve()
Mark an analysis as preserved.
This class represents the LLVM 'select' instruction.
A vector that has set insertion semantics.
bool remove(const value_type &X)
Remove an item from the set vector.
size_type size() const
Determine the number of elements in the SetVector.
bool set_union(const STy &S)
Compute This := This u S, return whether 'This' changed.
iterator end()
Get an iterator to the end of the SetVector.
bool empty() const
Determine if the SetVector is empty or not.
iterator begin()
Get an iterator to the beginning of the SetVector.
void set_subtract(const STy &S)
Compute This := This - B TODO: We should be able to use set_subtract from SetOperations....
bool insert(const value_type &X)
Insert a new element into the SetVector.
value_type pop_back_val()
A SetVector that performs no allocations if smaller than a certain size.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
std::string str() const
str - Get the contents as an std::string.
Class to represent struct types.
Analysis pass providing the TargetTransformInfo.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
The instances of the Type class are immutable: once they are created, they are never changed.
unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static Type * getVoidTy(LLVMContext &C)
This function has undefined behavior.
A Use represents the edge between a Value definition and its users.
bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
iterator_range< value_op_iterator > operand_values()
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
void setName(const Twine &Name)
Change the name of the value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
User * getUniqueUndroppableUser()
Return true if there is exactly one unique user of this value that cannot be dropped (that user can h...
LLVMContext & getContext() const
All values hold a context through their type.
unsigned getNumUses() const
This method computes the number of uses of this Value.
StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
A range adaptor for a pair of iterators.
This class implements an extremely fast bulk output stream that can only output to a stream.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Cold
Attempts to make code in the caller as efficient as possible under the assumption that the call is no...
AttributeList getAttributes(LLVMContext &C, ID id)
Return the attributes for an intrinsic.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
This is an optimization pass for GlobalISel generic memory operations.
pred_iterator pred_end(BasicBlock *BB)
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
void PromoteMemToReg(ArrayRef< AllocaInst * > Allocas, DominatorTree &DT, AssumptionCache *AC=nullptr)
Promote the specified list of alloca instructions into scalar registers, inserting PHI nodes as appro...
auto successors(const MachineBasicBlock *BB)
bool operator!=(uint64_t V1, const APInt &V2)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
auto unique(Range &&R, Predicate P)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
pred_iterator pred_begin(BasicBlock *BB)
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
StatepointDirectives parseStatepointDirectivesFromAttrs(AttributeList AS)
Parse out statepoint directives from the function attributes present in AS.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
BasicBlock * SplitBlockPredecessors(BasicBlock *BB, ArrayRef< BasicBlock * > Preds, const char *Suffix, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, bool PreserveLCSSA=false)
This method introduces at least one new basic block into the function and moves some of the predecess...
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
bool FoldSingleEntryPHINodes(BasicBlock *BB, MemoryDependenceResults *MemDep=nullptr)
We know that BB has one predecessor.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
@ DeoptLiveIn
Mark the deopt arguments associated with the statepoint as only being "live-in".
@ GCTransition
Indicates that this statepoint is a transition from GC-aware code to code that is not GC-aware.
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
std::unique_ptr< GCStrategy > getGCStrategy(const StringRef Name)
Lookup the GCStrategy object associated with the given gc name.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
bool isStatepointDirectiveAttr(Attribute Attr)
Return true if the Attr is an attribute that is a statepoint directive.
bool removeUnreachableBlocks(Function &F, DomTreeUpdater *DTU=nullptr, MemorySSAUpdater *MSSAU=nullptr)
Remove all blocks that can not be reached from the function's entry.
bool callsGCLeafFunction(const CallBase *Call, const TargetLibraryInfo &TLI)
Return true if this call calls a gc leaf function.
bool runOnFunction(Function &F, DominatorTree &, TargetTransformInfo &, const TargetLibraryInfo &)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Call sites that get wrapped by a gc.statepoint (currently only in RewriteStatepointsForGC and potenti...
std::optional< uint32_t > NumPatchBytes
std::optional< uint64_t > StatepointID
static const uint64_t DefaultStatepointID