mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[semantic-arc-opts] Create a new pass called semantic arc opts.
I am going to run it very early and use it to ensure that extra copies due to my refactoring of SILGenPattern do not cause COW copies to be introduced. For now, it does a very simple optimization, namely, it eliminates a copy_value, with only a destroy_value user on a guaranteed parameter. It is now disabled behind a flag.
This commit is contained in:
@@ -146,6 +146,9 @@ public:
|
||||
/// Emit checks to trap at run time when the law of exclusivity is violated.
|
||||
bool EnforceExclusivityDynamic = false;
|
||||
|
||||
/// Enable the mandatory semantic arc optimizer.
|
||||
bool EnableMandatorySemanticARCOpts = false;
|
||||
|
||||
SILOptions() : Sanitize(SanitizerKind::None) {}
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
|
||||
@@ -250,6 +250,9 @@ def emit_pch : Flag<["-"], "emit-pch">,
|
||||
def enable_sil_ownership : Flag<["-"], "enable-sil-ownership">,
|
||||
HelpText<"Enable the SIL Ownership Model">;
|
||||
|
||||
def enable_mandatory_semantic_arc_opts : Flag<["-"], "enable-mandatory-semantic-arc-opts">,
|
||||
HelpText<"Enable the mandatory semantic arc optimizer">;
|
||||
|
||||
def assume_parsing_unqualified_ownership_sil : Flag<["-"], "assume-parsing-unqualified-ownership-sil">,
|
||||
HelpText<"Assume unqualified SIL ownership when parsing SIL">;
|
||||
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
#define SWIFT_SIL_OWNERSHIPCHECKER_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
class SILBasicBlock;
|
||||
class SILInstruction;
|
||||
class SILModule;
|
||||
class SILValue;
|
||||
class TransitivelyUnreachableBlocksInfo;
|
||||
class SILInstruction;
|
||||
|
||||
/// This class is a higher level interface to the ownership checker meant for
|
||||
/// use with SILPasses. It uses the actual checker as an internal PImpl detail
|
||||
|
||||
@@ -251,6 +251,8 @@ PASS(UsePrespecialized, "use-prespecialized",
|
||||
"Use pre-specialized functions")
|
||||
PASS(ValueOwnershipKindDumper, "value-ownership-kind-dumper",
|
||||
"Print the value ownership kind of all ValueBase in a SILModule")
|
||||
PASS(SemanticARCOpts, "semantic-arc-opts",
|
||||
"Pass for performing semantic ARC optimizations")
|
||||
PASS(BugReducerTester, "bug-reducer-tester",
|
||||
"Utility pass for testing sil-bug-reducer. Asserts when visits an apply that calls a specific function")
|
||||
PASS_RANGE(AllPasses, AADumper, BugReducerTester)
|
||||
|
||||
@@ -1296,6 +1296,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
|
||||
Opts.EnableSILOwnership |= Args.hasArg(OPT_enable_sil_ownership);
|
||||
Opts.AssumeUnqualifiedOwnershipWhenParsing
|
||||
|= Args.hasArg(OPT_assume_parsing_unqualified_ownership_sil);
|
||||
Opts.EnableMandatorySemanticARCOpts |=
|
||||
Args.hasArg(OPT_enable_mandatory_semantic_arc_opts);
|
||||
|
||||
if (Args.hasArg(OPT_debug_on_sil)) {
|
||||
// Derive the name of the SIL file for debugging from
|
||||
|
||||
@@ -8,4 +8,5 @@ set(MANDATORY_SOURCES
|
||||
Mandatory/MandatoryInlining.cpp
|
||||
Mandatory/PredictableMemOpt.cpp
|
||||
Mandatory/ConstantPropagation.cpp
|
||||
Mandatory/SemanticARCOpts.cpp
|
||||
PARENT_SCOPE)
|
||||
|
||||
89
lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp
Normal file
89
lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
//===--- 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 "swift/SIL/OwnershipChecker.h"
|
||||
#include "swift/SIL/SILArgument.h"
|
||||
#include "swift/SIL/SILInstruction.h"
|
||||
#include "swift/SILOptimizer/PassManager/Passes.h"
|
||||
#include "swift/SILOptimizer/PassManager/Transforms.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
STATISTIC(NumEliminatedInsts, "number of removed instructions");
|
||||
|
||||
static bool optimizeGuaranteedArgument(SILArgument *Arg) {
|
||||
bool MadeChange = false;
|
||||
|
||||
// Gather all copy_value users of Arg.
|
||||
llvm::SmallVector<CopyValueInst *, 4> Copies;
|
||||
for (auto *Op : Arg->getUses()) {
|
||||
if (auto *CVI = dyn_cast<CopyValueInst>(Op->getUser())) {
|
||||
Copies.push_back(CVI);
|
||||
}
|
||||
}
|
||||
|
||||
// Then until we run out of copies...
|
||||
while (!Copies.empty()) {
|
||||
auto *CVI = Copies.pop_back_val();
|
||||
|
||||
// Quickly see if copy has only one use and that use is a destroy_value. In
|
||||
// such a case, we can always eliminate both the copy and the destroy.
|
||||
if (auto *Op = CVI->getSingleUse()) {
|
||||
if (auto *DVI = dyn_cast<DestroyValueInst>(Op->getUser())) {
|
||||
DVI->eraseFromParent();
|
||||
CVI->eraseFromParent();
|
||||
NumEliminatedInsts += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Top Level Entrypoint
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
struct SemanticARCOpts : SILFunctionTransform {
|
||||
void run() override {
|
||||
bool MadeChange = false;
|
||||
SILFunction *F = getFunction();
|
||||
|
||||
// First as a special case, handle guaranteed SIL function arguments.
|
||||
//
|
||||
// The reason that this is special is that we do not need to consider the
|
||||
// end of the borrow scope since the end of the function is the end of the
|
||||
// borrow scope.
|
||||
for (auto *Arg : F->getArguments()) {
|
||||
if (Arg->getOwnershipKind() != ValueOwnershipKind::Guaranteed)
|
||||
continue;
|
||||
MadeChange |= optimizeGuaranteedArgument(Arg);
|
||||
}
|
||||
|
||||
if (MadeChange) {
|
||||
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
|
||||
}
|
||||
}
|
||||
|
||||
StringRef getName() override { return "Semantic ARC Opts"; }
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
SILTransform *swift::createSemanticARCOpts() { return new SemanticARCOpts(); }
|
||||
@@ -71,8 +71,12 @@ static void addOwnershipModelEliminatorPipeline(SILPassPipelinePlan &P) {
|
||||
P.addOwnershipModelEliminator();
|
||||
}
|
||||
|
||||
static void addMandatoryOptPipeline(SILPassPipelinePlan &P) {
|
||||
static void addMandatoryOptPipeline(SILPassPipelinePlan &P,
|
||||
const SILOptions &Options) {
|
||||
P.startPipeline("Guaranteed Passes");
|
||||
if (Options.EnableMandatorySemanticARCOpts) {
|
||||
P.addSemanticARCOpts();
|
||||
}
|
||||
P.addCapturePromotion();
|
||||
P.addAllocBoxToStack();
|
||||
|
||||
@@ -107,7 +111,7 @@ SILPassPipelinePlan::getDiagnosticPassPipeline(const SILOptions &Options) {
|
||||
}
|
||||
|
||||
// Otherwise run the rest of diagnostics.
|
||||
addMandatoryOptPipeline(P);
|
||||
addMandatoryOptPipeline(P, Options);
|
||||
|
||||
if (SILViewGuaranteedCFG) {
|
||||
addCFGPrinterPipeline(P, "SIL View Guaranteed CFG");
|
||||
|
||||
17
test/SILOptimizer/semantic-arc-opts.sil
Normal file
17
test/SILOptimizer/semantic-arc-opts.sil
Normal file
@@ -0,0 +1,17 @@
|
||||
// RUN: %target-sil-opt -enable-sil-verify-all -enable-sil-ownership -semantic-arc-opts %s | %FileCheck %s
|
||||
|
||||
sil_stage canonical
|
||||
|
||||
import Builtin
|
||||
|
||||
// CHECK-LABEL: sil @only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
|
||||
// CHECK-NOT: copy_value
|
||||
// CHECK-NOT: destroy_value
|
||||
sil @only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
|
||||
bb0(%0 : @guaranteed $Builtin.NativeObject):
|
||||
%1 = copy_value %0 : $Builtin.NativeObject
|
||||
destroy_value %1 : $Builtin.NativeObject
|
||||
%9999 = tuple()
|
||||
return %9999 : $()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user