Skip to content

Commit e46ab4b

Browse files
authored
Merge pull request swiftlang#34787 from gottesmm/pr-aa2767f26b092e40ae7b044c1ac4bf2c1f02e1c8
[ownership] Teach CanonicalizeInstruction how to eliminate trivial copies/borrows.
2 parents 3706644 + ec71713 commit e46ab4b

File tree

7 files changed

+134
-59
lines changed

7 files changed

+134
-59
lines changed

lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,65 @@ broadenSingleElementStores(StoreInst *storeInst,
383383
return killInstruction(storeInst, nextII, pass);
384384
}
385385

386+
//===----------------------------------------------------------------------===//
387+
// Simple ARC Peepholes
388+
//===----------------------------------------------------------------------===//
389+
390+
static SILBasicBlock::iterator
391+
eliminateSimpleCopies(CopyValueInst *cvi, CanonicalizeInstruction &pass) {
392+
auto next = std::next(cvi->getIterator());
393+
394+
// Eliminate copies that only have destroy_value uses.
395+
SmallVector<DestroyValueInst *, 8> destroys;
396+
for (auto *use : getNonDebugUses(cvi)) {
397+
if (auto *dvi = dyn_cast<DestroyValueInst>(use->getUser())) {
398+
destroys.push_back(dvi);
399+
continue;
400+
}
401+
return next;
402+
}
403+
404+
while (!destroys.empty()) {
405+
next = killInstruction(destroys.pop_back_val(), next, pass);
406+
}
407+
408+
next = killInstAndIncidentalUses(cvi, next, pass);
409+
return next;
410+
}
411+
412+
static SILBasicBlock::iterator
413+
eliminateSimpleBorrows(BeginBorrowInst *bbi, CanonicalizeInstruction &pass) {
414+
auto next = std::next(bbi->getIterator());
415+
416+
// We know that our borrow is completely within the lifetime of its base value
417+
// if the borrow is never reborrowed. We check for reborrows and do not
418+
// optimize such cases. Otherwise, we can eliminate our borrow and instead use
419+
// our operand.
420+
auto base = bbi->getOperand();
421+
auto baseOwnership = base.getOwnershipKind();
422+
SmallVector<EndBorrowInst *, 8> endBorrows;
423+
for (auto *use : getNonDebugUses(bbi)) {
424+
if (auto *ebi = dyn_cast<EndBorrowInst>(use->getUser())) {
425+
endBorrows.push_back(ebi);
426+
continue;
427+
}
428+
429+
// Otherwise, if we have a use that is non-lifetime ending and can accept
430+
// our base ownership, continue.
431+
if (!use->isLifetimeEnding() && use->canAcceptKind(baseOwnership))
432+
continue;
433+
434+
return next;
435+
}
436+
437+
while (!endBorrows.empty()) {
438+
next = killInstruction(endBorrows.pop_back_val(), next, pass);
439+
}
440+
bbi->replaceAllUsesWith(base);
441+
pass.notifyHasNewUsers(base);
442+
return killInstruction(bbi, next, pass);
443+
}
444+
386445
//===----------------------------------------------------------------------===//
387446
// Top-Level Entry Point
388447
//===----------------------------------------------------------------------===//
@@ -398,6 +457,12 @@ CanonicalizeInstruction::canonicalize(SILInstruction *inst) {
398457
if (auto *storeInst = dyn_cast<StoreInst>(inst))
399458
return broadenSingleElementStores(storeInst, *this);
400459

460+
if (auto *cvi = dyn_cast<CopyValueInst>(inst))
461+
return eliminateSimpleCopies(cvi, *this);
462+
463+
if (auto *bbi = dyn_cast<BeginBorrowInst>(inst))
464+
return eliminateSimpleBorrows(bbi, *this);
465+
401466
// Skip ahead.
402467
return std::next(inst->getIterator());
403468
}

test/AutoDiff/SILOptimizer/activity_analysis.swift

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -347,31 +347,29 @@ func testArrayUninitializedIntrinsicNested(_ x: Float, _ y: Float) -> [Float] {
347347
// CHECK: [VARIED] %11 = integer_literal $Builtin.Word, 1
348348
// CHECK: [ACTIVE] %12 = index_addr %9 : $*Float, %11 : $Builtin.Word
349349
// CHECK: [NONE] // function_ref _finalizeUninitializedArray<A>(_:)
350-
// CHECK: [ACTIVE] %15 = apply %14<Float>(%7) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
350+
// CHECK: [ACTIVE] [[ARRAY:%.*]] = apply %14<Float>(%7) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
351351
// CHECK: [USEFUL] %17 = integer_literal $Builtin.Word, 2
352352
// CHECK: [NONE] // function_ref _allocateUninitializedArray<A>(_:)
353353
// CHECK: [ACTIVE] %19 = apply %18<Float>(%17) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
354354
// CHECK: [ACTIVE] (**%20**, %21) = destructure_tuple %19 : $(Array<Float>, Builtin.RawPointer)
355355
// CHECK: [VARIED] (%20, **%21**) = destructure_tuple %19 : $(Array<Float>, Builtin.RawPointer)
356356
// CHECK: [ACTIVE] %22 = pointer_to_address %21 : $Builtin.RawPointer to [strict] $*Float
357-
// CHECK: [ACTIVE] %23 = begin_borrow %15 : $Array<Float>
358-
// CHECK: [USEFUL] %24 = integer_literal $Builtin.IntLiteral, 0
359-
// CHECK: [USEFUL] %25 = metatype $@thin Int.Type
357+
// CHECK: [USEFUL] %23 = integer_literal $Builtin.IntLiteral, 0
358+
// CHECK: [USEFUL] %24 = metatype $@thin Int.Type
360359
// CHECK: [NONE] // function_ref Int.init(_builtinIntegerLiteral:)
361-
// CHECK: [USEFUL] %27 = apply %26(%24, %25) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
360+
// CHECK: [USEFUL] %26 = apply %25(%23, %24) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
362361
// CHECK: [NONE] // function_ref Array.subscript.getter
363-
// CHECK: [NONE] %29 = apply %28<Float>(%22, %27, %23) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
364-
// CHECK: [VARIED] %30 = integer_literal $Builtin.Word, 1
365-
// CHECK: [ACTIVE] %31 = index_addr %22 : $*Float, %30 : $Builtin.Word
366-
// CHECK: [ACTIVE] %32 = begin_borrow %15 : $Array<Float>
367-
// CHECK: [USEFUL] %33 = integer_literal $Builtin.IntLiteral, 1
368-
// CHECK: [USEFUL] %34 = metatype $@thin Int.Type
362+
// CHECK: [NONE] %28 = apply %27<Float>(%22, %26, %15) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
363+
// CHECK: [VARIED] %29 = integer_literal $Builtin.Word, 1
364+
// CHECK: [ACTIVE] %30 = index_addr %22 : $*Float, %29 : $Builtin.Word
365+
// CHECK: [USEFUL] %31 = integer_literal $Builtin.IntLiteral, 1
366+
// CHECK: [USEFUL] %32 = metatype $@thin Int.Type
369367
// CHECK: [NONE] // function_ref Int.init(_builtinIntegerLiteral:)
370-
// CHECK: [USEFUL] %36 = apply %35(%33, %34) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
368+
// CHECK: [USEFUL] %34 = apply %33(%31, %32) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
371369
// CHECK: [NONE] // function_ref Array.subscript.getter
372-
// CHECK: [NONE] %38 = apply %37<Float>(%31, %36, %32) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
370+
// CHECK: [NONE] %36 = apply %35<Float>(%30, %34, %15) : $@convention(method) <τ_0_0> (Int, @guaranteed Array<τ_0_0>) -> @out τ_0_0
373371
// CHECK: [NONE] // function_ref _finalizeUninitializedArray<A>(_:)
374-
// CHECK: [ACTIVE] %40 = apply %39<Float>(%20) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
372+
// CHECK: [ACTIVE] %38 = apply %37<Float>(%20) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
375373

376374
// TF-978: Test array literal initialized with `apply` indirect results.
377375
struct Wrapper<T: Differentiable>: Differentiable {
@@ -733,16 +731,13 @@ func testClassModifyAccessor(_ c: inout C) {
733731
// CHECK: [VARIED] %4 = load [copy] %3 : $*C
734732
// CHECK: [ACTIVE] %6 = begin_access [read] [static] %0 : $*C
735733
// CHECK: [VARIED] %7 = load [copy] %6 : $*C
736-
// CHECK: [VARIED] %9 = begin_borrow %7 : $C
737-
// CHECK: [VARIED] %10 = class_method %9 : $C, #C.float!getter : (C) -> () -> Float, $@convention(method) (@guaranteed C) -> Float
738-
// CHECK: [VARIED] %11 = apply %10(%9) : $@convention(method) (@guaranteed C) -> Float
739-
// CHECK: [VARIED] %14 = begin_borrow %4 : $C
740-
// CHECK: [VARIED] %15 = class_method %14 : $C, #C.float!modify : (C) -> () -> (), $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
741-
// CHECK: [VARIED] (**%16**, %17) = begin_apply %15(%14) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
742-
// CHECK: [VARIED] (%16, **%17**) = begin_apply %15(%14) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
734+
// CHECK: [VARIED] %9 = class_method %7 : $C, #C.float!getter : (C) -> () -> Float, $@convention(method) (@guaranteed C) -> Float
735+
// CHECK: [VARIED] %10 = apply %9(%7) : $@convention(method) (@guaranteed C) -> Float
736+
// CHECK: [VARIED] %12 = class_method %4 : $C, #C.float!modify : (C) -> () -> (), $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
737+
// CHECK: [VARIED] (**%13**, %14) = begin_apply %12(%4) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
738+
// CHECK: [VARIED] (%13, **%14**) = begin_apply %12(%4) : $@yield_once @convention(method) (@guaranteed C) -> @yields @inout Float
743739
// CHECK: [NONE] // function_ref static Float.*= infix(_:_:)
744-
// CHECK: [NONE] %19 = apply %18(%16, %11, %2) : $@convention(method) (@inout Float, Float, @thin Float.Type) -> ()
745-
// CHECK: [NONE] %23 = tuple ()
740+
// CHECK: [NONE] %16 = apply %15(%13, %10, %2) : $@convention(method) (@inout Float, Float, @thin Float.Type) -> ()
746741

747742
//===----------------------------------------------------------------------===//
748743
// Enum differentiation

test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ func modify(_ s: Struct, _ x: Float) -> Float {
714714
func tupleArrayLiteralInitialization(_ x: Float, _ y: Float) -> Float {
715715
// `Array<(Float, Float)>` does not conform to `Differentiable`.
716716
let array = [(x * y, x * y)]
717-
// expected-note @+1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{10-10=withoutDerivative(at: }} {{15-15=)}}
717+
// expected-note @-1 {{cannot differentiate through a non-differentiable argument; do you want to use 'withoutDerivative(at:)'?}} {{15-15=withoutDerivative(at: }} {{31-31=)}}
718718
return array[0].0
719719
}
720720

test/IRGen/alloc_box.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -primary-file %s -emit-ir -o - | %FileCheck %s
1+
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=SILGenCleanup -primary-file %s -emit-ir -o - | %FileCheck %s
22

33
func f() -> Bool? { return nil }
44

test/SILOptimizer/capturepromotion-wrong-lexicalscope.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
// CHECK: destroy_value %7 : ${ var Int }, loc {{.*}}:33:11, scope 3
2020
// CHECK: %13 = partial_apply [callee_guaranteed] %10(%11) : $@convention(thin) (Int) -> Int, loc {{.*}}:33:11, scope 3
2121
// CHECK: debug_value %13 : $@callee_guaranteed () -> Int, let, name "f", loc {{.*}}:33:7, scope 3
22-
// CHECK: %15 = begin_borrow %13 : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 3
23-
// CHECK: %16 = copy_value %15 : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 3
24-
// CHECK: end_borrow %15 : $@callee_guaranteed () -> Int
22+
// There used to be a begin_borrow here. We leave an emptyline here to preserve line numbers.
23+
// CHECK: %15 = copy_value %13 : $@callee_guaranteed () -> Int, loc {{.*}}:34:10, scope 3
24+
// There used to be an end_borrow here. We leave an emptyline here to preserve line numbers.
2525
// CHECK: destroy_value %13 : $@callee_guaranteed () -> Int, loc {{.*}}:35:1, scope 3
2626
// CHECK: destroy_value %0 : ${ var Int }, loc {{.*}}:35:1, scope 3
27-
// CHECK: return %16 : $@callee_guaranteed () -> Int, loc {{.*}}:34:3, scope 3
27+
// CHECK: return %15 : $@callee_guaranteed () -> Int, loc {{.*}}:34:3, scope 3
2828
// CHECK: }
2929

3030

test/SILOptimizer/constantprop-wrongscope.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// instructions surrounding it.
1414

1515
// CHECK: destroy_addr %7 : $*Any, loc {{.*}}:22:19, scope 2
16-
// CHECK: dealloc_stack %13 : $*Optional<Any>, loc {{.*}}:22:23, scope 2
16+
// CHECK: dealloc_stack %12 : $*Optional<Any>, loc {{.*}}:22:23, scope 2
1717
// CHECK: dealloc_stack %7 : $*Any, loc {{.*}}:22:23, scope 2
1818
// CHECK: dealloc_stack %6 : $*A, loc {{.*}}:22:7, scope 2
1919

test/SILOptimizer/silgen_cleanup.sil

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,27 @@ import Builtin
44

55
sil_stage raw
66

7-
import Swift
8-
import SwiftShims
7+
class Klass {}
8+
class SubKlass : Klass {}
9+
10+
sil @use_klass_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
11+
sil @use_klass_owned : $@convention(thin) (@owned Klass) -> ()
12+
sil @use_klass_unowned : $@convention(thin) (Klass) -> ()
13+
14+
enum FakeOptional<T> {
15+
case none
16+
case some(T)
17+
}
18+
19+
sil @use_fakeoptional_klass_guaranteed : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
20+
21+
struct Int {
22+
var _value : Builtin.Int32
23+
}
24+
25+
struct UInt8 {
26+
var _value : Builtin.Int8
27+
}
928

1029
// CHECK-LABEL: sil [ossa] @struct_extract_load_to_load_struct_element_addr
1130
// CHECK: bb0([[IN:%[0-9]+]] : $*UInt8):
@@ -91,30 +110,26 @@ bb0(%0 : $*(Builtin.Int8, Builtin.Int8)):
91110

92111
struct X1 {
93112
@_hasStorage @_hasInitialValue let a: Int { get }
94-
@_hasStorage @_hasInitialValue var obj1: AnyObject { get set }
95-
@_hasStorage @_hasInitialValue var obj2: AnyObject { get set }
96-
init(a: Int, obj1: AnyObject, obj2: AnyObject)
113+
@_hasStorage @_hasInitialValue var obj1: Builtin.NativeObject { get set }
114+
@_hasStorage @_hasInitialValue var obj2: Builtin.NativeObject { get set }
115+
init(a: Int, obj1: Builtin.NativeObject, obj2: Builtin.NativeObject)
97116
}
98117

99-
// CHECK-LABEL: sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned AnyObject, @owned AnyObject) {
118+
// CHECK-LABEL: sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned Builtin.NativeObject, @owned Builtin.NativeObject) {
100119
// CHECK-LABEL: bb0(%0 : $*X1):
101120
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] %0 : $*X1
102121
// CHECK: [[AA:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.a
103122
// CHECK: load [trivial] [[AA]] : $*Int
104123
// CHECK: [[OA1:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.obj1
105-
// CHECK: [[OV1:%.*]] = load [copy] [[OA1]] : $*AnyObject
124+
// CHECK: [[OV1:%.*]] = load [copy] [[OA1]] : $*Builtin.NativeObject
106125
// CHECK: [[OA2:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.obj2
107-
// CHECK: [[OV2:%.*]] = load [copy] [[OA2]] : $*AnyObject
126+
// CHECK: [[OV2:%.*]] = load [copy] [[OA2]] : $*Builtin.NativeObject
108127
// CHECK: end_access [[ACCESS]] : $*X1
109-
// CHECK: [[B1:%.*]] = begin_borrow [[OV1]] : $AnyObject
110-
// CHECK: copy_value [[B1]] : $AnyObject
111-
// CHECK: end_borrow [[B1]] : $AnyObject
112-
// CHECK: [[B2:%.*]] = begin_borrow [[OV2]] : $AnyObject
113-
// CHECK: copy_value [[B2]] : $AnyObject
114-
// CHECK: end_borrow [[B2]] : $AnyObject
128+
// CHECK: copy_value [[OV1]] : $Builtin.NativeObject
129+
// CHECK: copy_value [[OV2]] : $Builtin.NativeObject
115130
// CHECK: return
116131
// CHECK-LABEL: } // end sil function 'testLoadNontrivial'
117-
sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned AnyObject, @owned AnyObject) {
132+
sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned Builtin.NativeObject, @owned Builtin.NativeObject) {
118133
bb0(%0 : $*X1):
119134
%access = begin_access [read] [unknown] %0 : $*X1
120135
%load = load [copy] %access : $*X1
@@ -126,44 +141,44 @@ bb0(%0 : $*X1):
126141

127142
%borrow1 = begin_borrow %load : $X1
128143
%o1 = struct_extract %borrow1 : $X1, #X1.obj1
129-
%copy1 = copy_value %o1 : $AnyObject
144+
%copy1 = copy_value %o1 : $Builtin.NativeObject
130145
end_borrow %borrow1 : $X1
131146

132147
%borrow2 = begin_borrow %load : $X1
133148
%o2 = struct_extract %borrow2 : $X1, #X1.obj2
134-
%copy2 = copy_value %o2 : $AnyObject
149+
%copy2 = copy_value %o2 : $Builtin.NativeObject
135150
end_borrow %borrow2 : $X1
136151

137152
destroy_value %load : $X1
138153

139-
%result = tuple (%a : $Int, %copy1 : $AnyObject, %copy2 : $AnyObject)
140-
return %result : $(Int, AnyObject, AnyObject)
154+
%result = tuple (%a : $Int, %copy1 : $Builtin.NativeObject, %copy2 : $Builtin.NativeObject)
155+
return %result : $(Int, Builtin.NativeObject, Builtin.NativeObject)
141156
}
142157

143158
struct X2 {
144-
@_hasStorage @_hasInitialValue var obj: AnyObject { get set }
159+
@_hasStorage @_hasInitialValue var obj: Builtin.NativeObject { get set }
145160
}
146161

147162
struct X3 {
148163
@_hasStorage @_hasInitialValue var x2: X2 { get set }
149164
}
150165

151-
// CHECK-LABEL: sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed AnyObject) -> () {
152-
// CHECK-LABEL: bb0(%0 : $*X3, %1 : @guaranteed $AnyObject):
153-
// CHECK: [[CP:%.*]] = copy_value %1 : $AnyObject
166+
// CHECK-LABEL: sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed Builtin.NativeObject) -> () {
167+
// CHECK: bb0(%0 : $*X3, %1 : @guaranteed $Builtin.NativeObject):
168+
// CHECK: [[CP:%.*]] = copy_value %1 : $Builtin.NativeObject
154169
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] %0 : $*X3
155-
// CHECK: [[X2:%.*]] = struct $X2 ([[CP]] : $AnyObject)
170+
// CHECK: [[X2:%.*]] = struct $X2 ([[CP]] : $Builtin.NativeObject)
156171
// CHECK: [[X3:%.*]] = struct $X3 ([[X2]] : $X2)
157172
// CHECK: store [[X3]] to [assign] [[ACCESS]] : $*X3
158173
// CHECK: end_access [[ACCESS]] : $*X3
159-
// CHECK-LABEL: } // end sil function 'testStoreNontrivial'
160-
sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed AnyObject) -> () {
161-
bb0(%0 : $*X3, %1 : @guaranteed $AnyObject):
162-
%4 = copy_value %1 : $AnyObject
174+
// CHECK: } // end sil function 'testStoreNontrivial'
175+
sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed Builtin.NativeObject) -> () {
176+
bb0(%0 : $*X3, %1 : @guaranteed $Builtin.NativeObject):
177+
%4 = copy_value %1 : $Builtin.NativeObject
163178
%5 = begin_access [modify] [unknown] %0 : $*X3
164179
%6 = struct_element_addr %5 : $*X3, #X3.x2
165180
%7 = struct_element_addr %6 : $*X2, #X2.obj
166-
store %4 to [assign] %7 : $*AnyObject
181+
store %4 to [assign] %7 : $*Builtin.NativeObject
167182
end_access %5 : $*X3
168183
%12 = tuple ()
169184
return %12 : $()

0 commit comments

Comments
 (0)