Files
swift-mirror/lib/SIL/SILArgument.cpp
Michael Gottesman 4cb9eb72f4 [rc-id] Ensure that the reforming enum analysis properly handles no-payload incoming values.
One common problem in swift code is the "reforming enum problem". What
happens here is that we have some enum %0 : $Optional<T> and we break it
apart and reform it as a new enum as in the following:

   bb9:
     ...
     switch_enum %0 : $Optional<T>, #Optional.None: bb10,
                                    #Optional.Some: bb11

   bb10:
     %1 = enum $Optional<U>, #Optional.None
     br bb12(%1 : $Optional<U>)

   bb11:
     %2 = some_cast_to_u %0 : ...
     %3 = enum $Optional<U>, #Optional.Some, %2 : $U
     br bb12(%3 : $Optional<U>)

   bb12(%4 : $Optional<U>):
     retain_value %0 : $Optional<T> // id %5
     release_value %4 : $Optional<U> // id %6

We really would like to know that a retain on %4 is equivalent to a
retain on %0 so we can eliminate the retain, release pair. To be able to
do that safely, we need to know that along all paths %0 and %4 either:

1. Both refer to the same RCIdentity directly. An example of this is the
edge from bb11 -> bb12).
2. Both refer to the "null" RCIdentity (i.e. do not have a payload). An
example of this is the edge from bb10 -> bb12.

Only in such cases is it safe to match up %5, %6 and eliminate them. If
this is not true along all paths like in the following:

   bb9:
     ...
     cond_br %foo, bb10, bb11

   bb10:
     %1 = enum $Optional<U>, #Optional.None
     br bb12(%1 : $Optional<U>)

   bb11:
     %2 = some_cast_to_u %0 : ...
     %3 = enum $Optional<U>, #Optional.Some, %2 : $U
     br bb12(%3 : $Optional<U>)

   bb12(%4 : $Optional<U>):
     retain_value %0 : $Optional<T> // id %5
     release_value %4 : $Optional<U> // id %6

then we may have that %0 is always non-payloaded coming into bb12. Then
by matching up %0 and %4, if we go from bb9 -> bb11, we will lose a
retain.

Perf Changes:

TITLE..................OLD...........NEW...........NEW/OLD
LevenshteinDistance....1398195.00....1177397.00....0.84
Memset.................26541.00......23701.00......0.89
CaptureProp............5603.00.......5031.00.......0.90
ImageProc..............1281.00.......1196.00.......0.93
InsertionSort..........109828.00.....104129.00.....0.95
StringWalk.............6813.00.......7456.00.......1.09
Chars..................27182.00......30443.00......1.12

The StringWalk, Chars are both reproducible for me. When I turn back on parts of
the recursion (I took the recursion out to make this change more conservative),
the Chars regression goes away, but the StringWalk stays. I have not had a
chance to look at what is going on with StringWalk.

rdar://19724405

Swift SVN r25339
2015-02-17 01:30:19 +00:00

233 lines
6.7 KiB
C++

//===--- SILArgument.cpp - Arguments for high-level SIL code ---------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
using namespace swift;
//===----------------------------------------------------------------------===//
// SILArgument Implementation
//===----------------------------------------------------------------------===//
SILArgument::SILArgument(SILBasicBlock *ParentBB, SILType Ty,
const ValueDecl *D)
: ValueBase(ValueKind::SILArgument, Ty), ParentBB(ParentBB), Decl(D) {
// Function arguments need to have a decl.
assert(
!ParentBB->getParent()->isBare() &&
ParentBB->getParent()->size() == 1
? D != nullptr
: true );
ParentBB->insertArgument(ParentBB->bbarg_end(), this);
}
SILArgument::SILArgument(SILBasicBlock *ParentBB,
SILBasicBlock::bbarg_iterator Pos,
SILType Ty, const ValueDecl *D)
: ValueBase(ValueKind::SILArgument, Ty), ParentBB(ParentBB), Decl(D) {
// Function arguments need to have a decl.
assert(
!ParentBB->getParent()->isBare() &&
ParentBB->getParent()->size() == 1
? D != nullptr
: true );
ParentBB->insertArgument(Pos, this);
}
SILFunction *SILArgument::getFunction() {
return getParent()->getParent();
}
const SILFunction *SILArgument::getFunction() const {
return getParent()->getParent();
}
SILModule &SILArgument::getModule() const {
return getFunction()->getModule();
}
bool SILArgument::getIncomingValues(llvm::SmallVectorImpl<SILValue> &OutArray) {
SILBasicBlock *Parent = getParent();
if (Parent->pred_empty())
return false;
unsigned Index = getIndex();
for (SILBasicBlock *Pred : getParent()->getPreds()) {
TermInst *TI = Pred->getTerminator();
if (auto *BI = dyn_cast<BranchInst>(TI)) {
OutArray.push_back(BI->getArg(Index));
continue;
}
if (auto *CBI = dyn_cast<CondBranchInst>(TI)) {
OutArray.push_back(CBI->getArgForDestBB(getParent(), this));
continue;
}
if (auto *CCBI = dyn_cast<CheckedCastBranchInst>(TI)) {
OutArray.push_back(CCBI->getOperand());
continue;
}
if (auto *SWEI = dyn_cast<SwitchEnumInst>(TI)) {
OutArray.push_back(SWEI->getOperand());
continue;
}
return false;
}
return true;
}
bool SILArgument::getIncomingValues(
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray) {
SILBasicBlock *Parent = getParent();
if (Parent->pred_empty())
return false;
unsigned Index = getIndex();
for (SILBasicBlock *Pred : getParent()->getPreds()) {
TermInst *TI = Pred->getTerminator();
if (auto *BI = dyn_cast<BranchInst>(TI)) {
OutArray.push_back({Pred, BI->getArg(Index)});
continue;
}
if (auto *CBI = dyn_cast<CondBranchInst>(TI)) {
OutArray.push_back({Pred, CBI->getArgForDestBB(getParent(), this)});
continue;
}
if (auto *CCBI = dyn_cast<CheckedCastBranchInst>(TI)) {
OutArray.push_back({Pred, CCBI->getOperand()});
continue;
}
if (auto *SWEI = dyn_cast<SwitchEnumInst>(TI)) {
OutArray.push_back({Pred, SWEI->getOperand()});
continue;
}
return false;
}
return true;
}
SILValue SILArgument::getIncomingValue(unsigned BBIndex) {
SILBasicBlock *Parent = getParent();
if (Parent->pred_empty())
return SILValue();
unsigned Index = getIndex();
// We could do an early check if the size of the pred list is <= BBIndex, but
// that would involve walking the linked list anyways, so we just iterate once
// over the loop.
// We use this funky loop since predecessors are stored in a linked list but
// we want array like semantics.
unsigned BBCount = 0;
for (SILBasicBlock *Pred : Parent->getPreds()) {
// If BBCount is not BBIndex, continue.
if (BBCount < BBIndex) {
BBCount++;
continue;
}
TermInst *TI = Pred->getTerminator();
if (auto *BI = dyn_cast<BranchInst>(TI))
return BI->getArg(Index);
if (auto *CBI = dyn_cast<CondBranchInst>(TI))
return CBI->getArgForDestBB(Parent, this);
if (auto *CCBI = dyn_cast<CheckedCastBranchInst>(TI))
return CCBI->getOperand();
if (auto *SWEI = dyn_cast<SwitchEnumInst>(TI))
return SWEI->getOperand();
// Return an empty SILValue since we ran into something we were unable to
// understand.
return SILValue();
}
return SILValue();
}
SILValue SILArgument::getIncomingValue(SILBasicBlock *BB) {
SILBasicBlock *Parent = getParent();
assert(!Parent->pred_empty() && "Passed in non-predecessor BB!");
unsigned Index = getIndex();
// We could do an early check if the size of the pred list is <= BBIndex, but
// that would involve walking the linked list anyways, so we just iterate once
// over the loop.
// We use this funky loop since predecessors are stored in a linked list but
// we want array like semantics.
for (SILBasicBlock *Pred : Parent->getPreds()) {
// If BBCount is not BBIndex, continue.
if (Pred != BB)
continue;
TermInst *TI = Pred->getTerminator();
if (auto *BI = dyn_cast<BranchInst>(TI))
return BI->getArg(Index);
if (auto *CBI = dyn_cast<CondBranchInst>(TI))
return CBI->getArgForDestBB(Parent, this);
if (auto *CCBI = dyn_cast<CheckedCastBranchInst>(TI))
return CCBI->getOperand();
if (auto *SWEI = dyn_cast<SwitchEnumInst>(TI))
return SWEI->getOperand();
// Return an empty SILValue since we ran into something we were unable to
// understand.
return SILValue();
}
return SILValue();
}
bool SILArgument::isSelf() const {
// First make sure that we are actually a function argument. We use an assert
// boolean return here since in release builds we want to conservatively
// return false and in debug builds assert since this is a logic error.
bool isArg = isFunctionArg();
assert(isArg && "Only function arguments can be self");
if (!isArg)
return false;
// Return true if we are the last argument of our BB and that our parent
// function has a call signature with self.
return getFunction()->hasSelfArgument() &&
getParent()->getBBArgs().back() == this;
}