DenseMap<const Value *, unsigned> CatchPadExceptionPointers;
/// Keep track of frame indices allocated for statepoints as they could be
- /// used across basic block boundaries. Key of the map is statepoint
- /// instruction, value is a map from spilled llvm Value to the optional stack
- /// stack slot index. If optional is unspecified it means that we have
- /// visited this value but didn't spill it.
- typedef DenseMap<const Value*, Optional<int>> StatepointSpilledValueMapTy;
- DenseMap<const Instruction*, StatepointSpilledValueMapTy>
- StatepointRelocatedValues;
+ /// used across basic block boundaries. This struct is more complex than a
+ /// simple map because the stateopint lowering code de-duplicates gc pointers
+ /// based on their SDValue (so %p and (bitcast %p to T) will get the same
+ /// slot), and we track that here.
+
+ struct StatepointSpillMap {
+ typedef DenseMap<const Value *, Optional<int>> SlotMapTy;
+
+ /// Maps uniqued llvm IR values to the slots they were spilled in. If a
+ /// value is mapped to None it means we visited the value but didn't spill
+ /// it (because it was a constant, for instance).
+ SlotMapTy SlotMap;
+
+ /// Maps llvm IR values to the values they were de-duplicated to.
+ DenseMap<const Value *, const Value *> DuplicateMap;
+
+ SlotMapTy::const_iterator find(const Value *V) const {
+ auto DuplIt = DuplicateMap.find(V);
+ if (DuplIt != DuplicateMap.end())
+ V = DuplIt->second;
+ return SlotMap.find(V);
+ }
+
+ SlotMapTy::const_iterator end() const { return SlotMap.end(); }
+ };
+
+ /// Maps gc.statepoint instructions to their corresponding StatepointSpillMap
+ /// instances.
+ DenseMap<const Instruction *, StatepointSpillMap> StatepointSpillMaps;
/// StaticAllocaMap - Keep track of frame indices for fixed sized allocas in
/// the entry block. This allows the allocas to be efficiently referenced
// Spill location is known for gc relocates
if (const auto *Relocate = dyn_cast<GCRelocateInst>(Val)) {
const auto &SpillMap =
- Builder.FuncInfo.StatepointRelocatedValues[Relocate->getStatepoint()];
+ Builder.FuncInfo.StatepointSpillMaps[Relocate->getStatepoint()];
auto It = SpillMap.find(Relocate->getDerivedPtr());
if (It == SpillMap.end())
removeDuplicateGCPtrs(SmallVectorImpl<const Value *> &Bases,
SmallVectorImpl<const Value *> &Ptrs,
SmallVectorImpl<const GCRelocateInst *> &Relocs,
- SelectionDAGBuilder &Builder) {
-
- // This is horribly inefficient, but I don't care right now
- SmallSet<SDValue, 32> Seen;
+ SelectionDAGBuilder &Builder,
+ FunctionLoweringInfo::StatepointSpillMap &SSM) {
+ DenseMap<SDValue, const Value *> Seen;
SmallVector<const Value *, 64> NewBases, NewPtrs;
SmallVector<const GCRelocateInst *, 64> NewRelocs;
for (size_t i = 0, e = Ptrs.size(); i < e; i++) {
SDValue SD = Builder.getValue(Ptrs[i]);
- // Only add non-duplicates
- if (Seen.count(SD) == 0) {
+ auto SeenIt = Seen.find(SD);
+
+ if (SeenIt == Seen.end()) {
+ // Only add non-duplicates
NewBases.push_back(Bases[i]);
NewPtrs.push_back(Ptrs[i]);
NewRelocs.push_back(Relocs[i]);
+ Seen[SD] = Ptrs[i];
+ } else {
+ // Duplicate pointer found, note in SSM and move on:
+ SSM.DuplicateMap[Ptrs[i]] = SeenIt->second;
}
- Seen.insert(SD);
}
assert(Bases.size() >= NewBases.size());
assert(Ptrs.size() >= NewPtrs.size());
// This can not be embedded in lowering loops as we need to record *all*
// values, while previous loops account only values with unique SDValues.
const Instruction *StatepointInstr = SI.StatepointInstr;
- auto &SpillMap = Builder.FuncInfo.StatepointRelocatedValues[StatepointInstr];
+ auto &SpillMap = Builder.FuncInfo.StatepointSpillMaps[StatepointInstr];
for (const GCRelocateInst *Relocate : SI.GCRelocates) {
const Value *V = Relocate->getDerivedPtr();
SDValue Loc = Builder.StatepointLowering.getLocation(SDV);
if (Loc.getNode()) {
- SpillMap[V] = cast<FrameIndexSDNode>(Loc)->getIndex();
+ SpillMap.SlotMap[V] = cast<FrameIndexSDNode>(Loc)->getIndex();
} else {
// Record value as visited, but not spilled. This is case for allocas
// and constants. For this values we can avoid emitting spill load while
// Actually we do not need to record them in this map at all.
// We do this only to check that we are not relocating any unvisited
// value.
- SpillMap[V] = None;
+ SpillMap.SlotMap[V] = None;
// Default llvm mechanisms for exporting values which are used in
// different basic blocks does not work for gc relocates.
// input. Also has the effect of removing duplicates in the original
// llvm::Value input list as well. This is a useful optimization for
// reducing the size of the StackMap section. It has no other impact.
- removeDuplicateGCPtrs(SI.Bases, SI.Ptrs, SI.GCRelocates, *this);
+ removeDuplicateGCPtrs(SI.Bases, SI.Ptrs, SI.GCRelocates, *this,
+ FuncInfo.StatepointSpillMaps[SI.StatepointInstr]);
assert(SI.Bases.size() == SI.Ptrs.size() &&
SI.Ptrs.size() == SI.GCRelocates.size());
const Value *DerivedPtr = Relocate.getDerivedPtr();
SDValue SD = getValue(DerivedPtr);
- FunctionLoweringInfo::StatepointSpilledValueMapTy &SpillMap =
- FuncInfo.StatepointRelocatedValues[Relocate.getStatepoint()];
-
- // We should have recorded location for this pointer
- assert(SpillMap.count(DerivedPtr) && "Relocating not lowered gc value");
- Optional<int> DerivedPtrLocation = SpillMap[DerivedPtr];
+ auto &SpillMap = FuncInfo.StatepointSpillMaps[Relocate.getStatepoint()];
+ auto SlotIt = SpillMap.find(DerivedPtr);
+ assert(SlotIt != SpillMap.end() && "Relocating not lowered gc value");
+ Optional<int> DerivedPtrLocation = SlotIt->second;
// We didn't need to spill these special cases (constants and allocas).
// See the handling in spillIncomingValueForStatepoint for detail.
declare void @f()
declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) #3
+declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32) #3
-define void @test(i32 addrspace(1)* %ptr) gc "statepoint-example" {
-; CHECK-LABEL: test
+define void @test_gcrelocate_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" {
+; CHECK-LABEL: test_gcrelocate_uniqueing
%tok = tail call token (i64, i32, void ()*, i32, i32, ...)
@llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @f, i32 0, i32 0, i32 0, i32 2, i32 addrspace(1)* %ptr, i32 undef, i32 addrspace(1)* %ptr, i32 addrspace(1)* %ptr)
%a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 9, i32 9)
%b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 10, i32 10)
ret void
}
+
+define void @test_gcptr_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" {
+; CHECK-LABEL: test_gcptr_uniqueing
+ %ptr2 = bitcast i32 addrspace(1)* %ptr to i8 addrspace(1)*
+ %tok = tail call token (i64, i32, void ()*, i32, i32, ...)
+ @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @f, i32 0, i32 0, i32 0, i32 2, i32 addrspace(1)* %ptr, i32 undef, i32 addrspace(1)* %ptr, i8 addrspace(1)* %ptr2)
+ %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 9, i32 9)
+ %b = call i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %tok, i32 10, i32 10)
+ ret void
+}