Skip to content

Commit

Permalink
Revert "Reinstate "GenericSpecializer: When specializing a generic fu…
Browse files Browse the repository at this point in the history
…nction, convert indirect parameters/result to direct parameters/result."""

This reverts commit c556d5c.

Hitting a new assert.
  • Loading branch information
eeckstein committed Feb 25, 2016
1 parent 7606dd6 commit f70b53b
Show file tree
Hide file tree
Showing 18 changed files with 301 additions and 967 deletions.
17 changes: 7 additions & 10 deletions include/swift/SILOptimizer/Utils/GenericCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,37 @@
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/TypeSubstCloner.h"
#include "swift/SILOptimizer/Utils/Local.h"
#include "swift/SILOptimizer/Utils/Generics.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <functional>

namespace swift {

class GenericCloner : public TypeSubstCloner<GenericCloner> {
const ReabstractionInfo &ReInfo;
CloneCollector::CallbackType Callback;

public:
friend class SILCloner<GenericCloner>;

GenericCloner(SILFunction *F,
const ReabstractionInfo &ReInfo,
TypeSubstitutionMap &InterfaceSubs,
TypeSubstitutionMap &ContextSubs,
StringRef NewName,
ArrayRef<Substitution> ApplySubs,
CloneCollector::CallbackType Callback)
: TypeSubstCloner(*initCloned(F, ReInfo, NewName), *F, ContextSubs,
ApplySubs), ReInfo(ReInfo), Callback(Callback) {
: TypeSubstCloner(*initCloned(F, InterfaceSubs, NewName), *F, ContextSubs,
ApplySubs), Callback(Callback) {
assert(F->getDebugScope()->Parent != getCloned()->getDebugScope()->Parent);
}
/// Clone and remap the types in \p F according to the substitution
/// list in \p Subs. Parameters are re-abstracted (changed from indirect to
/// direct) according to \p ReInfo.
/// list in \p Subs.
static SILFunction *cloneFunction(SILFunction *F,
const ReabstractionInfo &ReInfo,
TypeSubstitutionMap &InterfaceSubs,
TypeSubstitutionMap &ContextSubs,
StringRef NewName, ApplySite Caller,
CloneCollector::CallbackType Callback =nullptr) {
// Clone and specialize the function.
GenericCloner SC(F, ReInfo, ContextSubs, NewName,
GenericCloner SC(F, InterfaceSubs, ContextSubs, NewName,
Caller.getSubstitutions(), Callback);
SC.populateCloned();
SC.cleanUp(SC.getCloned());
Expand All @@ -80,7 +77,7 @@ class GenericCloner : public TypeSubstCloner<GenericCloner> {

private:
static SILFunction *initCloned(SILFunction *Orig,
const ReabstractionInfo &ReInfo,
TypeSubstitutionMap &InterfaceSubs,
StringRef NewName);
/// Clone the body of the function into the empty function that was created
/// by initCloned.
Expand Down
106 changes: 5 additions & 101 deletions include/swift/SILOptimizer/Utils/Generics.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,118 +22,22 @@
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Utils/Local.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"

namespace swift {

/// Helper class to describe re-abstraction of function parameters done during
/// specialization.
///
/// Specifically, it contains information which parameters and returns are
/// changed from indirect values to direct values.
class ReabstractionInfo {
public:
/// Constructs the ReabstractionInfo for an apply site \p AI calling the
/// generic function \p Orig.
/// If specialization is not possible getSpecializedType() will return an
/// invalid type.
ReabstractionInfo(SILFunction *Orig, ApplySite AI);

/// Does the \p ArgIdx refer to an indirect out-parameter?
bool isResultIndex(unsigned ArgIdx) const {
assert(ArgIdx < Conversions.size());
return ArgIdx < NumResults;
}

/// Returns true if the \p ParamIdx'th (non-result) parameter is converted
/// from indirect to direct.
bool isParamConverted(unsigned ParamIdx) const {
return Conversions.test(ParamIdx + NumResults);
}

/// Returns true if the \p ResultIdx'th result is converted from indirect
/// to direct.
bool isResultConverted(unsigned ResultIdx) const {
assert(ResultIdx < NumResults);
return Conversions.test(ResultIdx);
}

/// Gets the total number of original function arguments.
unsigned getNumArguments() const { return Conversions.size(); }

/// Returns true if the \p ArgIdx'th argument is converted from an indirect
/// result or parameter to a direct result or parameter.
bool isArgConverted(unsigned ArgIdx) const {
return Conversions.test(ArgIdx);
}

/// Returns true if there are any conversions from indirect to direct values.
bool hasConversions() const { return Conversions.any(); }

/// Remove the arguments of a partial apply, leaving the arguments for the
/// partial apply result function.
void prunePartialApplyArgs(unsigned numPartialApplyArgs) {
assert(numPartialApplyArgs <= Conversions.size());
Conversions.resize(Conversions.size() - numPartialApplyArgs);
}

/// Returns the index of the first argument of an apply site, which may be
/// > 0 in case of a partial_apply.
unsigned getIndexOfFirstArg(ApplySite Apply) const {
unsigned numArgs = Apply.getNumArguments();
assert(numArgs == Conversions.size() || (numArgs < Conversions.size() &&
isa<PartialApplyInst>(Apply)));
return Conversions.size() - numArgs;
}

/// Get the function type after applying the substitutions of the original
/// apply site.
CanSILFunctionType getSubstitutedType() const { return SubstitutedType; }

/// Get the function type after applying the re-abstractions on the
/// substituted type. Returns an invalid type if specialization is not
/// possible.
CanSILFunctionType getSpecializedType() const { return SpecializedType; }

/// Create a specialized function type for a specific substituted type \p
/// SubstFTy by applying the re-abstractions.
CanSILFunctionType createSpecializedType(CanSILFunctionType SubstFTy,
SILModule &M) const;
private:
/// A 1-bit means that this parameter/return value is converted from indirect
/// to direct.
llvm::BitVector Conversions;

/// The first NumResults bits in Conversions refer to indirect out-parameters.
unsigned NumResults;

/// The function type after applying the substitutions of the original
/// apply site.
CanSILFunctionType SubstitutedType;

/// The function type after applying the re-abstractions on the
/// SubstitutedType.
CanSILFunctionType SpecializedType;
};

/// Tries to specialize an \p Apply of a generic function. It can be a full
/// apply site or a partial apply.
/// Replaced and now dead instructions are returned in \p DeadApplies.
/// New created functions, like the specialized callee and thunks, are returned
/// in \p NewFunctions.
void trySpecializeApplyOfGeneric(ApplySite Apply,
llvm::SmallVectorImpl<SILInstruction *> &DeadApplies,
llvm::SmallVectorImpl<SILFunction *> &NewFunctions);
ApplySite trySpecializeApplyOfGeneric(ApplySite Apply,
SILFunction *&NewFunction,
CloneCollector &Collector);

/// Checks if a given mangled name could be a name of a whitelisted specialization.
bool isWhitelistedSpecialization(StringRef SpecName);

/// Create a new apply based on an old one, but with a different
/// function being applied.
ApplySite replaceWithSpecializedFunction(ApplySite AI, SILFunction *NewF,
const ReabstractionInfo &ReInfo);
ApplySite replaceWithSpecializedFunction(ApplySite AI, SILFunction *NewF);

SILFunction *getExistingSpecialization(SILModule &M, StringRef FunctionName);

Expand Down
3 changes: 1 addition & 2 deletions lib/SIL/SILModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ SILFunction *SILModule::getOrCreateFunction(SILLocation loc,
SILFunction::ClassVisibility_t CV) {
if (auto fn = lookUpFunction(name)) {
assert(fn->getLoweredFunctionType() == type);
assert(fn->getLinkage() == linkage ||
stripExternalFromLinkage(fn->getLinkage()) == linkage);
assert(fn->getLinkage() == linkage);
return fn;
}

Expand Down
12 changes: 5 additions & 7 deletions lib/SILOptimizer/IPO/UsePrespecialized.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,13 @@ bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) {
if (Subs.empty())
continue;

ReabstractionInfo ReInfo(ReferencedF, AI);

auto SpecType = ReInfo.getSpecializedType();
if (!SpecType)
continue;
auto SubsFunctionType =
ReferencedF->getLoweredFunctionType()->substGenericArgs(M,
M.getSwiftModule(), Subs);

// Bail if any generic types parameters of the concrete type
// are unbound.
if (SpecType->hasArchetype())
if (SubsFunctionType->hasArchetype())
continue;

// Bail if any generic types parameters of the concrete type
Expand Down Expand Up @@ -130,7 +128,7 @@ bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) {
llvm::dbgs() << "Found a specialization of " << ReferencedF->getName()
<< " : " << NewF->getName() << "\n");

auto NewAI = replaceWithSpecializedFunction(AI, NewF, ReInfo);
auto NewAI = replaceWithSpecializedFunction(AI, NewF);
AI.getInstruction()->replaceAllUsesWith(NewAI.getInstruction());
recursivelyDeleteTriviallyDeadInstructions(AI.getInstruction(), true);
Changed = true;
Expand Down
36 changes: 27 additions & 9 deletions lib/SILOptimizer/Transforms/GenericSpecializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class GenericSpecializer : public SILFunctionTransform {
} // end anonymous namespace

bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
bool Changed = false;
llvm::SmallVector<SILInstruction *, 8> DeadApplies;

for (auto &BB : F) {
Expand All @@ -70,24 +71,41 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
// We have a call that can potentially be specialized, so
// attempt to do so.

llvm::SmallVector<SILFunction *, 2> NewFunctions;
trySpecializeApplyOfGeneric(Apply, DeadApplies, NewFunctions);
// The specializer helper function currently expects a collector
// argument, but we aren't going to make use of the results so
// we'll have our filter always return false;
auto Filter = [](SILInstruction *I) -> bool { return false; };
CloneCollector Collector(Filter);

SILFunction *SpecializedFunction;

auto Specialized =
trySpecializeApplyOfGeneric(Apply, SpecializedFunction, Collector);

if (Specialized) {
Changed = true;

// If calling the specialization utility resulted in new functions
// (as opposed to returning a previous specialization), we need to notify
// the pass manager so that the new functions get optimized.
for (SILFunction *NewF : reverse(NewFunctions)) {
notifyPassManagerOfFunction(NewF);
// If calling the specialization utility resulted in a new
// function (as opposed to returning a previous
// specialization), we need to notify the pass manager so that
// the new function gets optimized.
if (SpecializedFunction)
notifyPassManagerOfFunction(SpecializedFunction);

auto *AI = Apply.getInstruction();

if (!isa<TryApplyInst>(AI))
AI->replaceAllUsesWith(Specialized.getInstruction());

DeadApplies.push_back(AI);
}
}
}

// Remove all the now-dead applies.
bool Changed = false;
while (!DeadApplies.empty()) {
auto *AI = DeadApplies.pop_back_val();
recursivelyDeleteTriviallyDeadInstructions(AI, true);
Changed = true;
}

return Changed;
Expand Down
83 changes: 16 additions & 67 deletions lib/SILOptimizer/Utils/GenericCloner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,25 @@ using namespace swift;

/// Create a new empty function with the correct arguments and a unique name.
SILFunction *GenericCloner::initCloned(SILFunction *Orig,
const ReabstractionInfo &ReInfo,
TypeSubstitutionMap &InterfaceSubs,
StringRef NewName) {
SILModule &M = Orig->getModule();
Module *SM = M.getSwiftModule();

CanSILFunctionType FTy =
SILType::substFuncType(M, SM, InterfaceSubs,
Orig->getLoweredFunctionType(),
/*dropGenerics = */ true);

assert((Orig->isTransparent() || Orig->isBare() || Orig->getLocation())
&& "SILFunction missing location");
assert((Orig->isTransparent() || Orig->isBare() || Orig->getDebugScope())
&& "SILFunction missing DebugScope");
assert(!Orig->isGlobalInit() && "Global initializer cannot be cloned");

// Create a new empty function.
SILFunction *NewF = Orig->getModule().getOrCreateFunction(
getSpecializedLinkage(Orig, Orig->getLinkage()), NewName,
ReInfo.getSpecializedType(), nullptr,
SILFunction *NewF = M.getOrCreateFunction(
getSpecializedLinkage(Orig, Orig->getLinkage()), NewName, FTy, nullptr,
Orig->getLocation(), Orig->isBare(), Orig->isTransparent(),
Orig->isFragile(), Orig->isThunk(), Orig->getClassVisibility(),
Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig,
Expand All @@ -56,55 +63,18 @@ void GenericCloner::populateCloned() {
// Create arguments for the entry block.
SILBasicBlock *OrigEntryBB = &*Original.begin();
SILBasicBlock *ClonedEntryBB = new (M) SILBasicBlock(Cloned);
getBuilder().setInsertionPoint(ClonedEntryBB);

llvm::SmallVector<AllocStackInst *, 8> AllocStacks;
AllocStackInst *ReturnValueAddr = nullptr;

// Create the entry basic block with the function arguments.
auto I = OrigEntryBB->bbarg_begin(), E = OrigEntryBB->bbarg_end();
int ArgIdx = 0;
while (I != E) {
SILArgument *OrigArg = *I;
RegularLocation Loc((Decl *)OrigArg->getDecl());
AllocStackInst *ASI = nullptr;
SILType mappedType = remapType(OrigArg->getType());
if (ReInfo.isArgConverted(ArgIdx)) {
// We need an alloc_stack as a replacement for the indirect parameter.
assert(mappedType.isAddress());
mappedType = mappedType.getObjectType();
ASI = getBuilder().createAllocStack(Loc, mappedType);
ValueMap[OrigArg] = ASI;
AllocStacks.push_back(ASI);
if (ReInfo.isResultIndex(ArgIdx)) {
// This result is converted from indirect to direct. The return inst
// needs to load the value from the alloc_stack. See below.
assert(!ReturnValueAddr);
ReturnValueAddr = ASI;
} else {
// Store the new direct parameter to the alloc_stack.
auto *NewArg =
new (M) SILArgument(ClonedEntryBB, mappedType, OrigArg->getDecl());
getBuilder().createStore(Loc, NewArg, ASI);

// Try to create a new debug_value from an existing debug_value_addr.
for (Operand *ArgUse : OrigArg->getUses()) {
if (auto *DVAI = dyn_cast<DebugValueAddrInst>(ArgUse->getUser())) {
getBuilder().createDebugValue(DVAI->getLoc(), NewArg,
DVAI->getVarInfo());
break;
}
}
}
} else {
auto *NewArg =
new (M) SILArgument(ClonedEntryBB, mappedType, OrigArg->getDecl());
ValueMap[OrigArg] = NewArg;
}
SILValue MappedValue =
new (M) SILArgument(ClonedEntryBB, remapType((*I)->getType()),
(*I)->getDecl());
ValueMap.insert(std::make_pair(*I, MappedValue));
++I;
++ArgIdx;
}

getBuilder().setInsertionPoint(ClonedEntryBB);
BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB));
// Recursively visit original BBs in depth-first preorder, starting with the
// entry block, cloning all instructions other than terminators.
Expand All @@ -113,27 +83,6 @@ void GenericCloner::populateCloned() {
// Now iterate over the BBs and fix up the terminators.
for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) {
getBuilder().setInsertionPoint(BI->second);
TermInst *OrigTermInst = BI->first->getTerminator();
if (auto *RI = dyn_cast<ReturnInst>(OrigTermInst)) {
SILValue ReturnValue;
if (ReturnValueAddr) {
// The result is converted from indirect to direct. We have to load the
// returned value from the alloc_stack.
ReturnValue = getBuilder().createLoad(ReturnValueAddr->getLoc(),
ReturnValueAddr);
}
for (AllocStackInst *ASI : reverse(AllocStacks)) {
getBuilder().createDeallocStack(ASI->getLoc(), ASI);
}
if (ReturnValue) {
getBuilder().createReturn(RI->getLoc(), ReturnValue);
continue;
}
} else if (isa<ThrowInst>(OrigTermInst)) {
for (AllocStackInst *ASI : reverse(AllocStacks)) {
getBuilder().createDeallocStack(ASI->getLoc(), ASI);
}
}
visit(BI->first->getTerminator());
}
}
Loading

0 comments on commit f70b53b

Please sign in to comment.