Skip to content

Commit c7a5569

Browse files
committed
[embedded] Add support for ManagedBuffer to Embedded Swift
This makes ManagedBuffer available and usable in Embedded Swift, by: - Removing an internal consistency check from ManagedBuffer that relies on metatypes. - Making the .create() API transparent (to hoist the metatype to the callee). - Adding a AllocRefDynamicInst simplification to convert `alloc_ref_dynamic` to `alloc_ref`, which removes a metatype use. - Adding tests for the above.
1 parent a6c5e62 commit c7a5569

File tree

11 files changed

+207
-1
lines changed

11 files changed

+207
-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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
if let metatypeInst = operands[1].value as? MetatypeInst {
30+
type = metatypeInst.type.loweredInstanceTypeOfMetatype(in: parentFunction)
31+
} else if let upcastInst = operands[1].value as? UpcastInst,
32+
let metatypeInst = upcastInst.operands[0].value as? MetatypeInst {
33+
type = metatypeInst.type.loweredInstanceTypeOfMetatype(in: parentFunction)
34+
} else {
35+
return
36+
}
37+
38+
let builder = Builder(before: self, context)
39+
let newAlloc = builder.createAllocRef(type, isObjC: self.isObjC, canAllocOnStack: self.canAllocOnStack, isBare: false,
40+
tailAllocatedTypes: self.tailAllocatedTypes, tailAllocatedCounts: Array(self.tailAllocatedCounts.values))
41+
let newCast = builder.createUpcast(from: newAlloc, to: self.type)
42+
uses.replaceAll(with: newCast, context)
43+
context.erase(instruction: self)
44+
}
45+
}

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/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: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,9 +804,19 @@ struct BridgedSILTypeArray {
804804
BridgedSILTypeArray(llvm::ArrayRef<swift::SILType> silTypes)
805805
: typeArray(silTypes) {}
806806

807+
BridgedSILTypeArray(BridgedArrayRef typeArray)
808+
: typeArray(typeArray) {}
809+
807810
llvm::ArrayRef<swift::SILType> unbridged() const {
808811
return typeArray.unbridged<swift::SILType>();
809812
}
813+
814+
llvm::ArrayRef<swift::SILType> getValues(llvm::SmallVectorImpl<swift::SILType> &storage) {
815+
for (unsigned idx = 0; idx < getCount(); ++idx) {
816+
storage.push_back(unbridged()[idx]);
817+
}
818+
return storage;
819+
}
810820
#endif
811821

812822
SwiftInt getCount() const { return SwiftInt(typeArray.Length); }
@@ -1254,6 +1264,11 @@ struct BridgedBuilder{
12541264
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCondFail(BridgedValue condition,
12551265
BridgedStringRef message) const;
12561266
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createIntegerLiteral(BridgedType type, SwiftInt value) const;
1267+
1268+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAllocRef(BridgedType type,
1269+
bool objc, bool canAllocOnStack, bool isBare,
1270+
BridgedSILTypeArray elementTypes, BridgedValueArray elementCountOperands) const;
1271+
12571272
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction
12581273
createAllocStack(BridgedType type, bool hasDynamicLifetime, bool isLexical,
12591274
bool isFromVarDecl, bool wasMoved) const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,18 @@ 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::SILType, 16> elementTypesValues;
1635+
llvm::SmallVector<swift::SILValue, 16> elementCountOperandsValues;
1636+
return {unbridged().createAllocRef(
1637+
regularLoc(), type.unbridged(), objc, canAllocOnStack, isBare,
1638+
elementTypes.getValues(elementTypesValues),
1639+
elementCountOperands.getValues(elementCountOperandsValues)
1640+
)};
1641+
}
1642+
16311643
BridgedInstruction BridgedBuilder::createAllocStack(BridgedType type,
16321644
bool hasDynamicLifetime,
16331645
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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ extension ManagedBuffer where Element: ~Copyable {
7777
/// an initial `Header`.
7878
@_preInverseGenerics
7979
@inlinable
80+
#if $Embedded
81+
@_transparent
82+
#endif
8083
public final class func create(
8184
minimumCapacity: Int,
8285
makingHeaderWith factory: (ManagedBuffer<Header, Element>) throws -> Header
@@ -290,7 +293,9 @@ public struct ManagedBufferPointer<
290293
@_preInverseGenerics
291294
@inlinable
292295
public init(unsafeBufferObject buffer: AnyObject) {
296+
#if !$Embedded
293297
ManagedBufferPointer._checkValidBufferClass(type(of: buffer))
298+
#endif
294299

295300
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
296301
}
@@ -308,7 +313,10 @@ public struct ManagedBufferPointer<
308313
@_preInverseGenerics
309314
@inlinable
310315
internal init(_uncheckedUnsafeBufferObject buffer: AnyObject) {
316+
#if !$Embedded
311317
ManagedBufferPointer._internalInvariantValidBufferClass(type(of: buffer))
318+
#endif
319+
312320
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
313321
}
314322

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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
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'
25+
sil [ossa] @test : $@convention(thin) (Int) -> @owned BaseClass {
26+
// %0 "minimumCapacity"
27+
bb0(%0 : $Int):
28+
%4 = metatype $@thick SubClass.Type
29+
%5 = upcast %4 : $@thick SubClass.Type to $@thick BaseClass.Type
30+
%10 = struct_extract %0 : $Int, #Int._value
31+
%11 = builtin "truncOrBitCast_Int64_Word"(%10 : $Builtin.Int64) : $Builtin.Word
32+
%12 = alloc_ref_dynamic [tail_elems $Int * %11 : $Builtin.Word] %5 : $@thick BaseClass.Type, $BaseClass
33+
%13 = move_value [lexical] [var_decl] %12 : $BaseClass
34+
return %13 : $BaseClass
35+
}

0 commit comments

Comments
 (0)