Skip to content

Commit 0603991

Browse files
authored
Merge pull request #40162 from gottesmm/pr-7573070cdfd753af9f3f7dc3bf3a5f64359710c1
[moveOnly] Add a new pass called the LexicalLifetimeEliminator that runs after we finish lexical diagnostics.
2 parents fb88ace + d526f36 commit 0603991

File tree

6 files changed

+125
-0
lines changed

6 files changed

+125
-0
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,10 @@ class AllocStackInst final
19491949
/// Whether the alloc_stack instruction corresponds to a source-level VarDecl.
19501950
bool isLexical() const { return lexical; }
19511951

1952+
/// If this is a lexical borrow, eliminate the lexical bit. If this borrow
1953+
/// doesn't have a lexical bit, do not do anything.
1954+
void removeIsLexical() { lexical = false; }
1955+
19521956
/// Return the debug variable information attached to this instruction.
19531957
Optional<SILDebugVariable> getVarInfo() const {
19541958
Optional<SILType> AuxVarType;
@@ -4033,6 +4037,10 @@ class BeginBorrowInst
40334037
/// source-level lexical scope.
40344038
bool isLexical() const { return lexical; }
40354039

4040+
/// If this is a lexical borrow, eliminate the lexical bit. If this borrow
4041+
/// doesn't have a lexical bit, do not do anything.
4042+
void removeIsLexical() { lexical = false; }
4043+
40364044
/// Return a range over all EndBorrow instructions for this BeginBorrow.
40374045
EndBorrowRange getEndBorrows() const;
40384046

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ PASS(MoveOnlyChecker, "sil-move-only-checker",
425425
PASS(MoveKillsCopyableValuesChecker, "sil-move-kills-copyable-values-checker",
426426
"Pass that checks that any copyable (non-move only) value that is passed "
427427
"to _move do not have any uses later than the _move")
428+
PASS(LexicalLifetimeEliminator, "sil-lexical-lifetime-eliminator",
429+
"Pass that removes lexical lifetime markers from borrows and alloc stack")
428430
PASS(PruneVTables, "prune-vtables",
429431
"Mark class methods that do not require vtable dispatch")
430432
PASS_RANGE(AllPasses, AADumper, PruneVTables)

lib/SILOptimizer/Mandatory/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ target_sources(swiftSILOptimizer PRIVATE
1515
DiagnoseUnreachable.cpp
1616
Differentiation.cpp
1717
IRGenPrepare.cpp
18+
LexicalLifetimeEliminator.cpp
1819
LowerHopToActor.cpp
1920
MandatoryInlining.cpp
2021
MoveOnlyChecker.cpp
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===--- LexicalLifetimeEliminator.cpp ------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 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-lexical-lifetime-eliminator"
14+
15+
#include "swift/SILOptimizer/PassManager/Transforms.h"
16+
17+
using namespace swift;
18+
19+
namespace {
20+
21+
class LexicalLifetimeEliminatorPass : public SILFunctionTransform {
22+
void run() override {
23+
auto *fn = getFunction();
24+
25+
// If we are already canonical, we do not have any diagnostics to emit.
26+
if (fn->wasDeserializedCanonical())
27+
return;
28+
29+
// If we have experimental lexical lifetimes enabled, we do not want to run
30+
// this pass since we want lexical lifetimes to exist later in the pipeline.
31+
if (fn->getModule().getOptions().EnableExperimentalLexicalLifetimes)
32+
return;
33+
34+
bool madeChange = false;
35+
for (auto &block : *fn) {
36+
for (auto &inst : block) {
37+
if (auto *bbi = dyn_cast<BeginBorrowInst>(&inst)) {
38+
if (bbi->isLexical()) {
39+
bbi->removeIsLexical();
40+
madeChange = true;
41+
}
42+
continue;
43+
}
44+
45+
if (auto *asi = dyn_cast<AllocStackInst>(&inst)) {
46+
if (asi->isLexical()) {
47+
asi->removeIsLexical();
48+
madeChange = true;
49+
}
50+
continue;
51+
}
52+
}
53+
}
54+
55+
if (madeChange) {
56+
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
57+
}
58+
}
59+
};
60+
61+
} // anonymous namespace
62+
63+
SILTransform *swift::createLexicalLifetimeEliminator() {
64+
return new LexicalLifetimeEliminatorPass();
65+
}

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ static void addMandatoryDiagnosticOptPipeline(SILPassPipelinePlan &P) {
169169
// value.
170170
P.addMoveOnlyChecker(); // Check noImplicitCopy isn't copied.
171171

172+
// Now that we have finished performing diagnostics that rely on lexical
173+
// scopes, if lexical lifetimes are not enabled, eliminate lexical lfietimes.
174+
if (!Options.EnableExperimentalLexicalLifetimes) {
175+
P.addLexicalLifetimeEliminator();
176+
}
177+
172178
P.addOptimizeHopToExecutor();
173179
P.addMandatoryGenericSpecializer();
174180

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-sil-opt -sil-lexical-lifetime-eliminator %s -enable-sil-verify-all | %FileCheck %s
2+
3+
sil_stage raw
4+
5+
import Builtin
6+
7+
class Klass {}
8+
9+
// CHECK-LABEL: sil [ossa] @lexical_lifetime_object : $@convention(thin) (@owned Klass) -> () {
10+
// CHECK: bb0(%0 : @owned $Klass):
11+
// CHECK-NEXT: %1 = begin_borrow %0 : $Klass
12+
// CHECK-NEXT: end_borrow %1 : $Klass
13+
// CHECK-NEXT: destroy_value %0 : $Klass
14+
// CHECK-NEXT: tuple ()
15+
// CHECK-NEXT: return
16+
// CHECK-NEXT: }
17+
sil [ossa] @lexical_lifetime_object : $@convention(thin) (@owned Klass) -> () {
18+
bb0(%0 : @owned $Klass):
19+
%1 = begin_borrow [lexical] %0 : $Klass
20+
end_borrow %1 : $Klass
21+
destroy_value %0 : $Klass
22+
%9999 = tuple()
23+
return %9999 : $()
24+
}
25+
26+
// CHECK-LABEL: sil [ossa] @lexical_lifetime_address : $@convention(thin) (@in Klass) -> () {
27+
// CHECK: bb0(%0 : $*Klass):
28+
// CHECK-NEXT: %1 = alloc_stack $Klass
29+
// CHECK-NEXT: copy_addr [take] %0 to [initialization] %1 : $*Klass
30+
// CHECK-NEXT: destroy_addr %1 : $*Klass
31+
// CHECK-NEXT: dealloc_stack %1 : $*Klass
32+
// CHECK-NEXT: tuple ()
33+
// CHECK-NEXT: return
34+
// CHECK-NEXT: }
35+
sil [ossa] @lexical_lifetime_address : $@convention(thin) (@in Klass) -> () {
36+
bb0(%0 : $*Klass):
37+
%1 = alloc_stack [lexical] $Klass
38+
copy_addr [take] %0 to [initialization] %1 : $*Klass
39+
destroy_addr %1 : $*Klass
40+
dealloc_stack %1 : $*Klass
41+
%9999 = tuple()
42+
return %9999 : $()
43+
}

0 commit comments

Comments
 (0)