Skip to content

Commit e822ca3

Browse files
authored
Merge pull request #8576 from gottesmm/semantic_arc_opts_the_beginning
2 parents 31b92b1 + 5e278fd commit e822ca3

File tree

10 files changed

+134
-3
lines changed

10 files changed

+134
-3
lines changed

include/swift/AST/SILOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ class SILOptions {
146146
/// Emit checks to trap at run time when the law of exclusivity is violated.
147147
bool EnforceExclusivityDynamic = false;
148148

149+
/// Enable the mandatory semantic arc optimizer.
150+
bool EnableMandatorySemanticARCOpts = false;
151+
149152
SILOptions() : Sanitize(SanitizerKind::None) {}
150153

151154
/// Return a hash code of any components from these options that should

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ def emit_pch : Flag<["-"], "emit-pch">,
250250
def enable_sil_ownership : Flag<["-"], "enable-sil-ownership">,
251251
HelpText<"Enable the SIL Ownership Model">;
252252

253+
def enable_mandatory_semantic_arc_opts : Flag<["-"], "enable-mandatory-semantic-arc-opts">,
254+
HelpText<"Enable the mandatory semantic arc optimizer">;
255+
253256
def assume_parsing_unqualified_ownership_sil : Flag<["-"], "assume-parsing-unqualified-ownership-sil">,
254257
HelpText<"Assume unqualified SIL ownership when parsing SIL">;
255258

include/swift/SIL/OwnershipChecker.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
#define SWIFT_SIL_OWNERSHIPCHECKER_H
1515

1616
#include "llvm/ADT/SmallVector.h"
17+
#include "llvm/ADT/SmallPtrSet.h"
1718

1819
namespace swift {
1920

21+
class SILBasicBlock;
22+
class SILInstruction;
2023
class SILModule;
2124
class SILValue;
2225
class TransitivelyUnreachableBlocksInfo;
23-
class SILInstruction;
2426

2527
/// This class is a higher level interface to the ownership checker meant for
2628
/// use with SILPasses. It uses the actual checker as an internal PImpl detail

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ PASS(UsePrespecialized, "use-prespecialized",
251251
"Use pre-specialized functions")
252252
PASS(ValueOwnershipKindDumper, "value-ownership-kind-dumper",
253253
"Print the value ownership kind of all ValueBase in a SILModule")
254+
PASS(SemanticARCOpts, "semantic-arc-opts",
255+
"Pass for performing semantic ARC optimizations")
254256
PASS(BugReducerTester, "bug-reducer-tester",
255257
"Utility pass for testing sil-bug-reducer. Asserts when visits an apply that calls a specific function")
256258
PASS_RANGE(AllPasses, AADumper, BugReducerTester)

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
12961296
Opts.EnableSILOwnership |= Args.hasArg(OPT_enable_sil_ownership);
12971297
Opts.AssumeUnqualifiedOwnershipWhenParsing
12981298
|= Args.hasArg(OPT_assume_parsing_unqualified_ownership_sil);
1299+
Opts.EnableMandatorySemanticARCOpts |=
1300+
Args.hasArg(OPT_enable_mandatory_semantic_arc_opts);
12991301

13001302
if (Args.hasArg(OPT_debug_on_sil)) {
13011303
// Derive the name of the SIL file for debugging from

lib/SILOptimizer/Mandatory/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ set(MANDATORY_SOURCES
88
Mandatory/MandatoryInlining.cpp
99
Mandatory/PredictableMemOpt.cpp
1010
Mandatory/ConstantPropagation.cpp
11+
Mandatory/SemanticARCOpts.cpp
1112
PARENT_SCOPE)

lib/SILOptimizer/Mandatory/GuaranteedARCOpts.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
#include "swift/SILOptimizer/PassManager/Passes.h"
1515
#include "swift/SILOptimizer/PassManager/Transforms.h"
1616
#include "swift/SIL/SILVisitor.h"
17+
#include "llvm/ADT/Statistic.h"
1718

1819
using namespace swift;
1920

21+
STATISTIC(NumInstsEliminated, "Number of instructions eliminated");
22+
2023
namespace {
2124

2225
struct GuaranteedARCOptsVisitor
@@ -47,6 +50,7 @@ bool GuaranteedARCOptsVisitor::visitDestroyAddrInst(DestroyAddrInst *DAI) {
4750
if (CA->getSrc() == Operand && !CA->isTakeOfSrc()) {
4851
CA->setIsTakeOfSrc(IsTake);
4952
DAI->eraseFromParent();
53+
NumInstsEliminated += 2;
5054
return true;
5155
}
5256
}
@@ -107,6 +111,7 @@ bool GuaranteedARCOptsVisitor::visitStrongReleaseInst(StrongReleaseInst *SRI) {
107111
// Release on a functionref is a noop.
108112
if (isa<FunctionRefInst>(Operand)) {
109113
SRI->eraseFromParent();
114+
++NumInstsEliminated;
110115
return true;
111116
}
112117

@@ -121,6 +126,7 @@ bool GuaranteedARCOptsVisitor::visitStrongReleaseInst(StrongReleaseInst *SRI) {
121126
if (SRA->getOperand() == Operand) {
122127
SRA->eraseFromParent();
123128
SRI->eraseFromParent();
129+
NumInstsEliminated += 2;
124130
return true;
125131
}
126132
// Skip past unrelated retains.
@@ -148,6 +154,7 @@ bool GuaranteedARCOptsVisitor::visitDestroyValueInst(DestroyValueInst *DVI) {
148154
CVI->replaceAllUsesWith(CVI->getOperand());
149155
CVI->eraseFromParent();
150156
DVI->eraseFromParent();
157+
NumInstsEliminated += 2;
151158
return true;
152159
}
153160
// Skip past unrelated retains.
@@ -174,6 +181,7 @@ bool GuaranteedARCOptsVisitor::visitReleaseValueInst(ReleaseValueInst *RVI) {
174181
if (SRA->getOperand() == Operand) {
175182
SRA->eraseFromParent();
176183
RVI->eraseFromParent();
184+
NumInstsEliminated += 2;
177185
return true;
178186
}
179187
// Skip past unrelated retains.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//===--- SemanticARCOpts.cpp ----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#define DEBUG_TYPE "sil-semantic-arc-opts"
14+
#include "swift/SIL/OwnershipChecker.h"
15+
#include "swift/SIL/SILArgument.h"
16+
#include "swift/SIL/SILInstruction.h"
17+
#include "swift/SILOptimizer/PassManager/Passes.h"
18+
#include "swift/SILOptimizer/PassManager/Transforms.h"
19+
#include "llvm/ADT/SmallPtrSet.h"
20+
#include "llvm/ADT/SmallVector.h"
21+
#include "llvm/ADT/Statistic.h"
22+
23+
using namespace swift;
24+
25+
STATISTIC(NumEliminatedInsts, "number of removed instructions");
26+
27+
static bool optimizeGuaranteedArgument(SILArgument *Arg) {
28+
bool MadeChange = false;
29+
30+
// Gather all copy_value users of Arg.
31+
llvm::SmallVector<CopyValueInst *, 4> Copies;
32+
for (auto *Op : Arg->getUses()) {
33+
if (auto *CVI = dyn_cast<CopyValueInst>(Op->getUser())) {
34+
Copies.push_back(CVI);
35+
}
36+
}
37+
38+
// Then until we run out of copies...
39+
while (!Copies.empty()) {
40+
auto *CVI = Copies.pop_back_val();
41+
42+
// Quickly see if copy has only one use and that use is a destroy_value. In
43+
// such a case, we can always eliminate both the copy and the destroy.
44+
if (auto *Op = CVI->getSingleUse()) {
45+
if (auto *DVI = dyn_cast<DestroyValueInst>(Op->getUser())) {
46+
DVI->eraseFromParent();
47+
CVI->eraseFromParent();
48+
NumEliminatedInsts += 2;
49+
continue;
50+
}
51+
}
52+
}
53+
54+
return MadeChange;
55+
}
56+
57+
//===----------------------------------------------------------------------===//
58+
// Top Level Entrypoint
59+
//===----------------------------------------------------------------------===//
60+
61+
namespace {
62+
63+
struct SemanticARCOpts : SILFunctionTransform {
64+
void run() override {
65+
bool MadeChange = false;
66+
SILFunction *F = getFunction();
67+
68+
// First as a special case, handle guaranteed SIL function arguments.
69+
//
70+
// The reason that this is special is that we do not need to consider the
71+
// end of the borrow scope since the end of the function is the end of the
72+
// borrow scope.
73+
for (auto *Arg : F->getArguments()) {
74+
if (Arg->getOwnershipKind() != ValueOwnershipKind::Guaranteed)
75+
continue;
76+
MadeChange |= optimizeGuaranteedArgument(Arg);
77+
}
78+
79+
if (MadeChange) {
80+
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
81+
}
82+
}
83+
84+
StringRef getName() override { return "Semantic ARC Opts"; }
85+
};
86+
87+
} // end anonymous namespace
88+
89+
SILTransform *swift::createSemanticARCOpts() { return new SemanticARCOpts(); }

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,12 @@ static void addOwnershipModelEliminatorPipeline(SILPassPipelinePlan &P) {
7171
P.addOwnershipModelEliminator();
7272
}
7373

74-
static void addMandatoryOptPipeline(SILPassPipelinePlan &P) {
74+
static void addMandatoryOptPipeline(SILPassPipelinePlan &P,
75+
const SILOptions &Options) {
7576
P.startPipeline("Guaranteed Passes");
77+
if (Options.EnableMandatorySemanticARCOpts) {
78+
P.addSemanticARCOpts();
79+
}
7680
P.addCapturePromotion();
7781
P.addAllocBoxToStack();
7882

@@ -107,7 +111,7 @@ SILPassPipelinePlan::getDiagnosticPassPipeline(const SILOptions &Options) {
107111
}
108112

109113
// Otherwise run the rest of diagnostics.
110-
addMandatoryOptPipeline(P);
114+
addMandatoryOptPipeline(P, Options);
111115

112116
if (SILViewGuaranteedCFG) {
113117
addCFGPrinterPipeline(P, "SIL View Guaranteed CFG");
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all -enable-sil-ownership -semantic-arc-opts %s | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
7+
// CHECK-LABEL: sil @only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
8+
// CHECK-NOT: copy_value
9+
// CHECK-NOT: destroy_value
10+
sil @only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
11+
bb0(%0 : @guaranteed $Builtin.NativeObject):
12+
%1 = copy_value %0 : $Builtin.NativeObject
13+
destroy_value %1 : $Builtin.NativeObject
14+
%9999 = tuple()
15+
return %9999 : $()
16+
}
17+

0 commit comments

Comments
 (0)