Skip to content

Commit d3c5149

Browse files
authored
Merge pull request #76658 from kubamracek/embedded-managed-buffer
[embedded] Add support for ManagedBuffer to Embedded Swift
2 parents ea23b8a + 0b50c21 commit d3c5149

File tree

12 files changed

+229
-1
lines changed

12 files changed

+229
-1
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/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+
SimplifyAllocRefDynamic.swift
1011
SimplifyApply.swift
1112
SimplifyBeginBorrow.swift
1213
SimplifyBeginCOWMutation.swift
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//===--- SimplifyAllocRefDynamic.swift ------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
import SIL
14+
15+
extension AllocRefDynamicInst : OnoneSimplifyable {
16+
func simplify(_ context: SimplifyContext) {
17+
/// Optimize alloc_ref_dynamic of a known type to alloc_ref:
18+
///
19+
/// %3 = metatype SubClass.Type
20+
/// %4 = upcast %3 : SubClass.Type to BaseClass.Type
21+
/// %6 = alloc_ref_dynamic [...] %4 : BaseClass.Type, $BaseClass
22+
/// %8 = (... some use of ...) %6 : $BaseClass
23+
/// ->
24+
/// %6 = alloc_ref [...] $SubClass
25+
/// %7 = upcast %6 : $SubClass to $BaseClass
26+
/// %8 = (... some use of ...) %7 : $BaseClass
27+
28+
let type: Type
29+
let emitUpcast: Bool
30+
if let metatypeInst = metatypeOperand.value as? MetatypeInst {
31+
type = metatypeInst.type.loweredInstanceTypeOfMetatype(in: parentFunction)
32+
emitUpcast = false
33+
} else if let upcastInst = metatypeOperand.value as? UpcastInst,
34+
let metatypeInst = upcastInst.operands[0].value as? MetatypeInst {
35+
type = metatypeInst.type.loweredInstanceTypeOfMetatype(in: parentFunction)
36+
emitUpcast = true
37+
} else {
38+
return
39+
}
40+
41+
let builder = Builder(before: self, context)
42+
let newAlloc = builder.createAllocRef(type, isObjC: self.isObjC, canAllocOnStack: self.canAllocOnStack, isBare: false,
43+
tailAllocatedTypes: self.tailAllocatedTypes, tailAllocatedCounts: Array(self.tailAllocatedCounts.values))
44+
45+
let result: Value
46+
if emitUpcast {
47+
result = builder.createUpcast(from: newAlloc, to: self.type)
48+
} else {
49+
result = newAlloc
50+
}
51+
uses.replaceAll(with: result, context)
52+
context.erase(instruction: self)
53+
}
54+
}

SwiftCompilerSources/Sources/SIL/Builder.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ public struct Builder {
8989
let literal = bridged.createIntegerLiteral(type.bridged, value)
9090
return notifyNew(literal.getAs(IntegerLiteralInst.self))
9191
}
92+
93+
public func createAllocRef(_ type: Type, isObjC: Bool = false, canAllocOnStack: Bool = false, isBare: Bool = false,
94+
tailAllocatedTypes: TypeArray, tailAllocatedCounts: [Value]) -> AllocRefInst {
95+
return tailAllocatedCounts.withBridgedValues { countsRef in
96+
let dr = bridged.createAllocRef(type.bridged, isObjC, canAllocOnStack, isBare, tailAllocatedTypes.bridged, countsRef)
97+
return notifyNew(dr.getAs(AllocRefInst.self))
98+
}
99+
}
92100

93101
public func createAllocStack(_ type: Type, hasDynamicLifetime: Bool = false,
94102
isLexical: Bool = false, isFromVarDecl: Bool = false,

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,11 @@ final public class AllocRefDynamicInst : AllocRefInstBase {
11961196
public var isDynamicTypeDeinitAndSizeKnownEquivalentToBaseType: Bool {
11971197
bridged.AllocRefDynamicInst_isDynamicTypeDeinitAndSizeKnownEquivalentToBaseType()
11981198
}
1199+
1200+
public var metatypeOperand: Operand {
1201+
let numTailTypes = bridged.AllocRefInstBase_getNumTailTypes()
1202+
return operands[numTailTypes]
1203+
}
11991204
}
12001205

12011206
final public class AllocBoxInst : SingleValueInstruction, Allocation, DebugVariableInstruction {

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ extension Type: Equatable {
207207
}
208208

209209
public struct TypeArray : RandomAccessCollection, CustomReflectable {
210-
private let bridged: BridgedSILTypeArray
210+
public let bridged: BridgedSILTypeArray
211211

212212
public var startIndex: Int { return 0 }
213213
public var endIndex: Int { return bridged.getCount() }

docs/EmbeddedSwift/EmbeddedSwiftStatus.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ This status table describes which of the following standard library features can
4343
| Integer parsing | No |
4444
| KeyPaths | Partial (only compile-time constant key paths to stored properties supported, only usable in MemoryLayout and UnsafePointer APIs) |
4545
| Lazy collections | No |
46+
| ManagedBuffer | Yes |
4647
| Mirror (runtime reflection) | No, intentionally unsupported long-term |
4748
| Objective-C bridging | No, intentionally unsupported long-term |
4849
| Optional | Yes |

include/swift/SIL/SILBridging.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,11 @@ struct BridgedBuilder{
13061306
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCondFail(BridgedValue condition,
13071307
BridgedStringRef message) const;
13081308
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createIntegerLiteral(BridgedType type, SwiftInt value) const;
1309+
1310+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAllocRef(BridgedType type,
1311+
bool objc, bool canAllocOnStack, bool isBare,
1312+
BridgedSILTypeArray elementTypes, BridgedValueArray elementCountOperands) const;
1313+
13091314
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction
13101315
createAllocStack(BridgedType type, bool hasDynamicLifetime, bool isLexical,
13111316
bool isFromVarDecl, bool wasMoved) const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,17 @@ BridgedInstruction BridgedBuilder::createIntegerLiteral(BridgedType type, SwiftI
16281628
unbridged().createIntegerLiteral(regularLoc(), type.unbridged(), value)};
16291629
}
16301630

1631+
BridgedInstruction BridgedBuilder::createAllocRef(BridgedType type,
1632+
bool objc, bool canAllocOnStack, bool isBare,
1633+
BridgedSILTypeArray elementTypes, BridgedValueArray elementCountOperands) const {
1634+
llvm::SmallVector<swift::SILValue, 16> elementCountOperandsValues;
1635+
return {unbridged().createAllocRef(
1636+
regularLoc(), type.unbridged(), objc, canAllocOnStack, isBare,
1637+
elementTypes.unbridged(),
1638+
elementCountOperands.getValues(elementCountOperandsValues)
1639+
)};
1640+
}
1641+
16311642
BridgedInstruction BridgedBuilder::createAllocStack(BridgedType type,
16321643
bool hasDynamicLifetime,
16331644
bool isLexical,

stdlib/public/core/EmbeddedRuntime.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,15 @@ public func swift_dynamicCastClass(object: UnsafeMutableRawPointer, targetMetada
206206
return object
207207
}
208208

209+
@_cdecl("swift_dynamicCastClassUnconditional")
210+
public func swift_dynamicCastClassUnconditional(object: UnsafeMutableRawPointer, targetMetadata: UnsafeRawPointer,
211+
file: UnsafePointer<CChar>, line: CUnsignedInt, column: CUnsignedInt) -> UnsafeMutableRawPointer {
212+
guard let result = swift_dynamicCastClass(object: object, targetMetadata: targetMetadata) else {
213+
Builtin.int_trap()
214+
}
215+
return result
216+
}
217+
209218
@_cdecl("swift_isUniquelyReferenced_native")
210219
public func swift_isUniquelyReferenced_native(object: Builtin.RawPointer) -> Bool {
211220
if !isValidPointerForNativeRetain(object: object) { return false }

stdlib/public/core/ManagedBuffer.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ extension ManagedBuffer where Element: ~Copyable {
7777
/// an initial `Header`.
7878
@_preInverseGenerics
7979
@inlinable
80+
#if $Embedded
81+
// Transparent in Embedded Swift to avoid needing "self" as a metatype. By
82+
// inlining into the caller, we'll know the concrete type instead.
83+
@_transparent
84+
#endif
8085
public final class func create(
8186
minimumCapacity: Int,
8287
makingHeaderWith factory: (ManagedBuffer<Header, Element>) throws -> Header
@@ -290,7 +295,9 @@ public struct ManagedBufferPointer<
290295
@_preInverseGenerics
291296
@inlinable
292297
public init(unsafeBufferObject buffer: AnyObject) {
298+
#if !$Embedded
293299
ManagedBufferPointer._checkValidBufferClass(type(of: buffer))
300+
#endif
294301

295302
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
296303
}
@@ -308,7 +315,10 @@ public struct ManagedBufferPointer<
308315
@_preInverseGenerics
309316
@inlinable
310317
internal init(_uncheckedUnsafeBufferObject buffer: AnyObject) {
318+
#if !$Embedded
311319
ManagedBufferPointer._internalInvariantValidBufferClass(type(of: buffer))
320+
#endif
321+
312322
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
313323
}
314324

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=alloc_ref_dynamic | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
import Swift
6+
import Builtin
7+
8+
class BaseClass {
9+
init()
10+
}
11+
12+
class SubClass: BaseClass {
13+
override init()
14+
}
15+
16+
// CHECK-LABEL: sil [ossa] @test_alloc_ref_dynamic_with_upcast
17+
// CHECK: bb0(%0 : $Int):
18+
// CHECK: struct_extract %0 : $Int, #Int._value
19+
// CHECK: builtin "truncOrBitCast_Int64_Word"({{.*}} : $Builtin.Int64) : $Builtin.Word
20+
// CHECK: [[AL:%.*]] = alloc_ref [tail_elems $Int * {{.*}} : $Builtin.Word] $SubClass
21+
// CHECK: [[UP:%.*]] = upcast [[AL]] : $SubClass to $BaseClass
22+
// CHECK: [[MO:%.*]] = move_value [lexical] [var_decl] [[UP]] : $BaseClass
23+
// CHECK: return [[MO]] : $BaseClass
24+
// CHECK: } // end sil function 'test_alloc_ref_dynamic_with_upcast'
25+
sil [ossa] @test_alloc_ref_dynamic_with_upcast : $@convention(thin) (Int) -> @owned BaseClass {
26+
bb0(%0 : $Int):
27+
%4 = metatype $@thick SubClass.Type
28+
%5 = upcast %4 : $@thick SubClass.Type to $@thick BaseClass.Type
29+
%10 = struct_extract %0 : $Int, #Int._value
30+
%11 = builtin "truncOrBitCast_Int64_Word"(%10 : $Builtin.Int64) : $Builtin.Word
31+
%12 = alloc_ref_dynamic [tail_elems $Int * %11 : $Builtin.Word] %5 : $@thick BaseClass.Type, $BaseClass
32+
%13 = move_value [lexical] [var_decl] %12 : $BaseClass
33+
return %13 : $BaseClass
34+
}
35+
36+
// CHECK-LABEL: sil [ossa] @test_alloc_ref_dynamic_without_upcast
37+
// CHECK: bb0(%0 : $Int):
38+
// CHECK: struct_extract %0 : $Int, #Int._value
39+
// CHECK: builtin "truncOrBitCast_Int64_Word"({{.*}} : $Builtin.Int64) : $Builtin.Word
40+
// CHECK: [[AL:%.*]] = alloc_ref [tail_elems $Int * {{.*}} : $Builtin.Word] $BaseClass
41+
// CHECK: [[MO:%.*]] = move_value [lexical] [var_decl] [[AL]] : $BaseClass
42+
// CHECK: return [[MO]] : $BaseClass
43+
// CHECK: } // end sil function 'test_alloc_ref_dynamic_without_upcast'
44+
sil [ossa] @test_alloc_ref_dynamic_without_upcast : $@convention(thin) (Int) -> @owned BaseClass {
45+
bb0(%0 : $Int):
46+
%4 = metatype $@thick BaseClass.Type
47+
%10 = struct_extract %0 : $Int, #Int._value
48+
%11 = builtin "truncOrBitCast_Int64_Word"(%10 : $Builtin.Int64) : $Builtin.Word
49+
%12 = alloc_ref_dynamic [tail_elems $Int * %11 : $Builtin.Word] %4 : $@thick BaseClass.Type, $BaseClass
50+
%13 = move_value [lexical] [var_decl] %12 : $BaseClass
51+
return %13 : $BaseClass
52+
}

test/embedded/managed-buffer2.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s
2+
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo -O) | %FileCheck %s
3+
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo -Osize) | %FileCheck %s
4+
5+
// REQUIRES: swift_in_compiler
6+
// REQUIRES: executable_test
7+
// REQUIRES: optimized_stdlib
8+
// REQUIRES: OS=macosx || OS=linux-gnu
9+
10+
struct CountAndCapacity {
11+
var count: Int
12+
let capacity: Int
13+
}
14+
15+
final class TestManagedBuffer<T> : ManagedBuffer<CountAndCapacity, T> {
16+
class func create(_ capacity: Int) -> TestManagedBuffer {
17+
let r = super.create(minimumCapacity: capacity) {
18+
CountAndCapacity(count: 0, capacity: $0.capacity)
19+
}
20+
return r as! TestManagedBuffer
21+
22+
}
23+
24+
var count: Int {
25+
get { return header.count }
26+
set { header.count = newValue }
27+
}
28+
29+
var myCapacity: Int {
30+
return header.capacity
31+
}
32+
33+
deinit {
34+
teardown()
35+
}
36+
37+
func teardown() {
38+
let count = self.count
39+
40+
withUnsafeMutablePointerToElements { (x: UnsafeMutablePointer<T>) -> () in
41+
for i in stride(from: 0, to: count, by: 2) {
42+
(x + i).deinitialize(count: 1)
43+
}
44+
}
45+
}
46+
47+
func append(_ x: T) {
48+
let count = self.count
49+
precondition(count + 1 <= myCapacity)
50+
51+
withUnsafeMutablePointerToElements { (p: UnsafeMutablePointer<T>) -> () in
52+
(p + count).initialize(to: x)
53+
}
54+
self.count = count + 1
55+
}
56+
}
57+
58+
@main
59+
struct Main {
60+
static func main() {
61+
let s = TestManagedBuffer<Int>.create(10)
62+
s.append(42)
63+
s.append(777)
64+
s.withUnsafeMutablePointerToElements {
65+
for i in 0 ..< s.count {
66+
print($0[i])
67+
}
68+
}
69+
// CHECK: 42
70+
// CHECK: 777
71+
}
72+
}

0 commit comments

Comments
 (0)