Add a stand-alone devirtualizer pass.

Add back a stand-alone devirtualizer pass, running prior to generic
specialization. As with the stand-alone generic specializer pass, this
may add functions to the pass manager's work list.

This is another step in unbundling these passes from the performance
inliner.
This commit is contained in:
Mark Lacey
2015-12-20 21:04:43 -08:00
parent 4bb33dc3fd
commit 70938b1aee
9 changed files with 122 additions and 20 deletions

View File

@@ -75,6 +75,7 @@ PASS(DeadObjectElimination, "deadobject-elim",
"Eliminate unused objects that do not have destructors with side effects")
PASS(DefiniteInitialization, "definite-init",
"Definite Initialization")
PASS(Devirtualizer, "devirtualizer", "Devirtualize indirect calls")
PASS(DiagnoseUnreachable, "diagnose-unreachable",
"Diagnose Unreachable Code")
PASS(DiagnosticConstantPropagation, "diagnostic-constant-propagation",

View File

@@ -251,6 +251,7 @@ void swift::runSILOptimizationPasses(SILModule &Module) {
// Run two iterations of the high-level SSA passes.
PM.setStageName("HighLevel");
PM.addDevirtualizer();
PM.addGenericSpecializer();
AddSSAPasses(PM, OptimizationLevelKind::HighLevel);
PM.runOneIteration();

View File

@@ -7,6 +7,7 @@ set(TRANSFORMS_SOURCES
Transforms/DeadCodeElimination.cpp
Transforms/DeadObjectElimination.cpp
Transforms/DeadStoreElimination.cpp
Transforms/Devirtualizer.cpp
Transforms/GenericSpecializer.cpp
Transforms/MergeCondFail.cpp
Transforms/RedundantLoadElimination.cpp

View File

@@ -0,0 +1,99 @@
//===-------- Devirtualizer.cpp - Devirtualize indirect calls ------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Devirtualize indirect calls to functions, turning them into direct function
// references.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-devirtualizer"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
#include "swift/SILOptimizer/Utils/Devirtualize.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/ADT/SmallVector.h"
using namespace swift;
namespace {
class Devirtualizer : public SILFunctionTransform {
bool devirtualizeAppliesInFunction(SILFunction &F,
ClassHierarchyAnalysis *CHA);
/// The entry point to the transformation.
void run() override {
SILFunction &F = *getFunction();
ClassHierarchyAnalysis *CHA = PM->getAnalysis<ClassHierarchyAnalysis>();
DEBUG(llvm::dbgs() << "***** Devirtualizer on function:" << F.getName()
<< " *****\n");
if (devirtualizeAppliesInFunction(F, CHA))
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
}
StringRef getName() override { return "Devirtualizer"; }
};
} // end anonymous namespace
bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
ClassHierarchyAnalysis *CHA) {
bool Changed = false;
llvm::SmallVector<SILInstruction *, 8> DeadApplies;
for (auto &BB : F) {
for (auto It = BB.begin(), End = BB.end(); It != End;) {
auto &I = *It++;
// Skip non-apply instructions.
auto Apply = FullApplySite::isa(&I);
if (!Apply)
continue;
auto NewInstPair = tryDevirtualizeApply(Apply, CHA);
if (!NewInstPair.second)
continue;
Changed = true;
auto *CalleeFn = NewInstPair.second.getCalleeFunction();
assert(CalleeFn && "Expected devirtualized callee!");
// We may not have optimized these functions yet, and it could
// be beneficial to rerun some earlier passes on the current
// function now that we've made these direct references visible.
if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize())
notifyPassManagerOfFunction(CalleeFn);
auto *AI = Apply.getInstruction();
if (!isa<TryApplyInst>(AI))
AI->replaceAllUsesWith(NewInstPair.first);
DeadApplies.push_back(AI);
}
}
// Remove all the now-dead applies.
while (!DeadApplies.empty()) {
auto *AI = DeadApplies.pop_back_val();
recursivelyDeleteTriviallyDeadInstructions(AI, true);
}
return Changed;
}
SILTransform *swift::createDevirtualizer() { return new Devirtualizer(); }

View File

@@ -1,4 +1,4 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -inline | FileCheck %s
// RUN: %target-sil-opt -enable-sil-verify-all %s -devirtualizer | FileCheck %s
sil_stage canonical

View File

@@ -1,4 +1,4 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -inline -dce | FileCheck %s
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -devirtualizer -dce | FileCheck %s
sil_stage canonical

View File

@@ -1,4 +1,4 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -inline -redundant-load-elim -inline | FileCheck %s --check-prefix=CHECK-INLINE
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -devirtualizer -redundant-load-elim -inline | FileCheck %s --check-prefix=CHECK-DEVIRT
// RUN: %target-sil-opt -enable-sil-verify-all %s -early-inline | FileCheck %s --check-prefix=CHECK-EARLY-INLINE
// RUN: %target-sil-opt -enable-sil-verify-all %s -specdevirt | FileCheck %s --check-prefix=CHECK-SPECDEVIRT
// RUN: %target-sil-opt -enable-sil-verify-all %s -mandatory-inlining | FileCheck %s --check-prefix=CHECK-MANDATORY-INLINING
@@ -615,10 +615,10 @@ bb0:
// CHECK-SPECDEVIRT: checked_cast_br [exact]
// CHECK-SPECDEVIRT: }
// CHECK-INLINE-LABEL: sil @_TF16devirt_try_apply5test4FT_Vs5Int32
// CHECK-INLINE-NOT: checked_cast_br [exact]
// CHECK-INLINE-NOT: class_method
// CHECK-INLINE: }
// CHECK-DEVIRT-LABEL: sil @_TF16devirt_try_apply5test4FT_Vs5Int32
// CHECK-DEVIRT-NOT: checked_cast_br [exact]
// CHECK-DEVIRT-NOT: class_method
// CHECK-DEVIRT: }
// CHECK-EARLY-INLINE-LABEL: sil @_TF16devirt_try_apply5test4FT_Vs5Int32
// CHECK-EARLY-INLINE-NOT: checked_cast_br [exact]
@@ -658,10 +658,10 @@ bb4(%19 : $ErrorType):
// DISABLE THIS TEST CASE FOR NOW. AS RLE GETS BETTER. WILL RE-ENABLE.
//
// DISABLECHECK-INLINE-LABEL: sil @_TF16devirt_try_apply5test5FT_Vs5Int32
// DISABLECHECK-INLINE-NOT: = witness_method
// DISABLECHECK-INLINE-NOT: = class_method
// DISABLECHECK-INLINE: }
// DISABLECHECK-DEVIRT-LABEL: sil @_TF16devirt_try_apply5test5FT_Vs5Int32
// DISABLECHECK-DEVIRT-NOT: = witness_method
// DISABLECHECK-DEVIRT-NOT: = class_method
// DISABLECHECK-DEVIRT: }
sil @_TF16devirt_try_apply5test5FT_Vs5Int32 : $@convention(thin) () -> Int32 {
bb0:
%0 = alloc_stack $Int32
@@ -705,9 +705,9 @@ bb4(%23 : $ErrorType):
// CHECK-SPECDEVIRT: checked_cast_br [exact]
// CHECK-SPECDEVIRT: }
// CHECK-INLINE-LABEL: sil @_TF16devirt_try_apply5test6FT_GSqVs5Int32_
// CHECK-INLINE-NOT: class_method
// CHECK-INLINE: }
// CHECK-DEVIRT-LABEL: sil @_TF16devirt_try_apply5test6FT_GSqVs5Int32_
// CHECK-DEVIRT-NOT: class_method
// CHECK-DEVIRT: }
// CHECK-EARLY-INLINE-LABEL: sil @_TF16devirt_try_apply5test6FT_GSqVs5Int32_
// CHECK-EARLY-INLINE-NOT: class_method
@@ -751,10 +751,10 @@ bb4(%20 : $ErrorType):
// CHECK-SPECDEVIRT: checked_cast_br [exact]
// CHECK-SPECDEVIRT: }
// CHECK-INLINE-LABEL: sil @_TF16devirt_try_apply5test7FT_Vs5Int32
// CHECK-INLINE-NOT: checked_cast_br [exact]
// CHECK-INLINE-NOT: class_method
// CHECK-INLINE: }
// CHECK-DEVIRT-LABEL: sil @_TF16devirt_try_apply5test7FT_Vs5Int32
// CHECK-DEVIRT-NOT: checked_cast_br [exact]
// CHECK-DEVIRT-NOT: class_method
// CHECK-DEVIRT: }
// CHECK-EARLY-INLINE-LABEL: sil @_TF16devirt_try_apply5test7FT_Vs5Int32
// CHECK-EARLY-INLINE-NOT: checked_cast_br [exact]

View File

@@ -1,4 +1,4 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -dce | FileCheck %s
// RUN: %target-sil-opt -enable-sil-verify-all %s -devirtualizer -dce | FileCheck %s
sil_stage canonical

View File

@@ -1,4 +1,4 @@
// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -dce | FileCheck %s
// RUN: %target-sil-opt -enable-sil-verify-all %s -devirtualizer -dce | FileCheck %s
sil_stage canonical