File: escape_analysis_dead_store.sil

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (140 lines) | stat: -rw-r--r-- 6,489 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// RUN: %target-sil-opt %s -dead-store-elimination -enable-sil-verify-all | %FileCheck %s

// REQUIRES: swift_in_compiler

sil_stage canonical

import Builtin
import Swift
import SwiftShims

final class X {
  init()
}

public struct S {
  @_hasStorage var x: X { get set }
  @_hasStorage var i: Int { get set }
  init(x: X, i: Int)
}

@_hasStorage @_hasInitialValue var gg: X { get set }

@inline(never) func takex(_ x: X)

sil [noinline] @takeX : $@convention(thin) (@guaranteed X) -> ()

// Test that escape analysis does not consider an inout argument to
// escape at a call site even though it's reference-type field does
// escape. Dead store elimination asks MemoryBehaviorVisitor whether
// the apply may read from the inout argument. This call into
// canEscapeToUsePoint, which should return false because the inout
// structure itself is not exposed to the call, only it's
// reference-type field is.
//
// CHECK-LABEL: sil @testInoutNoEscape
// CHECK-NOT: store
// CHECK:     apply
// CHECK:     store
// CHECK-NOT: store
// CHECK:    } // end sil function 'testInoutNoEscape'
sil @testInoutNoEscape : $@convention(thin) (@inout S, @guaranteed S) -> () {
bb0(%0 : $*S, %1 : $S):
  %4 = struct_extract %1 : $S, #S.x
  %5 = struct_element_addr %0 : $*S, #S.x
  %6 = load %5 : $*X
  strong_retain %4 : $X
  strong_release %6 : $X
  store %1 to %0 : $*S
  %10 = function_ref @takeX : $@convention(thin) (@guaranteed X) -> ()
  strong_retain %4 : $X
  %12 = apply %10(%4) : $@convention(thin) (@guaranteed X) -> ()
  release_value %1 : $S
  store %1 to %0 : $*S
  %15 = tuple ()
  return %15 : $()
}

// =============================================================================
// Test that a store writing back into a container is not eliminated
// when the container's interior pointer later escapes into a function
// that reads from the pointer.

final internal class TestArrayContainer {
  @_hasStorage @_hasInitialValue internal final var pointer: UnsafeMutablePointer<Int32> { get set }
  @_hasStorage @_hasInitialValue internal final var storage: ContiguousArray<Int32> { get set }
  @_optimize(none) @inline(never) internal final func append(_ arg: Int32)
  internal final func va_list() -> UnsafeMutableRawPointer
  init()
}

sil @UnsafeMutablePointer_load_Int64 : $@convention(method) (Int64, UnsafeMutableRawPointer) -> Optional<UnsafeMutablePointer<Int32>> // user: %5
// ContiguousArray.append(_:)
sil @$ss15ContiguousArrayV6appendyyxnF : $@convention(method) <τ_0_0> (@in τ_0_0, @inout ContiguousArray<τ_0_0>) -> ()


// Helper that reads from a raw pointer.
sil hidden [noinline] @takeRawPtr : $@convention(thin) (UnsafeMutableRawPointer) -> Bool {
bb0(%0 : $UnsafeMutableRawPointer):
  %1 = integer_literal $Builtin.Int64, 0
  %2 = struct $Int64 (%1 : $Builtin.Int64)
  %3 = function_ref @UnsafeMutablePointer_load_Int64 : $@convention(method) (Int64, UnsafeMutableRawPointer) -> Optional<UnsafeMutablePointer<Int32>>
  %4 = apply %3(%2, %0) : $@convention(method) (Int64, UnsafeMutableRawPointer) -> Optional<UnsafeMutablePointer<Int32>> // users: %18, %6
  %5 = integer_literal $Builtin.Int1, -1
  %6 = struct $Bool (%5 : $Builtin.Int1)
  return %6 : $Bool
}

// TestArrayContainer.append(_:)
// Helper that produces a nonempty array.
sil hidden [noinline] [Onone] @TestArrayContainer_append : $@convention(method) (Int32, @guaranteed TestArrayContainer) -> () {
bb0(%0 : $Int32, %1 : $TestArrayContainer):
  %2 = alloc_stack $Int32
  store %0 to %2 : $*Int32
  %4 = ref_element_addr %1 : $TestArrayContainer, #TestArrayContainer.storage
  %5 = function_ref @$ss15ContiguousArrayV6appendyyxnF : $@convention(method) <τ_0_0> (@in τ_0_0, @inout ContiguousArray<τ_0_0>) -> ()
  %6 = apply %5<Int32>(%2, %4) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout ContiguousArray<τ_0_0>) -> ()
  dealloc_stack %2 : $*Int32
  %8 = tuple ()
  return %8 : $()
}

// CHECK-LABEL: sil [noinline] @testContainerPointer : $@convention(thin) () -> Bool {
// CHECK: [[ALLOC:%.*]] = alloc_ref [stack] $TestArrayContainer
// CHECK: [[PTR:%.*]] = ref_element_addr %0 : $TestArrayContainer, #TestArrayContainer.pointer
// CHECK: [[LOAD:%.*]] = load %{{.*}} : $*__ContiguousArrayStorageBase
// CHECK: [[ELTS:%.*]] = ref_tail_addr [[LOAD]] : $__ContiguousArrayStorageBase, $Int32
// CHECK: [[ELTPTR:%.*]] = address_to_pointer [[ELTS]] : $*Int32 to $Builtin.RawPointer
// CHECK: [[UMP:%.*]] = struct $UnsafeMutablePointer<Int32> ([[ELTPTR]] : $Builtin.RawPointer)
// CHECK: store [[UMP]] to [[PTR]] : $*UnsafeMutablePointer<Int32>
// CHECK: [[F:%.*]] = function_ref @takeRawPtr : $@convention(thin) (UnsafeMutableRawPointer) -> Bool
// CHECK: apply [[F]](%{{.*}}) : $@convention(thin) (UnsafeMutableRawPointer) -> Bool
// CHECK: fix_lifetime %0 : $TestArrayContainer
// CHECK-LABEL: } // end sil function 'testContainerPointer'
sil [noinline] @testContainerPointer : $@convention(thin) () -> Bool {
bb0:
  %0 = alloc_ref [stack] $TestArrayContainer
  %1 = ref_element_addr %0 : $TestArrayContainer, #TestArrayContainer.pointer
  %2 = ref_element_addr %0 : $TestArrayContainer, #TestArrayContainer.storage
  %3 = integer_literal $Builtin.Int32, 42
  %4 = struct $Int32 (%3 : $Builtin.Int32)
  %5 = function_ref @TestArrayContainer_append : $@convention(method) (Int32, @guaranteed TestArrayContainer) -> ()
  %6 = apply %5(%4, %0) : $@convention(method) (Int32, @guaranteed TestArrayContainer) -> ()
  %7 = struct_element_addr %2 : $*ContiguousArray<Int32>, #ContiguousArray._buffer
  %8 = struct_element_addr %7 : $*_ContiguousArrayBuffer<Int32>, #_ContiguousArrayBuffer._storage
  %9 = load %8 : $*__ContiguousArrayStorageBase
  %10 = ref_tail_addr %9 : $__ContiguousArrayStorageBase, $Int32
  %11 = address_to_pointer %10 : $*Int32 to $Builtin.RawPointer
  %12 = struct $UnsafeMutablePointer<Int32> (%11 : $Builtin.RawPointer)
  store %12 to %1 : $*UnsafeMutablePointer<Int32>
  %14 = address_to_pointer %1 : $*UnsafeMutablePointer<Int32> to $Builtin.RawPointer
  %15 = struct $UnsafeMutableRawPointer (%14 : $Builtin.RawPointer)
  %16 = function_ref @takeRawPtr : $@convention(thin) (UnsafeMutableRawPointer) -> Bool
  %17 = apply %16(%15) : $@convention(thin) (UnsafeMutableRawPointer) -> Bool
  fix_lifetime %0 : $TestArrayContainer
  %19 = begin_dealloc_ref %0 : $TestArrayContainer of %0 : $TestArrayContainer
  strong_release %9 : $__ContiguousArrayStorageBase
  dealloc_ref %19 : $TestArrayContainer
  dealloc_stack_ref %0 : $TestArrayContainer
  return %17 : $Bool
}