77#define DEBUG_TYPE "rewrite-statepoints-for-gc"
97#ifdef EXPENSIVE_CHECKS
134 bool Changed =
false;
138 if (
F.isDeclaration() ||
F.empty())
167struct GCPtrLivenessData {
198using RematerializedValueMapTy =
201struct PartiallyConstructedSafepointRecord {
203 StatepointLiveSetTy LiveSet;
216 RematerializedValueMapTy RematerializedValues;
219struct RematerizlizationCandidateRecord {
232 std::optional<OperandBundleUse> DeoptBundle =
237 "Found non-leaf call without deopt info!");
241 return DeoptBundle->Inputs;
254 assert(GC &&
"GC Strategy for isGCPointerType cannot be null");
256 if (!isa<PointerType>(
T))
260 return GC->isGCManagedPointer(
T).value_or(
true);
273 if (
auto VT = dyn_cast<VectorType>(
T))
285 if (
VectorType *VT = dyn_cast<VectorType>(Ty))
287 if (
ArrayType *AT = dyn_cast<ArrayType>(Ty))
289 if (
StructType *ST = dyn_cast<StructType>(Ty))
291 [GC](
Type *Ty) { return containsGCPtrType(Ty, GC); });
307 return V->hasName() ? (V->getName() + Suffix).str() : DefaultName.
str();
316 PartiallyConstructedSafepointRecord &Result,
GCStrategy *GC) {
317 StatepointLiveSetTy LiveSet;
321 dbgs() <<
"Live Variables:\n";
322 for (
Value *V : LiveSet)
323 dbgs() <<
" " << V->getName() <<
" " << *V <<
"\n";
326 dbgs() <<
"Safepoint For: " << Call->getCalledOperand()->getName() <<
"\n";
327 dbgs() <<
"Number live values: " << LiveSet.size() <<
"\n";
329 Result.LiveSet = LiveSet;
338 IsKnownBaseMapTy &KnownBases);
341 IsKnownBaseMapTy &KnownBases);
353 IsKnownBaseMapTy &KnownBases) {
357 auto Cached = Cache.find(
I);
358 if (Cached != Cache.end())
359 return Cached->second;
361 if (isa<Argument>(
I)) {
368 if (isa<Constant>(
I)) {
377 if (isa<LoadInst>(
I)) {
383 if (isa<InsertElementInst>(
I)) {
392 if (isa<ShuffleVectorInst>(
I)) {
405 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(
I)) {
414 if (
auto *Freeze = dyn_cast<FreezeInst>(
I)) {
422 if (
auto *BC = dyn_cast<BitCastInst>(
I)) {
431 if (isa<CallInst>(
I) || isa<InvokeInst>(
I)) {
439 assert((isa<SelectInst>(
I) || isa<PHINode>(
I)) &&
440 "unknown vector instruction - no base found for vector element");
451 IsKnownBaseMapTy &KnownBases) {
452 assert(
I->getType()->isPtrOrPtrVectorTy() &&
453 "Illegal to ask for the base pointer of a non-pointer type");
454 auto Cached = Cache.find(
I);
455 if (Cached != Cache.end())
456 return Cached->second;
458 if (
I->getType()->isVectorTy())
461 if (isa<Argument>(
I)) {
469 if (isa<Constant>(
I)) {
491 if (isa<IntToPtrInst>(
I)) {
497 if (
CastInst *CI = dyn_cast<CastInst>(
I)) {
498 Value *Def = CI->stripPointerCasts();
501 assert(cast<PointerType>(Def->getType())->getAddressSpace() ==
502 cast<PointerType>(CI->getType())->getAddressSpace() &&
503 "unsupported addrspacecast");
507 assert(!isa<CastInst>(Def) &&
"shouldn't find another cast here");
513 if (isa<LoadInst>(
I)) {
528 if (
auto *Freeze = dyn_cast<FreezeInst>(
I)) {
535 switch (
II->getIntrinsicID()) {
539 case Intrinsic::experimental_gc_statepoint:
541 case Intrinsic::experimental_gc_relocate:
546 case Intrinsic::gcroot:
551 "interaction with the gcroot mechanism is not supported");
552 case Intrinsic::experimental_gc_get_pointer_base:
561 if (isa<CallInst>(
I) || isa<InvokeInst>(
I)) {
569 assert(!isa<LandingPadInst>(
I) &&
"Landing Pad is unimplemented");
571 if (isa<AtomicCmpXchgInst>(
I)) {
580 if (isa<AtomicRMWInst>(
I)) {
582 "Only Xchg is allowed for pointer values");
593 if (isa<ExtractValueInst>(
I)) {
601 assert(!isa<InsertValueInst>(
I) &&
602 "Base pointer for a struct is meaningless");
607 isa<Instruction>(
I) && cast<Instruction>(
I)->getMetadata(
"is_base_value");
615 if (isa<ExtractElementInst>(
I))
625 assert((isa<SelectInst>(
I) || isa<PHINode>(
I)) &&
626 "missing instruction case in findBaseDefiningValue");
632 IsKnownBaseMapTy &KnownBases) {
633 if (!Cache.contains(
I)) {
637 << Cache[
I]->getName() <<
", is known base = "
638 << KnownBases[
I] <<
"\n");
641 assert(KnownBases.contains(Cache[
I]) &&
642 "Cached value must be present in known bases map");
649 IsKnownBaseMapTy &KnownBases) {
651 auto Found = Cache.find(Def);
652 if (Found != Cache.end()) {
654 return Found->second;
665 return !isa<PHINode>(V) && !isa<SelectInst>(V) &&
666 !isa<ExtractElementInst>(V) && !isa<InsertElementInst>(V) &&
667 !isa<ShuffleVectorInst>(V);
672 auto It = KnownBases.find(V);
673 assert(It != KnownBases.end() &&
"Value not present in the map");
678 IsKnownBaseMapTy &KnownBases) {
680 auto It = KnownBases.find(V);
681 if (It != KnownBases.end())
682 assert(It->second == IsKnownBase &&
"Changing already present value");
684 KnownBases[V] = IsKnownBase;
689 return isa<VectorType>(
First->getType()) ==
690 isa<VectorType>(Second->
getType());
715 explicit BDVState(
Value *OriginalValue)
716 : OriginalValue(OriginalValue) {}
717 explicit BDVState(
Value *OriginalValue, StatusTy
Status,
Value *BaseValue =
nullptr)
718 : OriginalValue(OriginalValue),
Status(
Status), BaseValue(BaseValue) {
722 StatusTy getStatus()
const {
return Status; }
723 Value *getOriginalValue()
const {
return OriginalValue; }
724 Value *getBaseValue()
const {
return BaseValue; }
726 bool isBase()
const {
return getStatus() ==
Base; }
727 bool isUnknown()
const {
return getStatus() ==
Unknown; }
728 bool isConflict()
const {
return getStatus() == Conflict; }
733 void meet(
const BDVState &
Other) {
734 auto markConflict = [&]() {
735 Status = BDVState::Conflict;
744 BaseValue =
Other.getBaseValue();
748 assert(isBase() &&
"Unknown state");
750 if (
Other.isUnknown())
753 if (
Other.isConflict())
754 return markConflict();
758 if (getBaseValue() !=
Other.getBaseValue())
759 return markConflict();
764 return OriginalValue ==
Other.OriginalValue && BaseValue ==
Other.BaseValue &&
768 bool operator!=(
const BDVState &other)
const {
return !(*
this == other); }
777 switch (getStatus()) {
788 OS <<
" (base " << getBaseValue() <<
" - "
789 << (getBaseValue() ? getBaseValue()->getName() :
"nullptr") <<
")"
790 <<
" for " << OriginalValue->getName() <<
":";
813 IsKnownBaseMapTy &KnownBases) {
842 auto isExpectedBDVType = [](
Value *BDV) {
843 return isa<PHINode>(BDV) || isa<SelectInst>(BDV) ||
844 isa<ExtractElementInst>(BDV) || isa<InsertElementInst>(BDV) ||
845 isa<ShuffleVectorInst>(BDV);
857 auto VerifyStates = [&]() {
858 for (
auto &Entry : States) {
859 assert(Entry.first == Entry.second.getOriginalValue());
864 auto visitBDVOperands = [](
Value *BDV, std::function<void (
Value*)>
F) {
865 if (
PHINode *PN = dyn_cast<PHINode>(BDV)) {
866 for (
Value *InVal : PN->incoming_values())
868 }
else if (
SelectInst *SI = dyn_cast<SelectInst>(BDV)) {
869 F(SI->getTrueValue());
870 F(SI->getFalseValue());
871 }
else if (
auto *EE = dyn_cast<ExtractElementInst>(BDV)) {
872 F(EE->getVectorOperand());
873 }
else if (
auto *IE = dyn_cast<InsertElementInst>(BDV)) {
874 F(IE->getOperand(0));
875 F(IE->getOperand(1));
876 }
else if (
auto *SV = dyn_cast<ShuffleVectorInst>(BDV)) {
879 F(SV->getOperand(0));
880 if (!SV->isZeroEltSplat())
881 F(SV->getOperand(1));
893 States.
insert({Def, BDVState(Def)});
894 while (!Worklist.
empty()) {
898 auto visitIncomingValue = [&](
Value *InVal) {
907 assert(isExpectedBDVType(
Base) &&
"the only non-base values "
908 "we see should be base defining values");
913 visitBDVOperands(Current, visitIncomingValue);
920 for (
const auto &Pair : States) {
921 LLVM_DEBUG(
dbgs() <<
" " << Pair.second <<
" for " << *Pair.first <<
"\n");
933 for (
auto Pair : States) {
934 Value *BDV = Pair.first;
935 auto canPruneInput = [&](
Value *V) {
938 if (V->stripPointerCasts() == BDV)
941 if (V->stripPointerCasts() != VBDV)
945 return States.count(VBDV) == 0;
948 bool CanPrune =
true;
949 visitBDVOperands(BDV, [&](
Value *
Op) {
950 CanPrune = CanPrune && canPruneInput(
Op);
963 if (!States.
count(Def))
968 auto GetStateForBDV = [&](
Value *BaseValue,
Value *Input) {
969 auto I = States.
find(BaseValue);
970 if (
I != States.
end())
973 return BDVState(BaseValue, BDVState::Base, BaseValue);
996 if (isa<InsertElementInst>(
I) || isa<ExtractElementInst>(
I))
1000 if (isa<ShuffleVectorInst>(
I))
1014 bool Progress =
true;
1017 const size_t OldSize = States.
size();
1024 for (
auto Pair : States) {
1025 Value *BDV = Pair.first;
1031 "why did it get added?");
1033 BDVState NewState(BDV);
1034 visitBDVOperands(BDV, [&](
Value *
Op) {
1036 auto OpState = GetStateForBDV(BDV,
Op);
1037 NewState.meet(OpState);
1043 auto I = cast<Instruction>(BDV);
1044 auto BV = NewState.getBaseValue();
1045 if (BV && MarkConflict(
I, BV))
1046 NewState = BDVState(
I, BDVState::Conflict);
1048 BDVState OldState = Pair.second;
1049 if (OldState != NewState) {
1051 States[BDV] = NewState;
1055 assert(OldSize == States.size() &&
1056 "fixed point shouldn't be adding any new nodes to state");
1062 for (
const auto &Pair : States) {
1063 LLVM_DEBUG(
dbgs() <<
" " << Pair.second <<
" for " << *Pair.first <<
"\n");
1068 for (
auto Pair : States) {
1070 BDVState State = Pair.second;
1071 auto *BaseValue = State.getBaseValue();
1077 "why did it get added?");
1078 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1084 for (
auto Pair : States) {
1086 BDVState State = Pair.second;
1092 "why did it get added?");
1093 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1098 assert(!isa<InsertElementInst>(
I) || State.isConflict());
1100 if (!State.isConflict())
1103 auto getMangledName = [](
Instruction *
I) -> std::string {
1104 if (isa<PHINode>(
I)) {
1106 }
else if (isa<SelectInst>(
I)) {
1108 }
else if (isa<ExtractElementInst>(
I)) {
1110 }
else if (isa<InsertElementInst>(
I)) {
1119 BaseInst->
setName(getMangledName(
I));
1122 States[
I] = BDVState(
I, BDVState::Conflict, BaseInst);
1141 if (!States.
count(BDV)) {
1147 Base = States[BDV].getBaseValue();
1151 if (
Base->getType() != Input->
getType() && InsertPt)
1153 InsertPt->getIterator());
1160 for (
auto Pair : States) {
1162 BDVState State = Pair.second;
1169 "why did it get added?");
1170 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1171 if (!State.isConflict())
1174 if (
PHINode *BasePHI = dyn_cast<PHINode>(State.getBaseValue())) {
1175 PHINode *PN = cast<PHINode>(BDV);
1183 for (
unsigned i = 0; i < NumPHIValues; i++) {
1186 if (!BlockToValue.
count(InBB))
1187 BlockToValue[InBB] = getBaseForInput(InVal, InBB->
getTerminator());
1190 Value *OldBase = BlockToValue[InBB];
1191 Value *
Base = getBaseForInput(InVal,
nullptr);
1195 auto StripBitCasts = [](
Value *V) ->
Value * {
1196 while (
auto *BC = dyn_cast<BitCastInst>(V))
1197 V = BC->getOperand(0);
1206 assert(StripBitCasts(
Base) == StripBitCasts(OldBase) &&
1207 "findBaseOrBDV should be pure!");
1211 BasePHI->setIncomingValue(i,
Base);
1214 dyn_cast<SelectInst>(State.getBaseValue())) {
1219 BaseSI->setTrueValue(getBaseForInput(SI->getTrueValue(), BaseSI));
1220 BaseSI->setFalseValue(getBaseForInput(SI->getFalseValue(), BaseSI));
1221 }
else if (
auto *BaseEE =
1222 dyn_cast<ExtractElementInst>(State.getBaseValue())) {
1223 Value *InVal = cast<ExtractElementInst>(BDV)->getVectorOperand();
1226 BaseEE->setOperand(0, getBaseForInput(InVal, BaseEE));
1227 }
else if (
auto *BaseIE = dyn_cast<InsertElementInst>(State.getBaseValue())){
1228 auto *BdvIE = cast<InsertElementInst>(BDV);
1229 auto UpdateOperand = [&](
int OperandIdx) {
1230 Value *InVal = BdvIE->getOperand(OperandIdx);
1231 Value *
Base = getBaseForInput(InVal, BaseIE);
1232 BaseIE->setOperand(OperandIdx,
Base);
1237 auto *BaseSV = cast<ShuffleVectorInst>(State.getBaseValue());
1238 auto *BdvSV = cast<ShuffleVectorInst>(BDV);
1239 auto UpdateOperand = [&](
int OperandIdx) {
1240 Value *InVal = BdvSV->getOperand(OperandIdx);
1241 Value *
Base = getBaseForInput(InVal, BaseSV);
1242 BaseSV->setOperand(OperandIdx,
Base);
1245 if (!BdvSV->isZeroEltSplat())
1249 Value *InVal = BdvSV->getOperand(1);
1260 [[maybe_unused]]
auto &
DL =
1261 cast<llvm::Instruction>(Def)->getDataLayout();
1265 for (
auto Pair : States) {
1266 auto *BDV = Pair.first;
1267 Value *
Base = Pair.second.getBaseValue();
1272 DL.getTypeAllocSize(
Base->getType()) &&
1273 "Derived and base values should have same size");
1279 "why did it get added?");
1282 dbgs() <<
"Updating base value cache"
1283 <<
" for: " << BDV->
getName() <<
" from: "
1284 << (Cache.count(BDV) ? Cache[BDV]->getName().str() :
"none")
1285 <<
" to: " <<
Base->getName() <<
"\n");
1289 assert(Cache.count(Def));
1310 DefiningValueMapTy &DVCache,
1311 IsKnownBaseMapTy &KnownBases) {
1314 assert(base &&
"failed to find base pointer");
1315 PointerToBase[ptr] = base;
1316 assert((!isa<Instruction>(base) || !isa<Instruction>(ptr) ||
1317 DT->
dominates(cast<Instruction>(base)->getParent(),
1318 cast<Instruction>(ptr)->getParent())) &&
1319 "The base we found better dominate the derived pointer");
1327 PartiallyConstructedSafepointRecord &result,
1328 PointerToBaseTy &PointerToBase,
1329 IsKnownBaseMapTy &KnownBases) {
1330 StatepointLiveSetTy PotentiallyDerivedPointers = result.LiveSet;
1337 for (
Value *V : Opt->Inputs) {
1338 if (!PotentiallyDerivedPointers.count(V))
1340 PotentiallyDerivedPointers.remove(V);
1341 PointerToBase[V] = V;
1351 PartiallyConstructedSafepointRecord &result,
1352 PointerToBaseTy &PointerToBase,
1358 PointerToBaseTy &PointerToBase,
GCStrategy *GC) {
1361 GCPtrLivenessData RevisedLivenessData;
1363 for (
size_t i = 0; i < records.
size(); i++) {
1364 struct PartiallyConstructedSafepointRecord &
info = records[i];
1376 Value *AlternateLiveBase) {
1386 assert(isa<GetElementPtrInst>(Instr) || isa<CastInst>(Instr));
1390 ClonedValue->
setName(Instr->getName() +
".remat");
1394 if (LastClonedValue) {
1402 "incorrect use in rematerialization chain");
1405 assert(OpValue != RootOfChain && OpValue != AlternateLiveBase);
1414 if (RootOfChain != AlternateLiveBase)
1418 LastClonedValue = ClonedValue;
1422 return LastClonedValue;
1441 assert(!isa<PHINode>(Ret->begin()) &&
1442 "All PHI nodes should have been removed!");
1455 {Attribute::Memory, Attribute::NoSync, Attribute::NoFree};
1463 return StatepointAL;
1482 return StatepointAL;
1487 for (
unsigned I :
llvm::seq(Call->arg_size()))
1493 return StatepointAL;
1513 assert(ValIt != LiveVec.
end() &&
"Val not found in LiveVec!");
1514 size_t Index = std::distance(LiveVec.
begin(), ValIt);
1527 auto getGCRelocateDecl = [&](
Type *Ty) {
1529 auto AS = Ty->getScalarType()->getPointerAddressSpace();
1531 if (
auto *VT = dyn_cast<VectorType>(Ty))
1535 M, Intrinsic::experimental_gc_relocate, {NewTy});
1549 if (!TypeToDeclMap.
count(Ty))
1550 TypeToDeclMap[Ty] = getGCRelocateDecl(Ty);
1551 Function *GCRelocateDecl = TypeToDeclMap[Ty];
1555 GCRelocateDecl, {StatepointToken, BaseIdx, LiveIdx},
1567class DeferredReplacement {
1570 bool IsDeoptimize =
false;
1572 DeferredReplacement() =
default;
1576 assert(Old != New && Old && New &&
1577 "Cannot RAUW equal values or to / from null!");
1579 DeferredReplacement
D;
1585 static DeferredReplacement createDelete(
Instruction *ToErase) {
1586 DeferredReplacement
D;
1591 static DeferredReplacement createDeoptimizeReplacement(
Instruction *Old) {
1593 auto *
F = cast<CallInst>(Old)->getCalledFunction();
1594 assert(
F &&
F->getIntrinsicID() == Intrinsic::experimental_deoptimize &&
1595 "Only way to construct a deoptimize deferred replacement");
1597 DeferredReplacement
D;
1599 D.IsDeoptimize =
true;
1604 void doReplacement() {
1608 assert(OldI != NewI &&
"Disallowed at construction?!");
1609 assert((!IsDeoptimize || !New) &&
1610 "Deoptimize intrinsics are not replaced!");
1621 auto *RI = cast<ReturnInst>(OldI->
getParent()->getTerminator());
1623 RI->eraseFromParent();
1633 const char *DeoptLowering =
"deopt-lowering";
1634 if (Call->hasFnAttr(DeoptLowering)) {
1640 Function *
F = Call->getCalledFunction();
1641 assert(
F &&
F->hasFnAttribute(DeoptLowering));
1642 return F->getFnAttribute(DeoptLowering).getValueAsString();
1644 return "live-through";
1651 PartiallyConstructedSafepointRecord &Result,
1652 std::vector<DeferredReplacement> &Replacements,
1653 const PointerToBaseTy &PointerToBase,
1669 std::optional<ArrayRef<Use>> DeoptArgs;
1671 DeoptArgs = Bundle->Inputs;
1672 std::optional<ArrayRef<Use>> TransitionArgs;
1674 TransitionArgs = Bundle->Inputs;
1682 bool IsDeoptimize =
false;
1683 bool IsMemIntrinsic =
false;
1694 if (DeoptLowering ==
"live-in")
1697 assert(DeoptLowering ==
"live-through" &&
"Unsupported value!");
1700 FunctionCallee CallTarget(Call->getFunctionType(), Call->getCalledOperand());
1702 auto IID =
F->getIntrinsicID();
1703 if (IID == Intrinsic::experimental_deoptimize) {
1709 for (
Value *Arg : CallArgs)
1718 CallTarget =
F->getParent()
1719 ->getOrInsertFunction(
"__llvm_deoptimize", FTy);
1721 IsDeoptimize =
true;
1722 }
else if (IID == Intrinsic::memcpy_element_unordered_atomic ||
1723 IID == Intrinsic::memmove_element_unordered_atomic) {
1724 IsMemIntrinsic =
true;
1742 auto &Context = Call->getContext();
1743 auto &
DL = Call->getDataLayout();
1744 auto GetBaseAndOffset = [&](
Value *Derived) {
1750 if (isa<Constant>(Derived))
1754 assert(PointerToBase.count(Derived));
1755 Base = PointerToBase.find(Derived)->second;
1757 unsigned AddressSpace = Derived->getType()->getPointerAddressSpace();
1763 return std::make_pair(
Base, Builder.
CreateSub(Derived_int, Base_int));
1766 auto *Dest = CallArgs[0];
1767 Value *DestBase, *DestOffset;
1768 std::tie(DestBase, DestOffset) = GetBaseAndOffset(Dest);
1770 auto *Source = CallArgs[1];
1771 Value *SourceBase, *SourceOffset;
1772 std::tie(SourceBase, SourceOffset) = GetBaseAndOffset(Source);
1774 auto *LengthInBytes = CallArgs[2];
1775 auto *ElementSizeCI = cast<ConstantInt>(CallArgs[3]);
1785 for (
Value *Arg : CallArgs)
1791 uint64_t ElementSize = ElementSizeCI->getZExtValue();
1792 if (IID == Intrinsic::memcpy_element_unordered_atomic) {
1793 switch (ElementSize) {
1795 return "__llvm_memcpy_element_unordered_atomic_safepoint_1";
1797 return "__llvm_memcpy_element_unordered_atomic_safepoint_2";
1799 return "__llvm_memcpy_element_unordered_atomic_safepoint_4";
1801 return "__llvm_memcpy_element_unordered_atomic_safepoint_8";
1803 return "__llvm_memcpy_element_unordered_atomic_safepoint_16";
1808 assert(IID == Intrinsic::memmove_element_unordered_atomic);
1809 switch (ElementSize) {
1811 return "__llvm_memmove_element_unordered_atomic_safepoint_1";
1813 return "__llvm_memmove_element_unordered_atomic_safepoint_2";
1815 return "__llvm_memmove_element_unordered_atomic_safepoint_4";
1817 return "__llvm_memmove_element_unordered_atomic_safepoint_8";
1819 return "__llvm_memmove_element_unordered_atomic_safepoint_16";
1827 ->getOrInsertFunction(GetFunctionName(IID, ElementSizeCI), FTy);
1833 if (
auto *CI = dyn_cast<CallInst>(Call)) {
1835 StatepointID, NumPatchBytes, CallTarget, Flags, CallArgs,
1836 TransitionArgs, DeoptArgs, GCLive,
"safepoint_token");
1846 Token = cast<GCStatepointInst>(SPCall);
1850 assert(CI->getNextNode() &&
"Not a terminator, must have next!");
1854 auto *
II = cast<InvokeInst>(Call);
1860 StatepointID, NumPatchBytes, CallTarget,
II->getNormalDest(),
1861 II->getUnwindDest(), Flags, CallArgs, TransitionArgs, DeoptArgs,
1862 GCLive,
"statepoint_token");
1871 Token = cast<GCStatepointInst>(SPInvoke);
1877 "can't safely insert in this block!");
1884 Result.UnwindToken = ExceptionalToken;
1892 "can't safely insert in this block!");
1899 assert(Token &&
"Should be set in one of the above branches!");
1905 Replacements.push_back(
1906 DeferredReplacement::createDeoptimizeReplacement(Call));
1908 Token->
setName(
"statepoint_token");
1909 if (!Call->getType()->isVoidTy() && !Call->use_empty()) {
1914 Call->getAttributes().getRetAttrs()));
1922 Replacements.emplace_back(
1923 DeferredReplacement::createRAUW(Call, GCResult));
1925 Replacements.emplace_back(DeferredReplacement::createDelete(Call));
1929 Result.StatepointToken = Token;
1942 PartiallyConstructedSafepointRecord &Result,
1943 std::vector<DeferredReplacement> &Replacements,
1944 const PointerToBaseTy &PointerToBase,
GCStrategy *GC) {
1945 const auto &LiveSet = Result.LiveSet;
1949 LiveVec.
reserve(LiveSet.size());
1950 BaseVec.
reserve(LiveSet.size());
1951 for (
Value *L : LiveSet) {
1953 assert(PointerToBase.count(L));
1954 Value *
Base = PointerToBase.find(L)->second;
1974 for (
User *U : GCRelocs) {
1981 Value *Alloca = AllocaMap[OriginalValue];
1985 "Should always have one since it's not a terminator");
1989 VisitedLiveValues.
insert(OriginalValue);
1997 const RematerializedValueMapTy &RematerializedValues,
2000 for (
auto RematerializedValuePair: RematerializedValues) {
2001 Instruction *RematerializedValue = RematerializedValuePair.first;
2002 Value *OriginalValue = RematerializedValuePair.second;
2005 "Can not find alloca for rematerialized value");
2006 Value *Alloca = AllocaMap[OriginalValue];
2008 new StoreInst(RematerializedValue, Alloca,
2012 VisitedLiveValues.
insert(OriginalValue);
2024 int InitialAllocaNum = 0;
2026 if (isa<AllocaInst>(
I))
2034 std::size_t NumRematerializedValues = 0;
2040 auto emitAllocaFor = [&](
Value *LiveValue) {
2042 new AllocaInst(LiveValue->getType(),
DL.getAllocaAddrSpace(),
"",
2043 F.getEntryBlock().getFirstNonPHIIt());
2044 AllocaMap[LiveValue] = Alloca;
2053 for (
const auto &
Info : Records)
2054 for (
auto RematerializedValuePair :
Info.RematerializedValues) {
2055 Value *OriginalValue = RematerializedValuePair.second;
2056 if (AllocaMap.
contains(OriginalValue))
2059 emitAllocaFor(OriginalValue);
2060 ++NumRematerializedValues;
2072 for (
const auto &
Info : Records) {
2073 Value *Statepoint =
Info.StatepointToken;
2083 if (isa<InvokeInst>(Statepoint)) {
2099 for (
auto Pair : AllocaMap) {
2100 Value *Def = Pair.first;
2104 if (VisitedLiveValues.
count(Def)) {
2111 for (
auto *AI : ToClobber) {
2112 auto AT = AI->getAllocatedType();
2114 if (AT->isVectorTy())
2124 if (
auto II = dyn_cast<InvokeInst>(Statepoint)) {
2125 InsertClobbersAt(
II->getNormalDest()->getFirstInsertionPt());
2126 InsertClobbersAt(
II->getUnwindDest()->getFirstInsertionPt());
2129 std::next(cast<Instruction>(Statepoint)->getIterator()));
2135 for (
auto Pair : AllocaMap) {
2136 Value *Def = Pair.first;
2144 Uses.reserve(Def->getNumUses());
2145 for (
User *U : Def->users()) {
2146 if (!isa<ConstantExpr>(U)) {
2152 Uses.push_back(cast<Instruction>(U));
2161 if (isa<PHINode>(
Use)) {
2163 for (
unsigned i = 0; i < Phi->getNumIncomingValues(); i++) {
2164 if (Def == Phi->getIncomingValue(i)) {
2167 Phi->getIncomingBlock(i)->getTerminator()->getIterator());
2168 Phi->setIncomingValue(i, Load);
2173 Use->getIterator());
2174 Use->replaceUsesOfWith(Def, Load);
2182 DL.getABITypeAlign(Def->getType()));
2183 if (
Instruction *Inst = dyn_cast<Instruction>(Def)) {
2184 if (
InvokeInst *Invoke = dyn_cast<InvokeInst>(Inst)) {
2187 BasicBlock *NormalDest = Invoke->getNormalDest();
2190 assert(!Inst->isTerminator() &&
2191 "The only terminator that can produce a value is "
2192 "InvokeInst which is handled above.");
2193 Store->insertAfter(Inst);
2196 assert(isa<Argument>(Def));
2197 Store->insertAfter(cast<Instruction>(Alloca));
2201 assert(PromotableAllocas.
size() ==
Live.size() + NumRematerializedValues &&
2202 "we must have the same allocas with lives");
2203 (void) NumRematerializedValues;
2204 if (!PromotableAllocas.
empty()) {
2210 for (
auto &
I :
F.getEntryBlock())
2211 if (isa<AllocaInst>(
I))
2213 assert(InitialAllocaNum == 0 &&
"We must not introduce any extra allocas");
2233 Module *M = Call->getModule();
2237 if (isa<CallInst>(Call)) {
2245 auto *
II = cast<InvokeInst>(Call);
2247 Func, Values,
"",
II->getNormalDest()->getFirstInsertionPt()));
2249 Func, Values,
"",
II->getUnwindDest()->getFirstInsertionPt()));
2256 GCPtrLivenessData OriginalLivenessData;
2258 for (
size_t i = 0; i < records.
size(); i++) {
2259 struct PartiallyConstructedSafepointRecord &
info = records[i];
2272 Value *CurrentValue) {
2276 GEP->getPointerOperand());
2279 if (
CastInst *CI = dyn_cast<CastInst>(CurrentValue)) {
2280 if (!CI->isNoopCast(CI->getDataLayout()))
2290 return CurrentValue;
2301 if (
CastInst *CI = dyn_cast<CastInst>(Instr)) {
2302 assert(CI->isNoopCast(CI->getDataLayout()) &&
2303 "non noop cast is found during rematerialization");
2305 Type *SrcTy = CI->getOperand(0)->getType();
2312 Type *ValTy =
GEP->getSourceElementType();
2318 if (!
GEP->hasAllConstantIndices())
2337 for (
unsigned i = 0; i < PhiNum; i++)
2343 for (
unsigned i = 0; i < PhiNum; i++) {
2346 if (CIVI == CurrentIncomingValues.
end())
2348 BasicBlock *CurrentIncomingBB = CIVI->second;
2359 RematCandTy &RematerizationCandidates,
2361 const unsigned int ChainLengthThreshold = 10;
2363 for (
auto P2B : PointerToBase) {
2364 auto *Derived = P2B.first;
2365 auto *
Base = P2B.second;
2367 if (Derived ==
Base)
2372 Value *RootOfChain =
2376 if ( ChainToBase.
size() == 0 ||
2377 ChainToBase.
size() > ChainLengthThreshold)
2382 if (RootOfChain != PointerToBase[Derived]) {
2383 PHINode *OrigRootPhi = dyn_cast<PHINode>(RootOfChain);
2384 PHINode *AlternateRootPhi = dyn_cast<PHINode>(PointerToBase[Derived]);
2385 if (!OrigRootPhi || !AlternateRootPhi)
2407 RematerizlizationCandidateRecord
Record;
2408 Record.ChainToBase = ChainToBase;
2409 Record.RootOfChain = RootOfChain;
2411 RematerizationCandidates.insert({ Derived,
Record });
2420 RematCandTy &RematerizationCandidates,
2422 PointerToBaseTy &PointerToBase) {
2429 <<
"Num statepoints: " << Records.size() <<
'\n');
2431 for (
auto &It : RematerizationCandidates) {
2433 auto &
Record = It.second;
2443 if (U->getParent() == Cand->
getParent())
2448 [](
const auto *U) { return isa<PHINode>(U); }))
2460 Records, [Cand](
const auto &R) {
return R.LiveSet.contains(Cand); });
2463 LLVM_DEBUG(
dbgs() <<
"Num uses: " << NumUses <<
" Num live statepoints: "
2464 << NumLiveStatepoints <<
" ");
2466 if (NumLiveStatepoints < NumUses) {
2474 if (NumLiveStatepoints == NumUses &&
Record.Cost > 0) {
2486 if (
Record.ChainToBase.size() > 1) {
2487 Record.ChainToBase.clear();
2503 Record.ChainToBase, UserI,
Record.RootOfChain, PointerToBase[Cand]);
2505 PointerToBase[RematChain] = PointerToBase[Cand];
2511 <<
" derived pointers\n");
2512 for (
auto *Cand : LiveValuesToBeDeleted) {
2513 assert(Cand->use_empty() &&
"Unexpected user remain");
2514 RematerizationCandidates.erase(Cand);
2515 for (
auto &R : Records) {
2516 assert(!R.LiveSet.contains(Cand) ||
2517 R.LiveSet.contains(PointerToBase[Cand]));
2518 R.LiveSet.remove(Cand);
2524 if (!LiveValuesToBeDeleted.
empty()) {
2525 for (
auto &
P : RematerizationCandidates) {
2527 if (R.ChainToBase.size() > 1) {
2528 R.ChainToBase.clear();
2540 PartiallyConstructedSafepointRecord &
Info,
2541 PointerToBaseTy &PointerToBase,
2542 RematCandTy &RematerizationCandidates,
2549 auto It = RematerizationCandidates.find(LiveValue);
2550 if (It == RematerizationCandidates.end())
2553 RematerizlizationCandidateRecord &
Record = It->second;
2558 if (isa<InvokeInst>(Call))
2566 LiveValuesToBeDeleted.
push_back(LiveValue);
2572 if (isa<CallInst>(Call)) {
2577 Record.RootOfChain, PointerToBase[LiveValue]);
2578 Info.RematerializedValues[RematerializedValue] = LiveValue;
2580 auto *Invoke = cast<InvokeInst>(Call);
2583 &*Invoke->getNormalDest()->getFirstInsertionPt();
2585 &*Invoke->getUnwindDest()->getFirstInsertionPt();
2589 Record.RootOfChain, PointerToBase[LiveValue]);
2592 Record.RootOfChain, PointerToBase[LiveValue]);
2594 Info.RematerializedValues[NormalRematerializedValue] = LiveValue;
2595 Info.RematerializedValues[UnwindRematerializedValue] = LiveValue;
2600 for (
auto *LiveValue: LiveValuesToBeDeleted) {
2601 Info.LiveSet.remove(LiveValue);
2607 DefiningValueMapTy &DVCache,
2608 IsKnownBaseMapTy &KnownBases) {
2609 auto &Context =
F.getContext();
2610 auto &
DL =
F.getDataLayout();
2611 bool Changed =
false;
2613 for (
auto *Callsite : Intrinsics)
2614 switch (Callsite->getIntrinsicID()) {
2615 case Intrinsic::experimental_gc_get_pointer_base: {
2619 assert(!DVCache.count(Callsite));
2620 Callsite->replaceAllUsesWith(
Base);
2621 if (!
Base->hasName())
2622 Base->takeName(Callsite);
2623 Callsite->eraseFromParent();
2626 case Intrinsic::experimental_gc_get_pointer_offset: {
2628 Value *Derived = Callsite->getOperand(0);
2630 assert(!DVCache.count(Callsite));
2642 Offset->takeName(Callsite);
2643 Callsite->eraseFromParent();
2656 DefiningValueMapTy &DVCache,
2657 IsKnownBaseMapTy &KnownBases) {
2662 std::set<CallBase *> Uniqued;
2663 Uniqued.insert(ToUpdate.
begin(), ToUpdate.
end());
2664 assert(Uniqued.size() == ToUpdate.
size() &&
"no duplicates please!");
2667 assert(Call->getFunction() == &
F);
2675 auto *
II = dyn_cast<InvokeInst>(Call);
2695 "support for FCA unimplemented");
2710 PointerToBaseTy PointerToBase;
2713 for (
size_t i = 0; i < Records.size(); i++) {
2714 PartiallyConstructedSafepointRecord &
info = Records[i];
2718 errs() <<
"Base Pairs (w/o Relocation):\n";
2719 for (
auto &Pair : PointerToBase) {
2720 errs() <<
" derived ";
2721 Pair.first->printAsOperand(
errs(),
false);
2723 Pair.second->printAsOperand(
errs(),
false);
2743 for (
size_t i = 0; i < Records.size(); i++) {
2744 PartiallyConstructedSafepointRecord &
Info = Records[i];
2747 for (
auto *Derived :
Info.LiveSet) {
2748 assert(PointerToBase.count(Derived) &&
"Missed base for derived pointer");
2749 Bases.
push_back(PointerToBase[Derived]);
2761 errs() <<
"Base Pairs: (w/Relocation)\n";
2762 for (
auto Pair : PointerToBase) {
2763 errs() <<
" derived ";
2764 Pair.first->printAsOperand(
errs(),
false);
2766 Pair.second->printAsOperand(
errs(),
false);
2779 for (
auto &
Info : Records) {
2780 Info.LiveSet.remove_if([&](
Value *LiveV) {
2781 assert(PointerToBase.count(LiveV) &&
"Missed base for derived pointer");
2782 return isa<Constant>(PointerToBase[LiveV]);
2787 CI->eraseFromParent();
2792 RematCandTy RematerizationCandidates;
2801 for (
size_t i = 0; i < Records.size(); i++)
2803 RematerizationCandidates,
TTI);
2808 std::vector<DeferredReplacement> Replacements;
2816 for (
size_t i = 0; i < Records.size(); i++)
2818 PointerToBase, GC.get());
2822 for (
auto &PR : Replacements)
2825 Replacements.clear();
2827 for (
auto &
Info : Records) {
2836 Info.LiveSet.clear();
2838 PointerToBase.clear();
2842 for (
const PartiallyConstructedSafepointRecord &
Info : Records) {
2855 "statepoint must be reachable or liveness is meaningless");
2856 for (
Value *V :
Info.StatepointToken->gc_live()) {
2857 if (!isa<Instruction>(V))
2860 auto *LiveInst = cast<Instruction>(V);
2862 "unreachable values should never be live");
2864 "basic SSA liveness expectation violated by liveness analysis");
2874 "must be a gc pointer type");
2878 return !Records.empty();
2886 R.addAttribute(Attribute::Dereferenceable);
2887 R.addAttribute(Attribute::DereferenceableOrNull);
2888 R.addAttribute(Attribute::ReadNone);
2889 R.addAttribute(Attribute::ReadOnly);
2890 R.addAttribute(Attribute::WriteOnly);
2891 R.addAttribute(Attribute::NoAlias);
2892 R.addAttribute(Attribute::NoFree);
2911 if (isa<PointerType>(
A.getType()))
2912 F.removeParamAttrs(
A.getArgNo(), R);
2914 if (isa<PointerType>(
F.getReturnType()))
2915 F.removeRetAttrs(R);
2918 F.removeFnAttr(Attr);
2925 if (!isa<LoadInst>(
I) && !isa<StoreInst>(
I))
2940 unsigned ValidMetadataAfterRS4GC[] = {LLVMContext::MD_tbaa,
2941 LLVMContext::MD_range,
2942 LLVMContext::MD_alias_scope,
2943 LLVMContext::MD_nontemporal,
2944 LLVMContext::MD_nonnull,
2945 LLVMContext::MD_align,
2946 LLVMContext::MD_type};
2949 I.dropUnknownNonDebugMetadata(ValidMetadataAfterRS4GC);
2970 if (
auto *
II = dyn_cast<IntrinsicInst>(&
I))
2971 if (
II->getIntrinsicID() == Intrinsic::invariant_start) {
2976 if (
MDNode *
Tag =
I.getMetadata(LLVMContext::MD_tbaa)) {
2978 I.setMetadata(LLVMContext::MD_tbaa, MutableTBAA);
2984 if (
auto *Call = dyn_cast<CallBase>(&
I)) {
2985 for (
int i = 0, e = Call->arg_size(); i != e; i++)
2986 if (isa<PointerType>(Call->getArgOperand(i)->getType()))
2987 Call->removeParamAttrs(i, R);
2988 if (isa<PointerType>(Call->getType()))
2989 Call->removeRetAttrs(R);
2994 for (
auto *
II : InvariantStartInstructions) {
2996 II->eraseFromParent();
3017 assert(Strategy &&
"GC strategy is required by function, but was not found");
3019 return Strategy->useRS4GC();
3037 assert(!
F.isDeclaration() && !
F.empty() &&
3038 "need function body to rewrite statepoints in");
3042 if (
const auto *Call = dyn_cast<CallBase>(&
I)) {
3043 if (isa<GCStatepointInst>(Call))
3056 assert((isa<AtomicMemCpyInst>(Call) || isa<AtomicMemMoveInst>(Call)) &&
3057 "Don't expect any other calls here!");
3080 if (NeedsRewrite(
I)) {
3086 "no unreachable blocks expected");
3087 ParsePointNeeded.
push_back(cast<CallBase>(&
I));
3089 if (
auto *CI = dyn_cast<CallInst>(&
I))
3090 if (CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_base ||
3091 CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_offset)
3096 if (ParsePointNeeded.
empty() && Intrinsics.
empty())
3104 if (BB.getUniquePredecessor())
3121 if (
auto *BI = dyn_cast<BranchInst>(TI))
3122 if (BI->isConditional())
3123 return dyn_cast<Instruction>(BI->getCondition());
3129 if (
auto *
Cond = getConditionInst(TI))
3132 if (isa<ICmpInst>(
Cond) &&
Cond->hasOneUse()) {
3134 Cond->moveBefore(TI);
3144 if (!isa<GetElementPtrInst>(
I))
3148 for (
unsigned i = 0; i <
I.getNumOperands(); i++)
3149 if (
auto *OpndVTy = dyn_cast<VectorType>(
I.getOperand(i)->getType())) {
3152 VF = cast<FixedVectorType>(OpndVTy)->getNumElements();
3157 if (!
I.getOperand(0)->getType()->isVectorTy() && VF != 0) {
3159 auto *
Splat =
B.CreateVectorSplat(VF,
I.getOperand(0));
3169 DefiningValueMapTy DVCache;
3173 IsKnownBaseMapTy KnownBases;
3175 if (!Intrinsics.
empty())
3180 if (!ParsePointNeeded.
empty())
3204 if (isa<PHINode>(
I))
3208 for (
Value *V :
I.operands()) {
3210 "support for FCA unimplemented");
3231 for (
auto &
I : *Succ) {
3232 PHINode *PN = dyn_cast<PHINode>(&
I);
3238 "support for FCA unimplemented");
3259 if (
auto *
I = dyn_cast<Instruction>(V)) {
3263 if (TermOkay && TI ==
I)
3266 "basic SSA liveness expectation violated by liveness analysis");
3289 Data.LiveSet[&BB].clear();
3294 assert(!
Data.LiveSet[&BB].count(Kill) &&
"live set contains kill");
3299 Data.LiveIn[&BB] =
Data.LiveSet[&BB];
3300 Data.LiveIn[&BB].set_union(
Data.LiveOut[&BB]);
3301 Data.LiveIn[&BB].set_subtract(
Data.KillSet[&BB]);
3302 if (!
Data.LiveIn[&BB].empty())
3307 while (!Worklist.
empty()) {
3313 const auto OldLiveOutSize = LiveOut.
size();
3319 if (OldLiveOutSize == LiveOut.
size()) {
3325 Data.LiveOut[BB] = LiveOut;
3335 if (OldLiveIn.
size() != LiveTmp.
size()) {
3336 Data.LiveIn[BB] = LiveTmp;
3364 Out.insert(LiveOut.
begin(), LiveOut.
end());
3369 PartiallyConstructedSafepointRecord &
Info,
3370 PointerToBaseTy &PointerToBase,
3372 StatepointLiveSetTy Updated;
3377 for (
auto *V : Updated)
3378 PointerToBase.insert({ V, V });
3380 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
Module.h This file contains the declarations for the Module class.
This file implements a map that provides insertion order iteration.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
const SmallVectorImpl< MachineOperand > & Cond
Remove Loads Into Fake Uses
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 attributes for this call.
AttributeList getAttributes() const
Return the 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 * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
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.
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...
Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
AttributeList getAttributes(LLVMContext &C, ID id)
Return the attributes for an intrinsic.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
This is an optimization pass for GlobalISel generic memory operations.
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 pred_end(const MachineBasicBlock *BB)
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.
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...
auto pred_begin(const MachineBasicBlock *BB)
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