Skip to content

Commit ae27805

Browse files
committed
Add an experimental pass to lower allocateVector builtins
By default it lowers the builtin to an `alloc_vector` with a paired `dealloc_stack`. If the builtin appears in the initializer of a global variable and the vector elements are initialized, a statically initialized global is created where the initializer is a `vector` instruction.
1 parent 43c4fce commit ae27805

File tree

10 files changed

+1276
-0
lines changed

10 files changed

+1276
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocVectorLowering.swift

Lines changed: 457 additions & 0 deletions
Large diffs are not rendered by default.

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
88

99
swift_compiler_sources(Optimizer
10+
AllocVectorLowering.swift
1011
AssumeSingleThreaded.swift
1112
AsyncDemotion.swift
1213
CleanupDebugSteps.swift

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ private func registerSwiftPasses() {
6565
registerPass(stackProtection, { stackProtection.run($0) })
6666

6767
// Function passes
68+
registerPass(allocVectorLowering, { allocVectorLowering.run($0) })
6869
registerPass(asyncDemotion, { asyncDemotion.run($0) })
6970
registerPass(letPropertyLowering, { letPropertyLowering.run($0) })
7071
registerPass(mergeCondFailsPass, { mergeCondFailsPass.run($0) })

include/swift/AST/DiagnosticsSIL.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,5 +899,13 @@ ERROR(regionbasedisolation_unknown_pattern, none,
899899
ERROR(deinit_not_visible, none,
900900
"deinit of non-copyable type not visible in the current module", ())
901901

902+
ERROR(lifetime_value_outside_scope, none,
903+
"lifetime-dependent value escapes its scope", ())
904+
ERROR(vector_capacity_not_constant, none,
905+
"vector capacity needs to be constant", ())
906+
907+
ERROR(fixed_arrays_not_available, none,
908+
"fixed arrays are only available with -enable-experimental-feature FixedArrays", ())
909+
902910
#define UNDEFINE_DIAGNOSTIC_MACROS
903911
#include "DefineDiagnosticMacros.h"

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,8 @@ SWIFT_FUNCTION_PASS(NamedReturnValueOptimization, "named-return-value-optimizati
411411
"Optimize copies to an indirect return value")
412412
SWIFT_FUNCTION_PASS(StripObjectHeaders, "strip-object-headers",
413413
"Sets the bare flag on objects which don't need their headers")
414+
SWIFT_FUNCTION_PASS(AllocVectorLowering, "alloc-vector-lowering",
415+
"lowering of allocVector builtins")
414416
PASS(SimplifyBBArgs, "simplify-bb-args",
415417
"SIL Block Argument Simplification")
416418
PASS(SimplifyCFG, "simplify-cfg",

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ static void addMandatoryDiagnosticOptPipeline(SILPassPipelinePlan &P) {
253253

254254
P.addMandatoryPerformanceOptimizations();
255255
P.addOnoneSimplification();
256+
P.addAllocVectorLowering();
256257
P.addInitializeStaticGlobals();
257258
P.addPerformanceDiagnostics();
258259
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// RUN: %target-sil-opt %s -alloc-vector-lowering -enable-experimental-feature FixedArrays | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
sil_stage canonical
6+
7+
import Builtin
8+
import Swift
9+
10+
@_moveOnly public struct FixedArray<T> {
11+
@_hasStorage let buffer: UnsafeMutablePointer<T> { get }
12+
@_hasStorage public let capacity: Int64 { get }
13+
@_hasStorage internal var _count: Int64 { get set }
14+
public struct _Literal {
15+
@_hasStorage let array: [T] { get }
16+
typealias ArrayLiteralElement = T
17+
}
18+
}
19+
20+
sil_global @global_fixed_array : $FixedArray<Int64>
21+
sil_global @global_fixed_array2 : $UnsafeMutablePointer<Int64>
22+
23+
// CHECK-LABEL: sil_global private @global_init_with_array_initializationTv_ : $Int64 = {
24+
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 1
25+
// CHECK-NEXT: %1 = struct $Int64 (%0 : $Builtin.Int64)
26+
// CHECK-NEXT: %2 = integer_literal $Builtin.Int64, 2
27+
// CHECK-NEXT: %3 = struct $Int64 (%2 : $Builtin.Int64)
28+
// CHECK-NEXT: %initval = vector (%1 : $Int64, %3 : $Int64)
29+
30+
// CHECK-LABEL: sil_global private @global_init_uninitializedTv_ : $Int64 = {
31+
// CHECK-NEXT: %0 = integer_literal $Builtin.Word, 10
32+
// CHECK-NEXT: %initval = alloc_vector $Int64, %0 : $Builtin.Word
33+
34+
sil [_semantics "array.uninitialized_intrinsic"] @alloc_uninitialized_array : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
35+
sil [_semantics "array.finalize_intrinsic"] @finalize_array : $@convention(thin) <Element> (@owned Array<Element>) -> @owned Array<Element>
36+
sil [_semantics "array.get_count"] @array_count : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> Int64
37+
sil [_semantics "array.copy_into_vector"] @array_copy_into_vector : $@convention(method) <Element> (UnsafeMutablePointer<Element>, @guaranteed Array<Element>) -> ()
38+
39+
// CHECK-LABEL: sil [ossa] @stack_allocated :
40+
// CHECK: [[C:%.*]] = integer_literal $Builtin.Word, 10
41+
// CHECK: [[V:%.*]] = alloc_vector $Int64, [[C]]
42+
// CHECK: bb1:
43+
// CHECK: dealloc_stack {{.*}} : $*Builtin.RawPointer
44+
// CHECK: dealloc_stack [[V]] : $*Int64
45+
// CHECK: bb2:
46+
// CHECK: dealloc_stack {{.*}} : $*Builtin.RawPointer
47+
// CHECK: dealloc_stack [[V]] : $*Int64
48+
// CHECK: bb3:
49+
// CHECK: } // end sil function 'stack_allocated'
50+
sil [ossa] @stack_allocated : $@convention(thin) () -> () {
51+
%8 = integer_literal $Builtin.Word, 10
52+
%9 = metatype $@thin Int64.Type
53+
%10 = builtin "allocVector"<Int64>(%9 : $@thin Int64.Type, %8 : $Builtin.Word) : $Builtin.RawPointer
54+
%11 = alloc_stack $Builtin.RawPointer
55+
store %10 to [trivial] %11 : $*Builtin.RawPointer
56+
cond_br undef, bb1, bb2
57+
bb1:
58+
dealloc_stack %11 : $*Builtin.RawPointer
59+
br bb3
60+
bb2:
61+
dealloc_stack %11 : $*Builtin.RawPointer
62+
br bb3
63+
bb3:
64+
%r = tuple()
65+
return %r : $()
66+
}
67+
68+
// CHECK-LABEL: sil [global_init_once_fn] [ossa] @global_init_with_array_initialization :
69+
// CHECK: [[G:%.*]] = global_addr @global_init_with_array_initializationTv_
70+
// CHECK: [[P:%.*]] = address_to_pointer [[G]]
71+
// CHECK: [[UMP:%.*]] = struct $UnsafeMutablePointer<Int64> ([[P]] : $Builtin.RawPointer)
72+
// CHECK: [[BA:%.*]] = struct_element_addr {{%.*}} : $*FixedArray<Int64>, #FixedArray.buffer
73+
// CHECK store [[UMP]] to [trivial] [[BA]]
74+
// CHECK: } // end sil function 'global_init_with_array_initialization'
75+
sil [global_init_once_fn] [ossa] @global_init_with_array_initialization : $@convention(thin) () -> () {
76+
bb0:
77+
alloc_global @global_fixed_array
78+
%2 = global_addr @global_fixed_array : $*FixedArray<Int64>
79+
%3 = integer_literal $Builtin.Word, 2
80+
%4 = function_ref @alloc_uninitialized_array : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
81+
%5 = apply %4<Int64>(%3) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer)
82+
(%6, %7) = destructure_tuple %5 : $(Array<Int64>, Builtin.RawPointer)
83+
%8 = mark_dependence %7 : $Builtin.RawPointer on %6 : $Array<Int64>
84+
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Int64
85+
%10 = integer_literal $Builtin.Int64, 1
86+
%11 = struct $Int64 (%10 : $Builtin.Int64)
87+
store %11 to [trivial] %9 : $*Int64
88+
%13 = integer_literal $Builtin.Word, 1
89+
%14 = index_addr %9 : $*Int64, %13 : $Builtin.Word
90+
%15 = integer_literal $Builtin.Int64, 2
91+
%16 = struct $Int64 (%15 : $Builtin.Int64)
92+
store %16 to [trivial] %14 : $*Int64
93+
%23 = function_ref @finalize_array : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
94+
%24 = apply %23<Int64>(%6) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0>
95+
%25 = copy_value %24 : $Array<Int64>
96+
%34 = struct $FixedArray<Int64>._Literal (%25 : $Array<Int64>)
97+
destroy_value %34 : $FixedArray<Int64>._Literal
98+
%36 = alloc_stack [lexical] $FixedArray<Int64>
99+
%37 = function_ref @array_count : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> Int64
100+
%38 = apply %37<Int64>(%24) : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> Int64
101+
%39 = begin_access [modify] [static] %36 : $*FixedArray<Int64>
102+
%40 = struct_element_addr %39 : $*FixedArray<Int64>, #FixedArray._count
103+
store %38 to [trivial] %40 : $*Int64
104+
end_access %39 : $*FixedArray<Int64>
105+
%43 = begin_access [modify] [static] %36 : $*FixedArray<Int64>
106+
%44 = struct_element_addr %43 : $*FixedArray<Int64>, #FixedArray.capacity
107+
store %38 to [trivial] %44 : $*Int64
108+
end_access %43 : $*FixedArray<Int64>
109+
%47 = begin_borrow %24 : $Array<Int64>
110+
%48 = function_ref @array_count : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> Int64
111+
%49 = apply %48<Int64>(%47) : $@convention(method) <τ_0_0> (@guaranteed Array<τ_0_0>) -> Int64
112+
%50 = struct_extract %49 : $Int64, #Int64._value
113+
%52 = metatype $@thin Int64.Type
114+
%53 = builtin "allocVector"<Int64>(%52 : $@thin Int64.Type, %50 : $Builtin.Int64) : $Builtin.RawPointer
115+
%54 = struct $UnsafeMutablePointer<Int64> (%53 : $Builtin.RawPointer)
116+
%55 = function_ref @array_copy_into_vector : $@convention(method) <τ_0_0> (UnsafeMutablePointer<τ_0_0>, @guaranteed Array<τ_0_0>) -> ()
117+
%56 = apply %55<Int64>(%54, %47) : $@convention(method) <τ_0_0> (UnsafeMutablePointer<τ_0_0>, @guaranteed Array<τ_0_0>) -> ()
118+
end_borrow %47 : $Array<Int64>
119+
%58 = begin_access [modify] [static] %36 : $*FixedArray<Int64>
120+
%59 = struct_element_addr %58 : $*FixedArray<Int64>, #FixedArray.buffer
121+
store %54 to [trivial] %59 : $*UnsafeMutablePointer<Int64>
122+
end_access %58 : $*FixedArray<Int64>
123+
%62 = load [take] %36 : $*FixedArray<Int64>
124+
destroy_value %24 : $Array<Int64>
125+
dealloc_stack %36 : $*FixedArray<Int64>
126+
store %62 to [init] %2 : $*FixedArray<Int64>
127+
%67 = tuple ()
128+
return %67 : $()
129+
}
130+
131+
// CHECK-LABEL: sil [global_init_once_fn] [ossa] @global_init_uninitialized :
132+
// CHECK: [[A:%.*]] = alloc_stack $UnsafeMutablePointer<Int64>
133+
// CHECK: [[G:%.*]] = global_addr @global_init_uninitializedTv_
134+
// CHECK: [[P:%.*]] = address_to_pointer [[G]]
135+
// CHECK: [[UMP:%.*]] = struct $UnsafeMutablePointer<Int64> ([[P]] : $Builtin.RawPointer)
136+
// CHECK store [[UMP]] to [trivial] [[A]]
137+
// CHECK: } // end sil function 'global_init_uninitialized'
138+
sil [global_init_once_fn] [ossa] @global_init_uninitialized : $@convention(thin) () -> () {
139+
bb0:
140+
alloc_global @global_fixed_array2
141+
%2 = global_addr @global_fixed_array2 : $*UnsafeMutablePointer<Int64>
142+
%5 = alloc_stack $UnsafeMutablePointer<Int64>
143+
%10 = integer_literal $Builtin.Word, 10
144+
%11 = metatype $@thin Int64.Type
145+
%12 = builtin "allocVector"<Int64>(%11 : $@thin Int64.Type, %10 : $Builtin.Word) : $Builtin.RawPointer
146+
%13 = struct $UnsafeMutablePointer<Int64> (%12 : $Builtin.RawPointer)
147+
store %13 to [trivial] %5 : $*UnsafeMutablePointer<Int64>
148+
%24 = load [trivial] %5 : $*UnsafeMutablePointer<Int64>
149+
dealloc_stack %5 : $*UnsafeMutablePointer<Int64>
150+
store %24 to [trivial] %2 : $*UnsafeMutablePointer<Int64>
151+
%27 = tuple ()
152+
return %27 : $()
153+
}
154+

0 commit comments

Comments
 (0)