[deserialization] Deserialize transparent functions lazily iff they will be used in mandatory inlining.

Swift SVN r14490
This commit is contained in:
Michael Gottesman
2014-02-28 01:05:01 +00:00
parent a861f9c2c8
commit 29e1a53bbb
10 changed files with 182 additions and 54 deletions

View File

@@ -58,6 +58,9 @@ public:
/// Stop optimizing after the Nth pass. For debugging purposes.
unsigned NumOptPassesToRun = UINT_MAX;
/// Are we debugging sil serialization.
bool DebugSerialization = false;
};
} // end namespace swift

View File

@@ -128,6 +128,10 @@ def sil_print_all : Flag<["-"], "sil-print-all">,
def sil_time_transforms : Flag<["-"], "sil-time-transforms">,
HelpText<"Time each SIL transform invocation">;
def sil_debug_serialization : Flag<["-"], "sil-debug-serialization">,
HelpText<"Only run mandatory inlining and do not allow inlining to eliminate "
"dead functions. (for debugging only)">;
def use_malloc : Flag<["-"], "use-malloc">,
HelpText<"Allocate internal data structures using malloc "
"(for memory debugging)">;

View File

@@ -20,6 +20,7 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/Module.h"
#include "swift/AST/SILOptions.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/Range.h"
#include "swift/SIL/SILDeclRef.h"
@@ -76,6 +77,7 @@ public:
using GlobalListType = llvm::ilist<SILGlobalVariable>;
using VTableListType = llvm::ilist<SILVTable>;
using WitnessTableListType = llvm::ilist<SILWitnessTable>;
using LinkingMode = SILOptions::LinkingMode;
private:
friend class SILBasicBlock;
@@ -317,6 +319,13 @@ public:
return FunctionTable.lookup(name);
}
/// Attempt to link the SILFunction. Returns true if linking succeeded, false
/// otherwise.
///
/// \return false if the linking failed.
bool linkFunction(SILFunction *Fun,
LinkingMode LinkAll=LinkingMode::LinkNormal);
/// \brief Return the declaration of a utility function that can,
/// but needn't, be shared between modules.
SILFunction *getOrCreateSharedFunction(SILLocation loc,

View File

@@ -17,8 +17,9 @@
#ifndef SWIFT_SILPASSES_PASSES_H
#define SWIFT_SILPASSES_PASSES_H
#include "swift/SIL/SILModule.h"
namespace swift {
class SILModule;
class SILOptions;
class SILTransform;
@@ -51,7 +52,8 @@ namespace swift {
SILTransform *createPredictableMemoryOptimizations();
SILTransform *createConstantPropagation();
SILTransform *createDCE();
SILTransform *createMandatoryInlining();
SILTransform *createMandatoryInlining(SILModule::LinkingMode Mode,
bool ShouldCleanup=true);
SILTransform *createSILCleanup();
SILTransform *createEmitDFDiagnostics();

View File

@@ -647,6 +647,7 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
Opts.VerifyAll = Args.hasArg(OPT_sil_verify_all);
Opts.PrintAll = Args.hasArg(OPT_sil_print_all);
Opts.TimeTransforms = Args.hasArg(OPT_sil_time_transforms);
Opts.DebugSerialization = Args.hasArg(OPT_sil_debug_serialization);
return false;
}

View File

@@ -16,8 +16,12 @@
#include "swift/SIL/SILValue.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
using namespace swift;
STATISTIC(NumFuncLinked, "Number of SIL functions linked");
namespace swift {
/// SILTypeList - The uniqued backing store for the SILValue type list. This
/// is only exposed out of SILValue as an ArrayRef of types, so it should
@@ -243,3 +247,82 @@ const BuiltinInfo &SILModule::getBuiltinInfo(Identifier ID) {
return Info;
}
bool SILModule::linkFunction(SILFunction *Fun, SILModule::LinkingMode Mode) {
// If we are not linking anything bail.
if (Mode == LinkingMode::LinkNone)
return nullptr;
bool LinkAll = Mode == LinkingMode::LinkAll;
// First attempt to link in Fun. If we fail, bail.
auto NewFn = SILLoader->lookupSILFunction(Fun);
if (!NewFn)
return false;
++NumFuncLinked;
// Ok, we succeeded in linking in Fun. Transitively link in the functions that
// Fun references.
SmallVector<SILFunction *, 128> Worklist;
Worklist.push_back(NewFn);
while (!Worklist.empty()) {
auto Fn = Worklist.pop_back_val();
for (auto &BB : *Fn)
for (auto I = BB.begin(), E = BB.end(); I != E; I++) {
SILFunction *CalleeFunction = nullptr;
bool TryLinking = false;
if (ApplyInst *AI = dyn_cast<ApplyInst>(I)) {
SILValue Callee = AI->getCallee();
// Handles FunctionRefInst only.
if (FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(Callee.getDef())) {
CalleeFunction = FRI->getReferencedFunction();
// When EnableLinkAll is true, we always link the Callee.
TryLinking = LinkAll || AI->isTransparent() ||
CalleeFunction->getLinkage() == SILLinkage::Shared;
}
} else if (PartialApplyInst *PAI = dyn_cast<PartialApplyInst>(I)) {
SILValue Callee = PAI->getCallee();
// Handles FunctionRefInst only.
if (FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(Callee.getDef())) {
CalleeFunction = FRI->getReferencedFunction();
// When EnableLinkAll is true, we always link the Callee.
TryLinking = LinkAll || CalleeFunction->isTransparent() ||
CalleeFunction->getLinkage() == SILLinkage::Shared;
} else {
continue;
}
} else if (FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(I)) {
// When EnableLinkAll is true, we link the function referenced by
// FunctionRefInst.
CalleeFunction = LinkAll ? FRI->getReferencedFunction() :
nullptr;
TryLinking = LinkAll;
}
if (!CalleeFunction)
continue;
// The ExternalSource may wish to rewrite non-empty bodies.
if (ExternalSource)
if (auto NewFn = ExternalSource->lookupSILFunction(CalleeFunction)) {
Worklist.push_back(NewFn);
++NumFuncLinked;
continue;
}
CalleeFunction->setBare(IsBare);
if (CalleeFunction->empty())
// Try to find the definition in a serialized module when callee is
// currently empty.
if (TryLinking)
if (auto NewFn = SILLoader->lookupSILFunction(CalleeFunction)) {
Worklist.push_back(NewFn);
++NumFuncLinked;
continue;
}
}
}
return true;
}

View File

@@ -201,7 +201,8 @@ cleanupCalleeValue(SILValue CalleeValue, ArrayRef<SILValue> CaptureArgs,
static SILFunction *
getCalleeFunction(ApplyInst* AI, bool &IsThick,
SmallVectorImpl<SILValue>& CaptureArgs,
SmallVectorImpl<SILValue>& FullArgs) {
SmallVectorImpl<SILValue>& FullArgs,
SILModule::LinkingMode Mode) {
if (!AI->isTransparent())
return nullptr;
@@ -278,10 +279,17 @@ getCalleeFunction(ApplyInst* AI, bool &IsThick,
assert(CalleeValue.getResultNumber() == 0);
SILFunction *CalleeFunction = FRI->getReferencedFunction();
if (!CalleeFunction || CalleeFunction->empty() ||
if (!CalleeFunction ||
(CalleeFunction->getAbstractCC() != AbstractCC::Freestanding &&
CalleeFunction->getAbstractCC() != AbstractCC::Method))
return nullptr;
// If CalleeFunction is a declaration, see if we can load it. If we fail to
// load it, bail.
if (CalleeFunction->empty() && !AI->getModule().linkFunction(CalleeFunction,
Mode))
return nullptr;
return CalleeFunction;
}
@@ -301,6 +309,7 @@ getCalleeFunction(ApplyInst* AI, bool &IsThick,
/// \returns true if successful, false if failed due to circular inlining.
static bool
runOnFunctionRecursively(SILFunction *F, ApplyInst* AI,
SILModule::LinkingMode Mode,
DenseFunctionSet &FullyInlinedSet,
ImmutableFunctionSet::Factory &SetFactory,
ImmutableFunctionSet CurrentInliningSet) {
@@ -339,15 +348,17 @@ runOnFunctionRecursively(SILFunction *F, ApplyInst* AI,
SILValue CalleeValue = InnerAI->getCallee();
bool IsThick;
SILFunction *CalleeFunction = getCalleeFunction(InnerAI, IsThick,
CaptureArgs, FullArgs);
CaptureArgs, FullArgs,
Mode);
if (!CalleeFunction) {
++I;
continue;
}
// Then recursively process it first before trying to inline it.
if (!runOnFunctionRecursively(CalleeFunction, InnerAI, FullyInlinedSet,
SetFactory, CurrentInliningSet)) {
if (!runOnFunctionRecursively(CalleeFunction, InnerAI, Mode,
FullyInlinedSet, SetFactory,
CurrentInliningSet)) {
// If we failed due to circular inlining, then emit some notes to
// trace back the failure if we have more information.
// FIXME: possibly it could be worth recovering and attempting other
@@ -420,13 +431,26 @@ runOnFunctionRecursively(SILFunction *F, ApplyInst* AI,
// Top Level Driver
//===----------------------------------------------------------------------===//
static void performSILMandatoryInlining(SILModule *M) {
class MandatoryInlining : public SILModuleTransform {
SILModule::LinkingMode Mode;
bool ShouldCleanup;
public:
MandatoryInlining(SILModule::LinkingMode M, bool C) : SILModuleTransform(),
Mode(M),
ShouldCleanup(C) {}
private:
/// The entry point to the transformation.
void run() {
SILModule *M = getModule();
DenseFunctionSet FullyInlinedSet;
ImmutableFunctionSet::Factory SetFactory;
for (auto &F : *M)
runOnFunctionRecursively(&F, nullptr, FullyInlinedSet, SetFactory,
runOnFunctionRecursively(&F, nullptr, Mode, FullyInlinedSet, SetFactory,
SetFactory.getEmptySet());
if (!ShouldCleanup)
return;
// Now that we've inlined some functions, clean up. If there are any
// transparent functions that are deserialized from another module that are
// now unused, just remove them from the module.
@@ -453,19 +477,14 @@ static void performSILMandatoryInlining(SILModule *M) {
// Okay, just erase the function from the module.
M->getFunctionList().erase(&F);
}
}
class MandatoryInlining : public SILModuleTransform {
/// The entry point to the transformation.
void run() {
performSILMandatoryInlining(getModule());
invalidateAnalysis(SILAnalysis::InvalidationKind::All);
}
StringRef getName() override { return "Mandatory Inlining"; }
};
SILTransform *swift::createMandatoryInlining() {
return new MandatoryInlining();
SILTransform *swift::createMandatoryInlining(SILModule::LinkingMode Mode,
bool ShouldCleanup) {
return new MandatoryInlining(Mode, ShouldCleanup);
}

View File

@@ -47,7 +47,18 @@ bool swift::runSILDiagnosticPasses(SILModule &Module,
PM.registerAnalysis(createCallGraphAnalysis(&Module));
PM.registerAnalysis(createAliasAnalysis(&Module));
PM.registerAnalysis(createDominanceAnalysis(&Module));
PM.add(createMandatoryInlining());
// If we are asked do debug serialization, instead of running all diagnostic
// passes, just run mandatory inlining with dead transparent function cleanup
// disabled.
PM.add(createMandatoryInlining(Options.LinkMode,
!Options.DebugSerialization/*ShouldCleanup*/));
if (Options.DebugSerialization) {
PM.run();
return Ctx.hadError();
}
// Otherwise run the rest of diagnostics.
PM.add(createCapturePromotion());
PM.add(createAllocBoxToStack());
PM.add(createInOutDeshadowing());

View File

@@ -141,10 +141,6 @@ static bool performCompile(CompilerInstance &Instance,
SM = performSILGeneration(*PrimarySourceFile);
else
SM = performSILGeneration(Instance.getMainModule());
// Link in transparent functions.
if (Invocation.getSILOptions().LinkMode > SILOptions::LinkNone)
performSILLinking(SM.get(), false);
}
// We've been told to emit SIL after SILGen, so write it now.

View File

@@ -323,7 +323,7 @@ int main(int argc, char **argv) {
PM.add(createInOutDeshadowing());
break;
case PassKind::MandatoryInlining:
PM.add(createMandatoryInlining());
PM.add(createMandatoryInlining(SILOpts.LinkMode));
break;
case PassKind::PredictableMemoryOpt:
PM.add(createPredictableMemoryOptimizations());