76#define DEBUG_TYPE "rewrite-statepoints-for-gc"
96#ifdef EXPENSIVE_CHECKS
133 bool Changed =
false;
137 if (
F.isDeclaration() ||
F.empty())
166struct GCPtrLivenessData {
197using RematerializedValueMapTy =
200struct PartiallyConstructedSafepointRecord {
202 StatepointLiveSetTy LiveSet;
215 RematerializedValueMapTy RematerializedValues;
218struct RematerizlizationCandidateRecord {
231 std::optional<OperandBundleUse> DeoptBundle =
236 "Found non-leaf call without deopt info!");
240 return DeoptBundle->Inputs;
253 assert(GC &&
"GC Strategy for isGCPointerType cannot be null");
255 if (!isa<PointerType>(
T))
259 return GC->isGCManagedPointer(
T).value_or(
true);
272 if (
auto VT = dyn_cast<VectorType>(
T))
284 if (
VectorType *VT = dyn_cast<VectorType>(Ty))
286 if (
ArrayType *AT = dyn_cast<ArrayType>(Ty))
288 if (
StructType *ST = dyn_cast<StructType>(Ty))
290 [GC](
Type *Ty) { return containsGCPtrType(Ty, GC); });
306 return V->hasName() ? (V->getName() + Suffix).str() : DefaultName.
str();
315 PartiallyConstructedSafepointRecord &Result,
GCStrategy *GC) {
316 StatepointLiveSetTy LiveSet;
320 dbgs() <<
"Live Variables:\n";
321 for (
Value *V : LiveSet)
322 dbgs() <<
" " << V->getName() <<
" " << *V <<
"\n";
325 dbgs() <<
"Safepoint For: " << Call->getCalledOperand()->getName() <<
"\n";
326 dbgs() <<
"Number live values: " << LiveSet.size() <<
"\n";
328 Result.LiveSet = LiveSet;
337 IsKnownBaseMapTy &KnownBases);
340 IsKnownBaseMapTy &KnownBases);
352 IsKnownBaseMapTy &KnownBases) {
356 auto Cached = Cache.find(
I);
357 if (Cached != Cache.end())
358 return Cached->second;
360 if (isa<Argument>(
I)) {
367 if (isa<Constant>(
I)) {
376 if (isa<LoadInst>(
I)) {
382 if (isa<InsertElementInst>(
I)) {
391 if (isa<ShuffleVectorInst>(
I)) {
404 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(
I)) {
413 if (
auto *Freeze = dyn_cast<FreezeInst>(
I)) {
421 if (
auto *BC = dyn_cast<BitCastInst>(
I)) {
430 if (isa<CallInst>(
I) || isa<InvokeInst>(
I)) {
438 assert((isa<SelectInst>(
I) || isa<PHINode>(
I)) &&
439 "unknown vector instruction - no base found for vector element");
450 IsKnownBaseMapTy &KnownBases) {
451 assert(
I->getType()->isPtrOrPtrVectorTy() &&
452 "Illegal to ask for the base pointer of a non-pointer type");
453 auto Cached = Cache.find(
I);
454 if (Cached != Cache.end())
455 return Cached->second;
457 if (
I->getType()->isVectorTy())
460 if (isa<Argument>(
I)) {
468 if (isa<Constant>(
I)) {
490 if (isa<IntToPtrInst>(
I)) {
496 if (
CastInst *CI = dyn_cast<CastInst>(
I)) {
497 Value *Def = CI->stripPointerCasts();
500 assert(cast<PointerType>(Def->getType())->getAddressSpace() ==
501 cast<PointerType>(CI->getType())->getAddressSpace() &&
502 "unsupported addrspacecast");
506 assert(!isa<CastInst>(Def) &&
"shouldn't find another cast here");
512 if (isa<LoadInst>(
I)) {
527 if (
auto *Freeze = dyn_cast<FreezeInst>(
I)) {
534 switch (
II->getIntrinsicID()) {
538 case Intrinsic::experimental_gc_statepoint:
540 case Intrinsic::experimental_gc_relocate:
545 case Intrinsic::gcroot:
550 "interaction with the gcroot mechanism is not supported");
551 case Intrinsic::experimental_gc_get_pointer_base:
560 if (isa<CallInst>(
I) || isa<InvokeInst>(
I)) {
568 assert(!isa<LandingPadInst>(
I) &&
"Landing Pad is unimplemented");
570 if (isa<AtomicCmpXchgInst>(
I)) {
579 if (isa<AtomicRMWInst>(
I)) {
581 "Only Xchg is allowed for pointer values");
592 if (isa<ExtractValueInst>(
I)) {
600 assert(!isa<InsertValueInst>(
I) &&
601 "Base pointer for a struct is meaningless");
606 isa<Instruction>(
I) && cast<Instruction>(
I)->getMetadata(
"is_base_value");
614 if (isa<ExtractElementInst>(
I))
624 assert((isa<SelectInst>(
I) || isa<PHINode>(
I)) &&
625 "missing instruction case in findBaseDefiningValue");
631 IsKnownBaseMapTy &KnownBases) {
632 if (!Cache.contains(
I)) {
636 << Cache[
I]->getName() <<
", is known base = "
637 << KnownBases[
I] <<
"\n");
640 assert(KnownBases.contains(Cache[
I]) &&
641 "Cached value must be present in known bases map");
648 IsKnownBaseMapTy &KnownBases) {
650 auto Found = Cache.find(Def);
651 if (Found != Cache.end()) {
653 return Found->second;
664 return !isa<PHINode>(V) && !isa<SelectInst>(V) &&
665 !isa<ExtractElementInst>(V) && !isa<InsertElementInst>(V) &&
666 !isa<ShuffleVectorInst>(V);
671 auto It = KnownBases.find(V);
672 assert(It != KnownBases.end() &&
"Value not present in the map");
677 IsKnownBaseMapTy &KnownBases) {
679 auto It = KnownBases.find(V);
680 if (It != KnownBases.end())
681 assert(It->second == IsKnownBase &&
"Changing already present value");
683 KnownBases[V] = IsKnownBase;
688 return isa<VectorType>(
First->getType()) ==
689 isa<VectorType>(Second->
getType());
714 explicit BDVState(
Value *OriginalValue)
715 : OriginalValue(OriginalValue) {}
716 explicit BDVState(
Value *OriginalValue, StatusTy
Status,
Value *BaseValue =
nullptr)
717 : OriginalValue(OriginalValue),
Status(
Status), BaseValue(BaseValue) {
721 StatusTy getStatus()
const {
return Status; }
722 Value *getOriginalValue()
const {
return OriginalValue; }
723 Value *getBaseValue()
const {
return BaseValue; }
725 bool isBase()
const {
return getStatus() ==
Base; }
726 bool isUnknown()
const {
return getStatus() ==
Unknown; }
727 bool isConflict()
const {
return getStatus() == Conflict; }
732 void meet(
const BDVState &
Other) {
733 auto markConflict = [&]() {
734 Status = BDVState::Conflict;
743 BaseValue =
Other.getBaseValue();
747 assert(isBase() &&
"Unknown state");
749 if (
Other.isUnknown())
752 if (
Other.isConflict())
753 return markConflict();
757 if (getBaseValue() !=
Other.getBaseValue())
758 return markConflict();
763 return OriginalValue ==
Other.OriginalValue && BaseValue ==
Other.BaseValue &&
767 bool operator!=(
const BDVState &other)
const {
return !(*
this == other); }
776 switch (getStatus()) {
787 OS <<
" (base " << getBaseValue() <<
" - "
788 << (getBaseValue() ? getBaseValue()->getName() :
"nullptr") <<
")"
789 <<
" for " << OriginalValue->getName() <<
":";
812 IsKnownBaseMapTy &KnownBases) {
841 auto isExpectedBDVType = [](
Value *BDV) {
842 return isa<PHINode>(BDV) || isa<SelectInst>(BDV) ||
843 isa<ExtractElementInst>(BDV) || isa<InsertElementInst>(BDV) ||
844 isa<ShuffleVectorInst>(BDV);
856 auto VerifyStates = [&]() {
857 for (
auto &Entry : States) {
858 assert(Entry.first == Entry.second.getOriginalValue());
863 auto visitBDVOperands = [](
Value *BDV, std::function<void (
Value*)>
F) {
864 if (
PHINode *PN = dyn_cast<PHINode>(BDV)) {
865 for (
Value *InVal : PN->incoming_values())
867 }
else if (
SelectInst *SI = dyn_cast<SelectInst>(BDV)) {
868 F(SI->getTrueValue());
869 F(SI->getFalseValue());
870 }
else if (
auto *EE = dyn_cast<ExtractElementInst>(BDV)) {
871 F(EE->getVectorOperand());
872 }
else if (
auto *IE = dyn_cast<InsertElementInst>(BDV)) {
873 F(IE->getOperand(0));
874 F(IE->getOperand(1));
875 }
else if (
auto *SV = dyn_cast<ShuffleVectorInst>(BDV)) {
878 F(SV->getOperand(0));
879 if (!SV->isZeroEltSplat())
880 F(SV->getOperand(1));
892 States.
insert({Def, BDVState(Def)});
893 while (!Worklist.
empty()) {
897 auto visitIncomingValue = [&](
Value *InVal) {
906 assert(isExpectedBDVType(
Base) &&
"the only non-base values "
907 "we see should be base defining values");
912 visitBDVOperands(Current, visitIncomingValue);
919 for (
const auto &Pair : States) {
920 LLVM_DEBUG(
dbgs() <<
" " << Pair.second <<
" for " << *Pair.first <<
"\n");
932 for (
auto Pair : States) {
933 Value *BDV = Pair.first;
934 auto canPruneInput = [&](
Value *V) {
937 if (V->stripPointerCasts() == BDV)
940 if (V->stripPointerCasts() != VBDV)
944 return States.count(VBDV) == 0;
947 bool CanPrune =
true;
948 visitBDVOperands(BDV, [&](
Value *
Op) {
949 CanPrune = CanPrune && canPruneInput(
Op);
962 if (!States.
count(Def))
967 auto GetStateForBDV = [&](
Value *BaseValue,
Value *Input) {
968 auto I = States.
find(BaseValue);
969 if (
I != States.
end())
972 return BDVState(BaseValue, BDVState::Base, BaseValue);
995 if (isa<InsertElementInst>(
I) || isa<ExtractElementInst>(
I))
999 if (isa<ShuffleVectorInst>(
I))
1013 bool Progress =
true;
1016 const size_t OldSize = States.
size();
1023 for (
auto Pair : States) {
1024 Value *BDV = Pair.first;
1030 "why did it get added?");
1032 BDVState NewState(BDV);
1033 visitBDVOperands(BDV, [&](
Value *
Op) {
1035 auto OpState = GetStateForBDV(BDV,
Op);
1036 NewState.meet(OpState);
1042 auto I = cast<Instruction>(BDV);
1043 auto BV = NewState.getBaseValue();
1044 if (BV && MarkConflict(
I, BV))
1045 NewState = BDVState(
I, BDVState::Conflict);
1047 BDVState OldState = Pair.second;
1048 if (OldState != NewState) {
1050 States[BDV] = NewState;
1054 assert(OldSize == States.size() &&
1055 "fixed point shouldn't be adding any new nodes to state");
1061 for (
const auto &Pair : States) {
1062 LLVM_DEBUG(
dbgs() <<
" " << Pair.second <<
" for " << *Pair.first <<
"\n");
1067 for (
auto Pair : States) {
1069 BDVState State = Pair.second;
1070 auto *BaseValue = State.getBaseValue();
1076 "why did it get added?");
1077 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1083 for (
auto Pair : States) {
1085 BDVState State = Pair.second;
1091 "why did it get added?");
1092 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1097 assert(!isa<InsertElementInst>(
I) || State.isConflict());
1099 if (!State.isConflict())
1102 auto getMangledName = [](
Instruction *
I) -> std::string {
1103 if (isa<PHINode>(
I)) {
1105 }
else if (isa<SelectInst>(
I)) {
1107 }
else if (isa<ExtractElementInst>(
I)) {
1109 }
else if (isa<InsertElementInst>(
I)) {
1118 BaseInst->
setName(getMangledName(
I));
1121 States[
I] = BDVState(
I, BDVState::Conflict, BaseInst);
1140 if (
auto It = States.
find(BDV); It == States.
end()) {
1145 Base = It->second.getBaseValue();
1149 if (
Base->getType() != Input->
getType() && InsertPt)
1151 InsertPt->getIterator());
1158 for (
auto Pair : States) {
1160 BDVState State = Pair.second;
1167 "why did it get added?");
1168 assert(!State.isUnknown() &&
"Optimistic algorithm didn't complete!");
1169 if (!State.isConflict())
1172 if (
PHINode *BasePHI = dyn_cast<PHINode>(State.getBaseValue())) {
1173 PHINode *PN = cast<PHINode>(BDV);
1181 for (
unsigned i = 0; i < NumPHIValues; i++) {
1184 auto [It, Inserted] = BlockToValue.
try_emplace(InBB);
1189 Value *OldBase = It->second;
1190 Value *
Base = getBaseForInput(InVal,
nullptr);
1194 auto StripBitCasts = [](
Value *V) ->
Value * {
1195 while (
auto *BC = dyn_cast<BitCastInst>(V))
1196 V = BC->getOperand(0);
1205 assert(StripBitCasts(
Base) == StripBitCasts(OldBase) &&
1206 "findBaseOrBDV should be pure!");
1210 BasePHI->setIncomingValue(i,
Base);
1213 dyn_cast<SelectInst>(State.getBaseValue())) {
1218 BaseSI->setTrueValue(getBaseForInput(SI->getTrueValue(), BaseSI));
1219 BaseSI->setFalseValue(getBaseForInput(SI->getFalseValue(), BaseSI));
1220 }
else if (
auto *BaseEE =
1221 dyn_cast<ExtractElementInst>(State.getBaseValue())) {
1222 Value *InVal = cast<ExtractElementInst>(BDV)->getVectorOperand();
1225 BaseEE->setOperand(0, getBaseForInput(InVal, BaseEE));
1226 }
else if (
auto *BaseIE = dyn_cast<InsertElementInst>(State.getBaseValue())){
1227 auto *BdvIE = cast<InsertElementInst>(BDV);
1228 auto UpdateOperand = [&](
int OperandIdx) {
1229 Value *InVal = BdvIE->getOperand(OperandIdx);
1230 Value *
Base = getBaseForInput(InVal, BaseIE);
1231 BaseIE->setOperand(OperandIdx,
Base);
1236 auto *BaseSV = cast<ShuffleVectorInst>(State.getBaseValue());
1237 auto *BdvSV = cast<ShuffleVectorInst>(BDV);
1238 auto UpdateOperand = [&](
int OperandIdx) {
1239 Value *InVal = BdvSV->getOperand(OperandIdx);
1240 Value *
Base = getBaseForInput(InVal, BaseSV);
1241 BaseSV->setOperand(OperandIdx,
Base);
1244 if (!BdvSV->isZeroEltSplat())
1248 Value *InVal = BdvSV->getOperand(1);
1259 [[maybe_unused]]
auto &
DL =
1260 cast<llvm::Instruction>(Def)->getDataLayout();
1264 for (
auto Pair : States) {
1265 auto *BDV = Pair.first;
1266 Value *
Base = Pair.second.getBaseValue();
1271 DL.getTypeAllocSize(
Base->getType()) &&
1272 "Derived and base values should have same size");
1278 "why did it get added?");
1281 dbgs() <<
"Updating base value cache"
1282 <<
" for: " << BDV->
getName() <<
" from: "
1283 << (Cache.count(BDV) ? Cache[BDV]->getName().str() :
"none")
1284 <<
" to: " <<
Base->getName() <<
"\n");
1288 assert(Cache.count(Def));
1309 DefiningValueMapTy &DVCache,
1310 IsKnownBaseMapTy &KnownBases) {
1313 assert(base &&
"failed to find base pointer");
1314 PointerToBase[ptr] = base;
1315 assert((!isa<Instruction>(base) || !isa<Instruction>(ptr) ||
1316 DT->
dominates(cast<Instruction>(base)->getParent(),
1317 cast<Instruction>(ptr)->getParent())) &&
1318 "The base we found better dominate the derived pointer");
1326 PartiallyConstructedSafepointRecord &result,
1327 PointerToBaseTy &PointerToBase,
1328 IsKnownBaseMapTy &KnownBases) {
1329 StatepointLiveSetTy PotentiallyDerivedPointers = result.LiveSet;
1336 for (
Value *V : Opt->Inputs) {
1337 if (!PotentiallyDerivedPointers.count(V))
1339 PotentiallyDerivedPointers.remove(V);
1340 PointerToBase[V] = V;
1350 PartiallyConstructedSafepointRecord &result,
1351 PointerToBaseTy &PointerToBase,
1357 PointerToBaseTy &PointerToBase,
GCStrategy *GC) {
1360 GCPtrLivenessData RevisedLivenessData;
1362 for (
size_t i = 0; i < records.
size(); i++) {
1363 struct PartiallyConstructedSafepointRecord &
info = records[i];
1375 Value *AlternateLiveBase) {
1384 assert(isa<GetElementPtrInst>(Instr) || isa<CastInst>(Instr));
1388 ClonedValue->
setName(Instr->getName() +
".remat");
1392 if (LastClonedValue) {
1400 "incorrect use in rematerialization chain");
1403 assert(OpValue != RootOfChain && OpValue != AlternateLiveBase);
1412 if (RootOfChain != AlternateLiveBase)
1416 LastClonedValue = ClonedValue;
1420 return LastClonedValue;
1439 assert(!isa<PHINode>(Ret->begin()) &&
1440 "All PHI nodes should have been removed!");
1453 {Attribute::Memory, Attribute::NoSync, Attribute::NoFree};
1461 return StatepointAL;
1480 return StatepointAL;
1485 for (
unsigned I :
llvm::seq(Call->arg_size()))
1491 return StatepointAL;
1511 assert(ValIt != LiveVec.
end() &&
"Val not found in LiveVec!");
1512 size_t Index = std::distance(LiveVec.
begin(), ValIt);
1525 auto getGCRelocateDecl = [&](
Type *Ty) {
1527 auto AS = Ty->getScalarType()->getPointerAddressSpace();
1529 if (
auto *VT = dyn_cast<VectorType>(Ty))
1533 M, Intrinsic::experimental_gc_relocate, {NewTy});
1547 auto [It, Inserted] = TypeToDeclMap.
try_emplace(Ty);
1549 It->second = getGCRelocateDecl(Ty);
1550 Function *GCRelocateDecl = It->second;
1554 GCRelocateDecl, {StatepointToken, BaseIdx, LiveIdx},
1566class DeferredReplacement {
1569 bool IsDeoptimize =
false;
1571 DeferredReplacement() =
default;
1575 assert(Old != New && Old && New &&
1576 "Cannot RAUW equal values or to / from null!");
1578 DeferredReplacement
D;
1584 static DeferredReplacement createDelete(
Instruction *ToErase) {
1585 DeferredReplacement
D;
1590 static DeferredReplacement createDeoptimizeReplacement(
Instruction *Old) {
1592 auto *
F = cast<CallInst>(Old)->getCalledFunction();
1593 assert(
F &&
F->getIntrinsicID() == Intrinsic::experimental_deoptimize &&
1594 "Only way to construct a deoptimize deferred replacement");
1596 DeferredReplacement
D;
1598 D.IsDeoptimize =
true;
1603 void doReplacement() {
1607 assert(OldI != NewI &&
"Disallowed at construction?!");
1608 assert((!IsDeoptimize || !New) &&
1609 "Deoptimize intrinsics are not replaced!");
1620 auto *RI = cast<ReturnInst>(OldI->
getParent()->getTerminator());
1622 RI->eraseFromParent();
1632 const char *DeoptLowering =
"deopt-lowering";
1633 if (Call->hasFnAttr(DeoptLowering)) {
1639 Function *
F = Call->getCalledFunction();
1640 assert(
F &&
F->hasFnAttribute(DeoptLowering));
1641 return F->getFnAttribute(DeoptLowering).getValueAsString();
1643 return "live-through";
1650 PartiallyConstructedSafepointRecord &Result,
1651 std::vector<DeferredReplacement> &Replacements,
1652 const PointerToBaseTy &PointerToBase,
1668 std::optional<ArrayRef<Use>> DeoptArgs;
1670 DeoptArgs = Bundle->Inputs;
1671 std::optional<ArrayRef<Use>> TransitionArgs;
1673 TransitionArgs = Bundle->Inputs;
1681 bool IsDeoptimize =
false;
1682 bool IsMemIntrinsic =
false;
1693 if (DeoptLowering ==
"live-in")
1696 assert(DeoptLowering ==
"live-through" &&
"Unsupported value!");
1699 FunctionCallee CallTarget(Call->getFunctionType(), Call->getCalledOperand());
1701 auto IID =
F->getIntrinsicID();
1702 if (IID == Intrinsic::experimental_deoptimize) {
1708 for (
Value *Arg : CallArgs)
1717 CallTarget =
F->getParent()
1718 ->getOrInsertFunction(
"__llvm_deoptimize", FTy);
1720 IsDeoptimize =
true;
1721 }
else if (IID == Intrinsic::memcpy_element_unordered_atomic ||
1722 IID == Intrinsic::memmove_element_unordered_atomic) {
1723 IsMemIntrinsic =
true;
1741 auto &
Context = Call->getContext();
1742 auto &
DL = Call->getDataLayout();
1743 auto GetBaseAndOffset = [&](
Value *Derived) {
1749 if (isa<Constant>(Derived))
1753 assert(PointerToBase.count(Derived));
1754 Base = PointerToBase.find(Derived)->second;
1756 unsigned AddressSpace = Derived->getType()->getPointerAddressSpace();
1762 return std::make_pair(
Base, Builder.
CreateSub(Derived_int, Base_int));
1765 auto *Dest = CallArgs[0];
1766 Value *DestBase, *DestOffset;
1767 std::tie(DestBase, DestOffset) = GetBaseAndOffset(Dest);
1769 auto *Source = CallArgs[1];
1770 Value *SourceBase, *SourceOffset;
1771 std::tie(SourceBase, SourceOffset) = GetBaseAndOffset(Source);
1773 auto *LengthInBytes = CallArgs[2];
1774 auto *ElementSizeCI = cast<ConstantInt>(CallArgs[3]);
1784 for (
Value *Arg : CallArgs)
1790 uint64_t ElementSize = ElementSizeCI->getZExtValue();
1791 if (IID == Intrinsic::memcpy_element_unordered_atomic) {
1792 switch (ElementSize) {
1794 return "__llvm_memcpy_element_unordered_atomic_safepoint_1";
1796 return "__llvm_memcpy_element_unordered_atomic_safepoint_2";
1798 return "__llvm_memcpy_element_unordered_atomic_safepoint_4";
1800 return "__llvm_memcpy_element_unordered_atomic_safepoint_8";
1802 return "__llvm_memcpy_element_unordered_atomic_safepoint_16";
1807 assert(IID == Intrinsic::memmove_element_unordered_atomic);
1808 switch (ElementSize) {
1810 return "__llvm_memmove_element_unordered_atomic_safepoint_1";
1812 return "__llvm_memmove_element_unordered_atomic_safepoint_2";
1814 return "__llvm_memmove_element_unordered_atomic_safepoint_4";
1816 return "__llvm_memmove_element_unordered_atomic_safepoint_8";
1818 return "__llvm_memmove_element_unordered_atomic_safepoint_16";
1826 ->getOrInsertFunction(GetFunctionName(IID, ElementSizeCI), FTy);
1832 if (
auto *CI = dyn_cast<CallInst>(Call)) {
1834 StatepointID, NumPatchBytes, CallTarget, Flags, CallArgs,
1835 TransitionArgs, DeoptArgs, GCLive,
"safepoint_token");
1845 Token = cast<GCStatepointInst>(SPCall);
1849 assert(CI->getNextNode() &&
"Not a terminator, must have next!");
1853 auto *
II = cast<InvokeInst>(Call);
1859 StatepointID, NumPatchBytes, CallTarget,
II->getNormalDest(),
1860 II->getUnwindDest(), Flags, CallArgs, TransitionArgs, DeoptArgs,
1861 GCLive,
"statepoint_token");
1870 Token = cast<GCStatepointInst>(SPInvoke);
1876 "can't safely insert in this block!");
1883 Result.UnwindToken = ExceptionalToken;
1891 "can't safely insert in this block!");
1898 assert(Token &&
"Should be set in one of the above branches!");
1904 Replacements.push_back(
1905 DeferredReplacement::createDeoptimizeReplacement(Call));
1907 Token->
setName(
"statepoint_token");
1908 if (!Call->getType()->isVoidTy() && !Call->use_empty()) {
1913 Call->getAttributes().getRetAttrs()));
1921 Replacements.emplace_back(
1922 DeferredReplacement::createRAUW(Call, GCResult));
1924 Replacements.emplace_back(DeferredReplacement::createDelete(Call));
1928 Result.StatepointToken = Token;
1941 PartiallyConstructedSafepointRecord &Result,
1942 std::vector<DeferredReplacement> &Replacements,
1943 const PointerToBaseTy &PointerToBase,
GCStrategy *GC) {
1944 const auto &LiveSet = Result.LiveSet;
1948 LiveVec.
reserve(LiveSet.size());
1949 BaseVec.
reserve(LiveSet.size());
1950 for (
Value *L : LiveSet) {
1952 assert(PointerToBase.count(L));
1953 Value *
Base = PointerToBase.find(L)->second;
1973 for (
User *U : GCRelocs) {
1980 Value *Alloca = AllocaMap[OriginalValue];
1984 "Should always have one since it's not a terminator");
1988 VisitedLiveValues.
insert(OriginalValue);
1996 const RematerializedValueMapTy &RematerializedValues,
1999 for (
auto RematerializedValuePair: RematerializedValues) {
2000 Instruction *RematerializedValue = RematerializedValuePair.first;
2001 Value *OriginalValue = RematerializedValuePair.second;
2004 "Can not find alloca for rematerialized value");
2005 Value *Alloca = AllocaMap[OriginalValue];
2007 new StoreInst(RematerializedValue, Alloca,
2011 VisitedLiveValues.
insert(OriginalValue);
2023 int InitialAllocaNum = 0;
2025 if (isa<AllocaInst>(
I))
2033 std::size_t NumRematerializedValues = 0;
2039 auto emitAllocaFor = [&](
Value *LiveValue) {
2041 new AllocaInst(LiveValue->getType(),
DL.getAllocaAddrSpace(),
"",
2042 F.getEntryBlock().getFirstNonPHIIt());
2043 AllocaMap[LiveValue] = Alloca;
2052 for (
const auto &
Info : Records)
2053 for (
auto RematerializedValuePair :
Info.RematerializedValues) {
2054 Value *OriginalValue = RematerializedValuePair.second;
2055 if (AllocaMap.
contains(OriginalValue))
2058 emitAllocaFor(OriginalValue);
2059 ++NumRematerializedValues;
2071 for (
const auto &
Info : Records) {
2072 Value *Statepoint =
Info.StatepointToken;
2082 if (isa<InvokeInst>(Statepoint)) {
2098 for (
auto Pair : AllocaMap) {
2099 Value *Def = Pair.first;
2103 if (VisitedLiveValues.
count(Def)) {
2110 for (
auto *AI : ToClobber) {
2111 auto AT = AI->getAllocatedType();
2113 if (AT->isVectorTy())
2123 if (
auto II = dyn_cast<InvokeInst>(Statepoint)) {
2124 InsertClobbersAt(
II->getNormalDest()->getFirstInsertionPt());
2125 InsertClobbersAt(
II->getUnwindDest()->getFirstInsertionPt());
2128 std::next(cast<Instruction>(Statepoint)->getIterator()));
2134 for (
auto Pair : AllocaMap) {
2135 Value *Def = Pair.first;
2143 Uses.reserve(Def->getNumUses());
2144 for (
User *U : Def->users()) {
2145 if (!isa<ConstantExpr>(U)) {
2151 Uses.push_back(cast<Instruction>(U));
2160 if (isa<PHINode>(
Use)) {
2162 for (
unsigned i = 0; i < Phi->getNumIncomingValues(); i++) {
2163 if (Def == Phi->getIncomingValue(i)) {
2166 Phi->getIncomingBlock(i)->getTerminator()->getIterator());
2167 Phi->setIncomingValue(i, Load);
2172 Use->getIterator());
2173 Use->replaceUsesOfWith(Def, Load);
2181 DL.getABITypeAlign(Def->getType()));
2182 if (
Instruction *Inst = dyn_cast<Instruction>(Def)) {
2183 if (
InvokeInst *Invoke = dyn_cast<InvokeInst>(Inst)) {
2186 BasicBlock *NormalDest = Invoke->getNormalDest();
2189 assert(!Inst->isTerminator() &&
2190 "The only terminator that can produce a value is "
2191 "InvokeInst which is handled above.");
2192 Store->insertAfter(Inst->getIterator());
2195 assert(isa<Argument>(Def));
2196 Store->insertAfter(cast<Instruction>(Alloca)->getIterator());
2200 assert(PromotableAllocas.
size() ==
Live.size() + NumRematerializedValues &&
2201 "we must have the same allocas with lives");
2202 (void) NumRematerializedValues;
2203 if (!PromotableAllocas.
empty()) {
2209 for (
auto &
I :
F.getEntryBlock())
2210 if (isa<AllocaInst>(
I))
2212 assert(InitialAllocaNum == 0 &&
"We must not introduce any extra allocas");
2224 Module *M = Call->getModule();
2228 if (isa<CallInst>(Call)) {
2236 auto *
II = cast<InvokeInst>(Call);
2238 Func, Values,
"",
II->getNormalDest()->getFirstInsertionPt()));
2240 Func, Values,
"",
II->getUnwindDest()->getFirstInsertionPt()));
2247 GCPtrLivenessData OriginalLivenessData;
2249 for (
size_t i = 0; i < records.
size(); i++) {
2250 struct PartiallyConstructedSafepointRecord &
info = records[i];
2263 Value *CurrentValue) {
2267 GEP->getPointerOperand());
2270 if (
CastInst *CI = dyn_cast<CastInst>(CurrentValue)) {
2271 if (!CI->isNoopCast(CI->getDataLayout()))
2281 return CurrentValue;
2292 if (
CastInst *CI = dyn_cast<CastInst>(Instr)) {
2293 assert(CI->isNoopCast(CI->getDataLayout()) &&
2294 "non noop cast is found during rematerialization");
2296 Type *SrcTy = CI->getOperand(0)->getType();
2304 GEP->getType(),
nullptr,
nullptr,
2310 if (!
GEP->hasAllConstantIndices())
2329 for (
unsigned i = 0; i < PhiNum; i++)
2335 for (
unsigned i = 0; i < PhiNum; i++) {
2338 if (CIVI == CurrentIncomingValues.
end())
2340 BasicBlock *CurrentIncomingBB = CIVI->second;
2351 RematCandTy &RematerizationCandidates,
2353 const unsigned int ChainLengthThreshold = 10;
2355 for (
auto P2B : PointerToBase) {
2356 auto *Derived = P2B.first;
2357 auto *
Base = P2B.second;
2359 if (Derived ==
Base)
2364 Value *RootOfChain =
2368 if ( ChainToBase.
size() == 0 ||
2369 ChainToBase.
size() > ChainLengthThreshold)
2374 if (
Value *BaseVal = PointerToBase[Derived]; RootOfChain != BaseVal) {
2375 PHINode *OrigRootPhi = dyn_cast<PHINode>(RootOfChain);
2376 PHINode *AlternateRootPhi = dyn_cast<PHINode>(BaseVal);
2377 if (!OrigRootPhi || !AlternateRootPhi)
2399 RematerizlizationCandidateRecord
Record;
2400 Record.ChainToBase = ChainToBase;
2401 Record.RootOfChain = RootOfChain;
2403 RematerizationCandidates.insert({ Derived,
Record });
2412 RematCandTy &RematerizationCandidates,
2414 PointerToBaseTy &PointerToBase) {
2421 <<
"Num statepoints: " << Records.size() <<
'\n');
2423 for (
auto &It : RematerizationCandidates) {
2425 auto &
Record = It.second;
2435 if (U->getParent() == Cand->
getParent())
2440 [](
const auto *U) { return isa<PHINode>(U); }))
2452 Records, [Cand](
const auto &R) {
return R.LiveSet.contains(Cand); });
2455 LLVM_DEBUG(
dbgs() <<
"Num uses: " << NumUses <<
" Num live statepoints: "
2456 << NumLiveStatepoints <<
" ");
2458 if (NumLiveStatepoints < NumUses) {
2466 if (NumLiveStatepoints == NumUses &&
Record.Cost > 0) {
2478 if (
Record.ChainToBase.size() > 1) {
2479 Record.ChainToBase.clear();
2496 Record.RootOfChain, PointerToBase[Cand]);
2498 PointerToBase[RematChain] = PointerToBase[Cand];
2504 <<
" derived pointers\n");
2505 for (
auto *Cand : LiveValuesToBeDeleted) {
2506 assert(Cand->use_empty() &&
"Unexpected user remain");
2507 RematerizationCandidates.erase(Cand);
2508 for (
auto &R : Records) {
2509 assert(!R.LiveSet.contains(Cand) ||
2510 R.LiveSet.contains(PointerToBase[Cand]));
2511 R.LiveSet.remove(Cand);
2517 if (!LiveValuesToBeDeleted.
empty()) {
2518 for (
auto &
P : RematerizationCandidates) {
2520 if (R.ChainToBase.size() > 1) {
2521 R.ChainToBase.clear();
2533 PartiallyConstructedSafepointRecord &
Info,
2534 PointerToBaseTy &PointerToBase,
2535 RematCandTy &RematerizationCandidates,
2542 auto It = RematerizationCandidates.find(LiveValue);
2543 if (It == RematerizationCandidates.end())
2546 RematerizlizationCandidateRecord &
Record = It->second;
2551 if (isa<InvokeInst>(Call))
2559 LiveValuesToBeDeleted.
push_back(LiveValue);
2565 if (isa<CallInst>(Call)) {
2570 Record.RootOfChain, PointerToBase[LiveValue]);
2571 Info.RematerializedValues[RematerializedValue] = LiveValue;
2573 auto *Invoke = cast<InvokeInst>(Call);
2576 Invoke->getNormalDest()->getFirstInsertionPt();
2578 Invoke->getUnwindDest()->getFirstInsertionPt();
2582 Record.RootOfChain, PointerToBase[LiveValue]);
2585 Record.RootOfChain, PointerToBase[LiveValue]);
2587 Info.RematerializedValues[NormalRematerializedValue] = LiveValue;
2588 Info.RematerializedValues[UnwindRematerializedValue] = LiveValue;
2593 for (
auto *LiveValue: LiveValuesToBeDeleted) {
2594 Info.LiveSet.remove(LiveValue);
2600 DefiningValueMapTy &DVCache,
2601 IsKnownBaseMapTy &KnownBases) {
2603 auto &
DL =
F.getDataLayout();
2604 bool Changed =
false;
2606 for (
auto *Callsite : Intrinsics)
2607 switch (Callsite->getIntrinsicID()) {
2608 case Intrinsic::experimental_gc_get_pointer_base: {
2612 assert(!DVCache.count(Callsite));
2613 Callsite->replaceAllUsesWith(
Base);
2614 if (!
Base->hasName())
2615 Base->takeName(Callsite);
2616 Callsite->eraseFromParent();
2619 case Intrinsic::experimental_gc_get_pointer_offset: {
2621 Value *Derived = Callsite->getOperand(0);
2623 assert(!DVCache.count(Callsite));
2635 Offset->takeName(Callsite);
2636 Callsite->eraseFromParent();
2649 DefiningValueMapTy &DVCache,
2650 IsKnownBaseMapTy &KnownBases) {
2655 std::set<CallBase *> Uniqued;
2656 Uniqued.insert(ToUpdate.
begin(), ToUpdate.
end());
2657 assert(Uniqued.size() == ToUpdate.
size() &&
"no duplicates please!");
2660 assert(Call->getFunction() == &
F);
2668 auto *
II = dyn_cast<InvokeInst>(Call);
2688 "support for FCA unimplemented");
2703 PointerToBaseTy PointerToBase;
2706 for (
size_t i = 0; i < Records.size(); i++) {
2707 PartiallyConstructedSafepointRecord &
info = Records[i];
2711 errs() <<
"Base Pairs (w/o Relocation):\n";
2712 for (
auto &Pair : PointerToBase) {
2713 errs() <<
" derived ";
2714 Pair.first->printAsOperand(
errs(),
false);
2716 Pair.second->printAsOperand(
errs(),
false);
2736 for (
size_t i = 0; i < Records.size(); i++) {
2737 PartiallyConstructedSafepointRecord &
Info = Records[i];
2740 for (
auto *Derived :
Info.LiveSet) {
2741 assert(PointerToBase.count(Derived) &&
"Missed base for derived pointer");
2742 Bases.
push_back(PointerToBase[Derived]);
2754 errs() <<
"Base Pairs: (w/Relocation)\n";
2755 for (
auto Pair : PointerToBase) {
2756 errs() <<
" derived ";
2757 Pair.first->printAsOperand(
errs(),
false);
2759 Pair.second->printAsOperand(
errs(),
false);
2772 for (
auto &
Info : Records) {
2773 Info.LiveSet.remove_if([&](
Value *LiveV) {
2774 assert(PointerToBase.count(LiveV) &&
"Missed base for derived pointer");
2775 return isa<Constant>(PointerToBase[LiveV]);
2780 CI->eraseFromParent();
2785 RematCandTy RematerizationCandidates;
2794 for (
size_t i = 0; i < Records.size(); i++)
2796 RematerizationCandidates,
TTI);
2801 std::vector<DeferredReplacement> Replacements;
2809 for (
size_t i = 0; i < Records.size(); i++)
2811 PointerToBase, GC.get());
2815 for (
auto &PR : Replacements)
2818 Replacements.clear();
2820 for (
auto &
Info : Records) {
2829 Info.LiveSet.clear();
2831 PointerToBase.clear();
2837 for (
const PartiallyConstructedSafepointRecord &
Info : Records) {
2843 Live.insert_range(
Info.StatepointToken->gc_live());
2850 "statepoint must be reachable or liveness is meaningless");
2851 for (
Value *V :
Info.StatepointToken->gc_live()) {
2852 if (!isa<Instruction>(V))
2855 auto *LiveInst = cast<Instruction>(V);
2857 "unreachable values should never be live");
2859 "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<AnyMemTransferInst>(Call) &&
3051 cast<AnyMemTransferInst>(Call)->isAtomic() &&
3052 "Don't expect any other calls here!");
3075 if (NeedsRewrite(
I)) {
3081 "no unreachable blocks expected");
3082 ParsePointNeeded.
push_back(cast<CallBase>(&
I));
3084 if (
auto *CI = dyn_cast<CallInst>(&
I))
3085 if (CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_base ||
3086 CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_offset)
3091 if (ParsePointNeeded.
empty() && Intrinsics.
empty())
3099 if (BB.getUniquePredecessor())
3116 if (
auto *BI = dyn_cast<BranchInst>(TI))
3117 if (BI->isConditional())
3118 return dyn_cast<Instruction>(BI->getCondition());
3124 if (
auto *
Cond = getConditionInst(TI))
3127 if (isa<ICmpInst>(
Cond) &&
Cond->hasOneUse()) {
3139 if (!isa<GetElementPtrInst>(
I))
3143 for (
unsigned i = 0; i <
I.getNumOperands(); i++)
3144 if (
auto *OpndVTy = dyn_cast<VectorType>(
I.getOperand(i)->getType())) {
3147 VF = cast<FixedVectorType>(OpndVTy)->getNumElements();
3152 if (!
I.getOperand(0)->getType()->isVectorTy() && VF != 0) {
3154 auto *
Splat =
B.CreateVectorSplat(VF,
I.getOperand(0));
3164 DefiningValueMapTy DVCache;
3168 IsKnownBaseMapTy KnownBases;
3170 if (!Intrinsics.
empty())
3175 if (!ParsePointNeeded.
empty())
3199 if (isa<PHINode>(
I))
3203 for (
Value *V :
I.operands()) {
3205 "support for FCA unimplemented");
3226 for (
auto &
I : *Succ) {
3227 PHINode *PN = dyn_cast<PHINode>(&
I);
3233 "support for FCA unimplemented");
3254 if (
auto *
I = dyn_cast<Instruction>(V)) {
3258 if (TermOkay && TI ==
I)
3261 "basic SSA liveness expectation violated by liveness analysis");
3284 auto &LiveSet =
Data.LiveSet[&BB];
3290 assert(!
Data.LiveSet[&BB].count(Kill) &&
"live set contains kill");
3295 auto &In =
Data.LiveIn[&BB] =
Data.LiveSet[&BB];
3297 In.set_subtract(
Data.KillSet[&BB]);
3303 while (!Worklist.
empty()) {
3309 const auto OldLiveOutSize = LiveOut.
size();
3315 if (OldLiveOutSize == LiveOut.
size()) {
3330 if (LiveIn.
size() != LiveTmp.
size()) {
3331 LiveIn = std::move(LiveTmp);
3359 Out.insert_range(LiveOut);
3364 PartiallyConstructedSafepointRecord &
Info,
3365 PointerToBaseTy &PointerToBase,
3367 StatepointLiveSetTy Updated;
3372 for (
auto *V : Updated)
3373 PointerToBase.insert({ V, V });
3375 Info.LiveSet = Updated;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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 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 Instruction * rematerializeChain(ArrayRef< Instruction * > ChainToBase, BasicBlock::iterator InsertBefore, Value *RootOfChain, Value *AlternateLiveBase)
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...
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 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),...
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
Value handle that asserts if the Value is deleted.
LLVM_ABI AttrBuilder & removeAttribute(Attribute::AttrKind Val)
Remove an attribute from the builder.
LLVM_ABI AttributeSet getFnAttrs() const
The function attributes are returned.
static LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI const LandingPadInst * getLandingPadInst() const
Return the landingpad instruction associated with the landing pad.
LLVM_ABI 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()
LLVM_ABI InstListType::const_iterator getFirstNonPHIIt() const
Returns an iterator to the first instruction in this block that is not a PHINode instruction.
InstListType::reverse_iterator reverse_iterator
LLVM_ABI 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 LLVM_ABI ConstantAggregateZero * get(Type *Ty)
This is the shared class of boolean and integer constants.
static LLVM_ABI 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)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
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.
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
static LLVM_ABI 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 LLVM_ABI 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.
LLVM_ABI 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
LLVM_ABI 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)
LLVM_ABI 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.
LLVM_ABI 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...
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI 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.
LLVM_ABI 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 LLVM_ABI PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static LLVM_ABI 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.
PreservedAnalyses & 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.
void insert_range(Range &&R)
bool set_union(const STy &S)
Compute This := This u S, return whether 'This' changed.
bool empty() const
Determine if the SetVector is empty or not.
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.
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.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
This function has undefined behavior.
A Use represents the edge between a Value definition and its users.
LLVM_ABI 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()
LLVM_ABI 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.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVM_ABI User * getUniqueUndroppableUser()
Return true if there is exactly one unique user of this value that cannot be dropped (that user can h...
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
LLVM_ABI unsigned getNumUses() const
This method computes the number of uses of this Value.
LLVM_ABI 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...
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI AttributeList getAttributes(LLVMContext &C, ID id, FunctionType *FT)
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.
LLVM_ABI 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.
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.
auto reverse(ContainerTy &&C)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI 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.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVM_ABI 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.
LLVM_ABI 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...
LLVM_ABI std::unique_ptr< GCStrategy > getGCStrategy(const StringRef Name)
Lookup the GCStrategy object associated with the given gc name.
auto predecessors(const MachineBasicBlock *BB)
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.
LLVM_ABI bool removeUnreachableBlocks(Function &F, DomTreeUpdater *DTU=nullptr, MemorySSAUpdater *MSSAU=nullptr)
Remove all blocks that can not be reached from the function's entry.
LLVM_ABI 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