Changeset View
Changeset View
Standalone View
Standalone View
llvm/trunk/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
Show First 20 Lines • Show All 1,311 Lines • ▼ Show 20 Lines | static void CreateGCRelocates(ArrayRef<Value *> LiveVariables, | ||||
auto FindIndex = [](ArrayRef<Value *> LiveVec, Value *Val) { | auto FindIndex = [](ArrayRef<Value *> LiveVec, Value *Val) { | ||||
auto ValIt = std::find(LiveVec.begin(), LiveVec.end(), Val); | auto ValIt = std::find(LiveVec.begin(), LiveVec.end(), Val); | ||||
assert(ValIt != LiveVec.end() && "Val not found in LiveVec!"); | assert(ValIt != LiveVec.end() && "Val not found in LiveVec!"); | ||||
size_t Index = std::distance(LiveVec.begin(), ValIt); | size_t Index = std::distance(LiveVec.begin(), ValIt); | ||||
assert(Index < LiveVec.size() && "Bug in std::find?"); | assert(Index < LiveVec.size() && "Bug in std::find?"); | ||||
return Index; | return Index; | ||||
}; | }; | ||||
// All gc_relocate are set to i8 addrspace(1)* type. We originally generated | |||||
// unique declarations for each pointer type, but this proved problematic | |||||
// because the intrinsic mangling code is incomplete and fragile. Since | |||||
// we're moving towards a single unified pointer type anyways, we can just | |||||
// cast everything to an i8* of the right address space. A bitcast is added | |||||
// later to convert gc_relocate to the actual value's type. | |||||
Module *M = StatepointToken->getModule(); | Module *M = StatepointToken->getModule(); | ||||
auto AS = cast<PointerType>(LiveVariables[0]->getType())->getAddressSpace(); | |||||
Type *Types[] = {Type::getInt8PtrTy(M->getContext(), AS)}; | // All gc_relocate are generated as i8 addrspace(1)* (or a vector type whose | ||||
Value *GCRelocateDecl = | // element type is i8 addrspace(1)*). We originally generated unique | ||||
Intrinsic::getDeclaration(M, Intrinsic::experimental_gc_relocate, Types); | // declarations for each pointer type, but this proved problematic because | ||||
// the intrinsic mangling code is incomplete and fragile. Since we're moving | |||||
// towards a single unified pointer type anyways, we can just cast everything | |||||
// to an i8* of the right address space. A bitcast is added later to convert | |||||
// gc_relocate to the actual value's type. | |||||
auto getGCRelocateDecl = [&] (Type *Ty) { | |||||
assert(isHandledGCPointerType(Ty)); | |||||
auto AS = Ty->getScalarType()->getPointerAddressSpace(); | |||||
Type *NewTy = Type::getInt8PtrTy(M->getContext(), AS); | |||||
if (auto *VT = dyn_cast<VectorType>(Ty)) | |||||
NewTy = VectorType::get(NewTy, VT->getNumElements()); | |||||
return Intrinsic::getDeclaration(M, Intrinsic::experimental_gc_relocate, | |||||
{NewTy}); | |||||
}; | |||||
// Lazily populated map from input types to the canonicalized form mentioned | |||||
// in the comment above. This should probably be cached somewhere more | |||||
// broadly. | |||||
DenseMap<Type*, Value*> TypeToDeclMap; | |||||
for (unsigned i = 0; i < LiveVariables.size(); i++) { | for (unsigned i = 0; i < LiveVariables.size(); i++) { | ||||
// Generate the gc.relocate call and save the result | // Generate the gc.relocate call and save the result | ||||
Value *BaseIdx = | Value *BaseIdx = | ||||
Builder.getInt32(LiveStart + FindIndex(LiveVariables, BasePtrs[i])); | Builder.getInt32(LiveStart + FindIndex(LiveVariables, BasePtrs[i])); | ||||
Value *LiveIdx = Builder.getInt32(LiveStart + i); | Value *LiveIdx = Builder.getInt32(LiveStart + i); | ||||
Type *Ty = LiveVariables[i]->getType(); | |||||
if (!TypeToDeclMap.count(Ty)) | |||||
TypeToDeclMap[Ty] = getGCRelocateDecl(Ty); | |||||
Value *GCRelocateDecl = TypeToDeclMap[Ty]; | |||||
// only specify a debug name if we can give a useful one | // only specify a debug name if we can give a useful one | ||||
CallInst *Reloc = Builder.CreateCall( | CallInst *Reloc = Builder.CreateCall( | ||||
GCRelocateDecl, {StatepointToken, BaseIdx, LiveIdx}, | GCRelocateDecl, {StatepointToken, BaseIdx, LiveIdx}, | ||||
suffixed_name_or(LiveVariables[i], ".relocated", "")); | suffixed_name_or(LiveVariables[i], ".relocated", "")); | ||||
// Trick CodeGen into thinking there are lots of free registers at this | // Trick CodeGen into thinking there are lots of free registers at this | ||||
// fake call. | // fake call. | ||||
Reloc->setCallingConv(CallingConv::Cold); | Reloc->setCallingConv(CallingConv::Cold); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,126 Lines • ▼ Show 20 Lines | #ifndef NDEBUG | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
unique_unsorted(Live); | unique_unsorted(Live); | ||||
#ifndef NDEBUG | #ifndef NDEBUG | ||||
// sanity check | // sanity check | ||||
for (auto *Ptr : Live) | for (auto *Ptr : Live) | ||||
assert(isGCPointerType(Ptr->getType()) && "must be a gc pointer type"); | assert(isHandledGCPointerType(Ptr->getType()) && | ||||
"must be a gc pointer type"); | |||||
#endif | #endif | ||||
relocationViaAlloca(F, DT, Live, Records); | relocationViaAlloca(F, DT, Live, Records); | ||||
return !Records.empty(); | return !Records.empty(); | ||||
} | } | ||||
// Handles both return values and arguments for Functions and CallSites. | // Handles both return values and arguments for Functions and CallSites. | ||||
template <typename AttrHolder> | template <typename AttrHolder> | ||||
▲ Show 20 Lines • Show All 429 Lines • Show Last 20 Lines |