Files
swift-mirror/lib/SILOptimizer/Transforms/GenericSpecializer.cpp
Mark Lacey 84473f242a Do not specialize dead apply/partial_apply.
Do not specialize an apply/partial_apply that we've already added to the
set of dead instructions. Doing so can result in creating a new
instruction which we will leave around, and which will have a type
mismatch in its parameter list.

Fixes rdar://problem/25447450.
2016-03-30 21:16:00 -07:00

112 lines
3.8 KiB
C++

//===--- GenericSpecializer.cpp - Specialization of generic functions -----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 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
//
//===----------------------------------------------------------------------===//
//
// Specialize calls to generic functions by substituting static type
// information.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-generic-specializer"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Utils/Generics.h"
#include "swift/SILOptimizer/Utils/Local.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/ADT/SmallVector.h"
using namespace swift;
namespace {
class GenericSpecializer : public SILFunctionTransform {
bool specializeAppliesInFunction(SILFunction &F);
/// The entry point to the transformation.
void run() override {
SILFunction &F = *getFunction();
DEBUG(llvm::dbgs() << "***** GenericSpecializer on function:" << F.getName()
<< " *****\n");
if (specializeAppliesInFunction(F))
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
}
StringRef getName() override { return "Generic Specializer"; }
};
} // end anonymous namespace
bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
DeadInstructionSet DeadApplies;
for (auto &BB : F) {
for (auto It = BB.begin(), End = BB.end(); It != End;) {
auto &I = *It++;
// Skip non-apply instructions, apply instructions with no
// substitutions, apply instructions where we do not statically
// know the called function, and apply instructions where we do
// not have the body of the called function.
ApplySite Apply = ApplySite::isa(&I);
if (!Apply || !Apply.hasSubstitutions())
continue;
auto *Callee = Apply.getReferencedFunction();
if (!Callee || !Callee->isDefinition())
continue;
// Do not attempt to specialize known dead instructions. Doing
// so would be a waste of time (since they are unused), and can
// also lead to verification errors on the newly created
// apply. This can happen in the case of a partial application
// of a reabstraction thunk where we have done an RAUW on the
// reabstracted function (which is an argument of the partial
// apply). In this case we add the partial apply of the
// reabstraction thunk to the set of dead applies, but its
// arguments types do not match the expected types of the
// argument that has been RAUWed into it.
if (DeadApplies.count(Apply.getInstruction()))
continue;
// We have a call that can potentially be specialized, so
// attempt to do so.
llvm::SmallVector<SILFunction *, 2> NewFunctions;
trySpecializeApplyOfGeneric(Apply, DeadApplies, NewFunctions);
// 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);
}
}
}
// 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;
}
SILTransform *swift::createGenericSpecializer() {
return new GenericSpecializer();
}