Don't de-virtualize in SILCombine.

It is important to de-serialize the devirtualized function (and its callees), especially because we must make sure that all transparent functions are de-serialized.
SILCombine did not do that. But as we have the same optimization in the Devirtualizer, it's not needed to duplicate the code in SILCombine.

The only reason we had this peephole in SILCombine is that the Devirtualizer pass could not handle partial applies.
So with this change the Devirtualizer can now also handle partial applies.

Fixes rdar://problem/30544344 (again, after my first attempt failed)
This commit is contained in:
Erik Eckstein
2017-02-18 18:03:46 -08:00
parent 63b122c1f6
commit a67a4e1a38
9 changed files with 96 additions and 118 deletions

View File

@@ -1080,7 +1080,7 @@ DevirtualizationResult swift::tryDevirtualizeWitnessMethod(ApplySite AI) {
/// Attempt to devirtualize the given apply if possible, and return a
/// new instruction in that case, or nullptr otherwise.
DevirtualizationResult
swift::tryDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) {
swift::tryDevirtualizeApply(ApplySite AI, ClassHierarchyAnalysis *CHA) {
DEBUG(llvm::dbgs() << " Trying to devirtualize: " << *AI.getInstruction());
// Devirtualize apply instructions that call witness_method instructions:
@@ -1091,6 +1091,11 @@ swift::tryDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) {
if (isa<WitnessMethodInst>(AI.getCallee()))
return tryDevirtualizeWitnessMethod(AI);
// TODO: check if we can also de-virtualize partial applies of class methods.
FullApplySite FAS = FullApplySite::isa(AI.getInstruction());
if (!FAS)
return std::make_pair(nullptr, ApplySite());
/// Optimize a class_method and alloc_ref pair into a direct function
/// reference:
///
@@ -1107,8 +1112,8 @@ swift::tryDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) {
/// into
///
/// %YY = function_ref @...
if (auto *CMI = dyn_cast<ClassMethodInst>(AI.getCallee())) {
auto &M = AI.getModule();
if (auto *CMI = dyn_cast<ClassMethodInst>(FAS.getCallee())) {
auto &M = FAS.getModule();
auto Instance = stripUpCasts(CMI->getOperand());
auto ClassType = Instance->getType();
if (ClassType.is<MetatypeType>())
@@ -1116,34 +1121,34 @@ swift::tryDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) {
auto *CD = ClassType.getClassOrBoundGenericClass();
if (isEffectivelyFinalMethod(AI, ClassType, CD, CHA))
return tryDevirtualizeClassMethod(AI, Instance);
if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA))
return tryDevirtualizeClassMethod(FAS, Instance);
// Try to check if the exact dynamic type of the instance is statically
// known.
if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(),
CMI->getModule(),
CHA))
return tryDevirtualizeClassMethod(AI, Instance);
return tryDevirtualizeClassMethod(FAS, Instance);
if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CMI->getModule(),
CHA)) {
if (ExactTy == CMI->getOperand()->getType())
return tryDevirtualizeClassMethod(AI, CMI->getOperand());
return tryDevirtualizeClassMethod(FAS, CMI->getOperand());
}
}
if (isa<SuperMethodInst>(AI.getCallee())) {
if (AI.hasSelfArgument()) {
return tryDevirtualizeClassMethod(AI, AI.getSelfArgument());
if (isa<SuperMethodInst>(FAS.getCallee())) {
if (FAS.hasSelfArgument()) {
return tryDevirtualizeClassMethod(FAS, FAS.getSelfArgument());
}
// It is an invocation of a class method.
// Last operand is the metatype that should be used for dispatching.
return tryDevirtualizeClassMethod(AI, AI.getArguments().back());
return tryDevirtualizeClassMethod(FAS, FAS.getArguments().back());
}
return std::make_pair(nullptr, FullApplySite());
return std::make_pair(nullptr, ApplySite());
}
bool swift::canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) {