blob: 42e1bdae310e0b17333635b746e36fcceff72f78 [file] [log] [blame]
//===--- SemanticARCOpts.cpp ----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-semantic-arc-opts"
#include "SemanticARCOpts.h"
#include "SemanticARCOptVisitor.h"
#include "Transforms.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/Support/CommandLine.h"
using namespace swift;
using namespace swift::semanticarc;
static llvm::cl::list<ARCTransformKind> TransformsToPerform(
llvm::cl::values(
clEnumValN(ARCTransformKind::AllPeepholes,
"sil-semantic-arc-peepholes-all",
"Perform All ARC canonicalizations and peepholes"),
clEnumValN(ARCTransformKind::LoadCopyToLoadBorrowPeephole,
"sil-semantic-arc-peepholes-loadcopy-to-loadborrow",
"Perform the load [copy] to load_borrow peephole"),
clEnumValN(ARCTransformKind::RedundantBorrowScopeElimPeephole,
"sil-semantic-arc-peepholes-redundant-borrowscope-elim",
"Perform the redundant borrow scope elimination peephole"),
clEnumValN(ARCTransformKind::RedundantCopyValueElimPeephole,
"sil-semantic-arc-peepholes-redundant-copyvalue-elim",
"Perform the redundant copy_value peephole"),
clEnumValN(ARCTransformKind::LifetimeJoiningPeephole,
"sil-semantic-arc-peepholes-lifetime-joining",
"Perform the join lifetimes peephole"),
clEnumValN(ARCTransformKind::OwnershipConversionElimPeephole,
"sil-semantic-arc-peepholes-ownership-conversion-elim",
"Eliminate unchecked_ownership_conversion insts that are "
"not needed"),
clEnumValN(ARCTransformKind::OwnedToGuaranteedPhi,
"sil-semantic-arc-owned-to-guaranteed-phi",
"Perform Owned To Guaranteed Phi. NOTE: Seeded by peephole "
"optimizer for compile time saving purposes, so run this "
"after running peepholes)")),
llvm::cl::desc(
"For testing purposes only run the specified list of semantic arc "
"optimization. If the list is empty, we run all transforms"));
//===----------------------------------------------------------------------===//
// Top Level Entrypoint
//===----------------------------------------------------------------------===//
namespace {
// Even though this is a mandatory pass, it is rerun after deserialization in
// case DiagnosticConstantPropagation exposed anything new in this assert
// configuration.
struct SemanticARCOpts : SILFunctionTransform {
bool guaranteedOptsOnly;
SemanticARCOpts(bool guaranteedOptsOnly)
: guaranteedOptsOnly(guaranteedOptsOnly) {}
#ifndef NDEBUG
void performCommandlineSpecifiedTransforms(SemanticARCOptVisitor &visitor) {
for (auto transform : TransformsToPerform) {
visitor.ctx.transformKind = transform;
SWIFT_DEFER {
visitor.ctx.transformKind = ARCTransformKind::Invalid;
visitor.reset();
};
switch (transform) {
case ARCTransformKind::LifetimeJoiningPeephole:
case ARCTransformKind::RedundantCopyValueElimPeephole:
case ARCTransformKind::RedundantBorrowScopeElimPeephole:
case ARCTransformKind::LoadCopyToLoadBorrowPeephole:
case ARCTransformKind::AllPeepholes:
case ARCTransformKind::OwnershipConversionElimPeephole:
// We never assume we are at fixed point when running these transforms.
if (performPeepholesWithoutFixedPoint(visitor)) {
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
}
continue;
case ARCTransformKind::OwnedToGuaranteedPhi:
if (tryConvertOwnedPhisToGuaranteedPhis(visitor.ctx)) {
invalidateAnalysis(
SILAnalysis::InvalidationKind::BranchesAndInstructions);
}
continue;
case ARCTransformKind::All:
case ARCTransformKind::Invalid:
llvm_unreachable("unsupported option");
}
}
}
#endif
bool performPeepholesWithoutFixedPoint(SemanticARCOptVisitor &visitor) {
// Add all the results of all instructions that we want to visit to the
// worklist.
for (auto &block : *getFunction()) {
for (auto &inst : block) {
if (SemanticARCOptVisitor::shouldVisitInst(&inst)) {
for (SILValue v : inst.getResults()) {
visitor.worklist.insert(v);
}
}
}
}
// Then process the worklist, performing peepholes.
return visitor.optimizeWithoutFixedPoint();
}
bool performPeepholes(SemanticARCOptVisitor &visitor) {
// Add all the results of all instructions that we want to visit to the
// worklist.
for (auto &block : *getFunction()) {
for (auto &inst : block) {
if (SemanticARCOptVisitor::shouldVisitInst(&inst)) {
for (SILValue v : inst.getResults()) {
visitor.worklist.insert(v);
}
}
}
}
// Then process the worklist, performing peepholes.
return visitor.optimize();
}
void run() override {
SILFunction &f = *getFunction();
// Return early if we are not performing OSSA optimizations or we are not in
// ownership.
if (!f.getModule().getOptions().EnableOSSAOptimizations ||
!f.hasOwnership())
return;
// Make sure we are running with ownership verification enabled.
assert(f.getModule().getOptions().VerifySILOwnership &&
"Can not perform semantic arc optimization unless ownership "
"verification is enabled");
SemanticARCOptVisitor visitor(f, guaranteedOptsOnly);
#ifndef NDEBUG
// If we are being asked for testing purposes to run a series of transforms
// expressed on the command line, run that and return.
if (!TransformsToPerform.empty()) {
return performCommandlineSpecifiedTransforms(visitor);
}
#endif
// Otherwise, perform our standard optimizations.
bool didEliminateARCInsts = performPeepholes(visitor);
// Now that we have seeded the map of phis to incoming values that could be
// converted to guaranteed, ignoring the phi, try convert those phis to be
// guaranteed.
if (tryConvertOwnedPhisToGuaranteedPhis(visitor.ctx)) {
// We return here early to save a little compile time so we do not
// invalidate analyses redundantly.
return invalidateAnalysis(
SILAnalysis::InvalidationKind::BranchesAndInstructions);
}
// Otherwise, we only deleted instructions and did not touch phis.
if (didEliminateARCInsts)
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
}
};
} // end anonymous namespace
SILTransform *swift::createSemanticARCOpts() {
return new SemanticARCOpts(false /*guaranteed*/);
}
SILTransform *swift::createGuaranteedARCOpts() {
return new SemanticARCOpts(true /*guaranteed*/);
}