teach AllocBoxToStack to remove alloc_stack's that are artificial (or inlined)

and only stored to.  With this change, we now -emit-sil this testcase:

func f() {
 var a = 1
}

as:

sil @_T1t1fFT_T_ : $@thin () -> () {
bb0:
  %0 = tuple ()
  %1 = alloc_stack $Int64  // var a               // users: %8, %7
  %2 = metatype $Int64.metatype
  %3 = metatype $Int64.metatype
  %4 = module #Builtin
  %5 = integer_literal $Builtin.Int64, 1          // user: %6
  %6 = struct $Int64 (%5 : $Builtin.Int64)        // user: %7
  store %6 to %1#1 : $*Int64
  dealloc_stack %1#0 : $*@local_storage Int64
  %9 = tuple ()                                   // user: %10
  return %9 : $()
}



Swift SVN r9305
This commit is contained in:
Chris Lattner
2013-10-14 04:24:08 +00:00
parent 3d8e8d1e8f
commit 0d610cf952

View File

@@ -19,6 +19,7 @@
using namespace swift;
STATISTIC(NumStackPromoted, "Number of alloc_box's promoted to the stack");
STATISTIC(NumStackRemoved, "Number of variables removed completely");
//===----------------------------------------------------------------------===//
// alloc_box Promotion
@@ -250,12 +251,100 @@ static bool optimizeAllocBox(AllocBoxInst *ABI,
User->eraseFromParent();
}
return true;
}
//===----------------------------------------------------------------------===//
// Top Level Driver
// AllocStack Removal
//===----------------------------------------------------------------------===//
/// areAllocStackUsesSafeToRemove - Return true if there are no uses of the
/// specified address (or any pointers derived from it) that prevent us from
/// removing the allocation. For example, stores to the value can just be
/// discarded, but loads from the value require the memory to exist.
static bool areAllocStackUsesSafeToRemove(SILValue V) {
for (auto UI : V.getUses()) {
auto *User = cast<SILInstruction>(UI->getUser());
// Stores to the pointer (either in store or copy_addr form) can be
// discarded.
if ((isa<CopyAddrInst>(User) || isa<StoreInst>(User)) &&
UI->getOperandNumber() == 1)
continue;
// Zero initializations can be dropped.
if (isa<InitializeVarInst>(User))
continue;
// Recursively check uses of instructions that derive a pointer from the
// original pointer.
if (isa<StructElementAddrInst>(User) || isa<TupleElementAddrInst>(User) ||
isa<ProjectExistentialInst>(User)) {
if (!areAllocStackUsesSafeToRemove(SILValue(User, 0)))
return false;
continue;
}
// Otherwise, this is something we don't know about, conservatively keep the
// instruction
DEBUG(llvm::errs() << "*** Failed to remove autogenerated alloc_stack: "
"kept alive by: " << *User);
return false;
}
return true;
}
static void eraseUsesOfInstruction(SILInstruction *Inst) {
for (auto UI : Inst->getUses()) {
auto *User = cast<SILInstruction>(UI->getUser());
eraseUsesOfInstruction(User);
User->eraseFromParent();
}
}
/// optimizeAllocStack - Remove alloc_stack's the are only stored to, if they
/// are artificial allocations. We keep around normal allocations for debug
/// info generation to use.
static bool optimizeAllocStack(AllocStackInst *ASI) {
// We only look at (and try to remove) autogenerated allocations.
if (!ASI->getLoc().isAutoGenerated() &&
// FIXME: This is a temporary hack. The transparent inliner should set
// the autogenerated bit on inlined allocations.
!ASI->getLoc().is<InlinedLocation>())
return false;
// Walk the use list to see if we have only safe-to-remove uses hanging off
// of the allocation. Check the local_storage piece first.
for (auto UI : SILValue(ASI, 0).getUses()) {
auto *User = cast<SILInstruction>(UI->getUser());
if (isa<DeallocStackInst>(User))
continue;
// Otherwise, it was an instruction we can't handle.
DEBUG(llvm::errs() << "*** Failed to remove autogenerated alloc_stack: "
"kept alive by: " << *User);
return false;
}
// Next, check uses of the address.
if (!areAllocStackUsesSafeToRemove(SILValue(ASI, 1)))
return false;
DEBUG(llvm::errs() << "*** Removing autogenerated alloc_stack: " << *ASI);
// If it is safe to remove, do it. Recursively remove all instructions
// hanging off the alloc_stack, then return success.
eraseUsesOfInstruction(ASI);
return true;
}
//===----------------------------------------------------------------------===//
// Top Level Driver
//===----------------------------------------------------------------------===//
void swift::performSILAllocBoxToStackPromotion(SILModule *M) {
@@ -268,21 +357,25 @@ void swift::performSILAllocBoxToStackPromotion(SILModule *M) {
for (auto &BB : Fn) {
auto I = BB.begin(), E = BB.end();
while (I != E) {
auto *ABI = dyn_cast<AllocBoxInst>(I);
if (auto *ABI = dyn_cast<AllocBoxInst>(I))
if (optimizeAllocBox(ABI, PostDomInfo)) {
++NumStackPromoted;
// Carefully move iterator to avoid invalidation problems.
++I;
ABI->eraseFromParent();
continue;
}
if (!ABI) {
++I;
continue;
}
if (optimizeAllocBox(ABI, PostDomInfo)) {
++NumStackPromoted;
// Carefully move iterator to avoid invalidation problems.
++I;
ABI->eraseFromParent();
} else {
++I;
}
if (auto *ASI = dyn_cast<AllocStackInst>(I))
if (optimizeAllocStack(ASI)) {
++NumStackRemoved;
// Carefully move iterator to avoid invalidation problems.
++I;
ASI->eraseFromParent();
continue;
}
++I;
}
}
}