passes: mark alloca live when its address is used
When a stack slot's address is taken, it could potentially be
live any point after it. It could also be initialized
"indirectly", like
tmp = phi(&a, &b)
*tmp = ...
In this case we didn't see the initialization of either a or b.
But the slot needs to be live. This CL fixes this.
The slot could also be initialized some time later (after a few
statepoints), or never. We don't know for sure. So we need to
pre-zero it, if we don't otherwise know it is initialized.
Also some minor cleanup:
- no need to add pointerless allocas into AddrTakenAllocas.
- delete an unused function (only relevant for relocations).
Change-Id: I44fdb4fb08883bffd51e125aabd6421cbec820e8
Reviewed-on: https://go-review.googlesource.com/c/155761
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/passes/GoStatepoints.cpp b/passes/GoStatepoints.cpp
index 20ee31c..6b22e10 100644
--- a/passes/GoStatepoints.cpp
+++ b/passes/GoStatepoints.cpp
@@ -1588,35 +1588,6 @@
}
}
-// Helper function for the "rematerializeLiveValues". It walks use chain
-// starting from the "CurrentValue" until it reaches the root of the chain, i.e.
-// the base or a value it cannot process. Only "simple" values are processed
-// (currently it is GEP's and casts). The returned root is examined by the
-// callers of findRematerializableChainToBasePointer. Fills "ChainToBase" array
-// with all visited values.
-static Value* findRematerializableChainToBasePointer(
- SmallVectorImpl<Instruction*> &ChainToBase,
- Value *CurrentValue) {
- if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(CurrentValue)) {
- ChainToBase.push_back(GEP);
- return findRematerializableChainToBasePointer(ChainToBase,
- GEP->getPointerOperand());
- }
-
- if (CastInst *CI = dyn_cast<CastInst>(CurrentValue)) {
- if (!CI->isNoopCast(CI->getModule()->getDataLayout()))
- return CI;
-
- ChainToBase.push_back(CI);
- return findRematerializableChainToBasePointer(ChainToBase,
- CI->getOperand(0));
- }
-
- // We have reached the root of the chain, which is either equal to the base or
- // is the first unsupported value along the use chain.
- return CurrentValue;
-}
-
static void
zeroAmbiguouslyLiveSlots(Function &F, SetVector<Value *> &ToZero,
SetVector<Value *> &AddrTakenAllocas) {
@@ -2318,13 +2289,17 @@
// Determine whether an alloca has its address taken.
// We use different mechanisms to track the liveness of
// address-taken and non-address-taken allocas.
+// Also keep track the location where the address is used.
+// The alloca needs to be live where its address is taken.
static void
determineAllocaAddrTaken(Function &F,
SetVector<Value *> &AddrTakenAllocas,
+ MapVector<BasicBlock *, SetVector<Value *>> &AllocaAddrUse,
DefiningValueMapTy &DVCache) {
// Use the metadata inserted by the FE.
for (Instruction &I : F.getEntryBlock())
- if (isa<AllocaInst>(I) && I.getMetadata("go_addrtaken"))
+ if (isa<AllocaInst>(I) && I.getMetadata("go_addrtaken") &&
+ hasPointer(I.getType()->getPointerElementType()))
AddrTakenAllocas.insert(&I);
// The FE's addrtaken mark may be imprecise. Look for certain
@@ -2345,8 +2320,10 @@
for (Value *V : I.operands()) {
if (!isHandledGCPointerType(V->getType()))
continue;
- if (Value *Base = isTrackedAlloca(V, DVCache))
+ if (Value *Base = isTrackedAlloca(V, DVCache)) {
AddrTakenAllocas.insert(Base);
+ AllocaAddrUse[I.getParent()].insert(Base);
+ }
}
else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
// If the address of a slot is stored, it must be addrtaken.
@@ -2355,8 +2332,10 @@
// TODO: maybe we should fix the FE?
Value *V = SI->getValueOperand();
if (isHandledGCPointerType(V->getType()))
- if (Value *Base = isTrackedAlloca(V, DVCache))
+ if (Value *Base = isTrackedAlloca(V, DVCache)) {
AddrTakenAllocas.insert(Base);
+ AllocaAddrUse[I.getParent()].insert(Base);
+ }
}
}
}
@@ -2521,9 +2500,8 @@
SetVector<Value *> &ToZero,
SetVector<Value *> &BadLoads,
DefiningValueMapTy &DVCache) {
- SmallSetVector<BasicBlock *, 32> Worklist;
-
- determineAllocaAddrTaken(F, AddrTakenAllocas, DVCache);
+ MapVector<BasicBlock *, SetVector<Value *>> AllocaAddrUse;
+ determineAllocaAddrTaken(F, AddrTakenAllocas, AllocaAddrUse, DVCache);
if (PrintLiveSet) {
dbgs() << "AddrTakenAllocas:\n";
printLiveSet(AddrTakenAllocas);
@@ -2546,8 +2524,9 @@
#endif
}
- // Propagate Alloca def any/all until stable.
+ // Propagate Alloca def any until stable.
bool changed = true;
+again:
while (changed) {
changed = false;
for (BasicBlock &BB : F) {
@@ -2559,6 +2538,31 @@
changed = true;
}
}
+
+ // When a slot's address is taken, it can be live any point after it.
+ // It can also be initialized "indirectly", like
+ // tmp = phi(&a, &b)
+ // *tmp = ...
+ // computeAllocaDefs doesn't see this initialization.
+ // It can be initialized some time later, or never. We don't know for
+ // sure. The slot needs to be live. And we need to pre-zero it, if we
+ // don't otherwise know it is initialized.
+ if (!AllocaAddrUse.empty()) {
+ for (BasicBlock &BB : F) {
+ AllocaAddrUse[&BB].set_subtract(Data.AllocaKillSet[&BB]);
+ for (Value *V : AllocaAddrUse[&BB])
+ if (!Data.AllocaDefAny[&BB].count(V)) {
+ Data.AllocaDefAny[&BB].insert(V);
+ ToZero.insert(V);
+ changed = true;
+ }
+ }
+ AllocaAddrUse.clear();
+ if (changed)
+ goto again; // re-propagate alloca def any
+ }
+
+ // Propagate Alloca def all until stable.
for (BasicBlock &BB : F)
Data.AllocaDefAll[&BB] = Data.AllocaDefAny[&BB];
changed = true;
@@ -2610,6 +2614,7 @@
}
}
+ SmallSetVector<BasicBlock *, 32> Worklist;
for (BasicBlock &BB : F) {
Data.LiveIn[&BB] = Data.LiveSet[&BB];
Data.LiveIn[&BB].set_union(Data.LiveOut[&BB]);