mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
|
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
|
||||||
|
|
||||||
swift_compiler_sources(Optimizer
|
swift_compiler_sources(Optimizer
|
||||||
|
SimplifyAllocRefDynamic.swift
|
||||||
SimplifyApply.swift
|
SimplifyApply.swift
|
||||||
SimplifyBeginBorrow.swift
|
SimplifyBeginBorrow.swift
|
||||||
SimplifyBeginCOWMutation.swift
|
SimplifyBeginCOWMutation.swift
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
//===--- SimplifyAllocRefDynamic.swift ------------------------------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
|
||||||
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||||
|
//
|
||||||
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import SIL
|
||||||
|
|
||||||
|
extension AllocRefDynamicInst : OnoneSimplifyable {
|
||||||
|
func simplify(_ context: SimplifyContext) {
|
||||||
|
/// Optimize alloc_ref_dynamic of a known type to alloc_ref:
|
||||||
|
///
|
||||||
|
/// %3 = metatype SubClass.Type
|
||||||
|
/// %4 = upcast %3 : SubClass.Type to BaseClass.Type
|
||||||
|
/// %6 = alloc_ref_dynamic [...] %4 : BaseClass.Type, $BaseClass
|
||||||
|
/// %8 = (... some use of ...) %6 : $BaseClass
|
||||||
|
/// ->
|
||||||
|
/// %6 = alloc_ref [...] $SubClass
|
||||||
|
/// %7 = upcast %6 : $SubClass to $BaseClass
|
||||||
|
/// %8 = (... some use of ...) %7 : $BaseClass
|
||||||
|
|
||||||
|
let type: Type
|
||||||
|
if let metatypeInst = operands[1].value as? MetatypeInst {
|
||||||
|
type = metatypeInst.type.loweredInstanceTypeOfMetatype(in: parentFunction)
|
||||||
|
} else if let upcastInst = operands[1].value as? UpcastInst,
|
||||||
|
let metatypeInst = upcastInst.operands[0].value as? MetatypeInst {
|
||||||
|
type = metatypeInst.type.loweredInstanceTypeOfMetatype(in: parentFunction)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let builder = Builder(before: self, context)
|
||||||
|
let newAlloc = builder.createAllocRef(type, isObjC: self.isObjC, canAllocOnStack: self.canAllocOnStack, isBare: false,
|
||||||
|
tailAllocatedTypes: self.tailAllocatedTypes, tailAllocatedCounts: Array(self.tailAllocatedCounts.values))
|
||||||
|
let newCast = builder.createUpcast(from: newAlloc, to: self.type)
|
||||||
|
uses.replaceAll(with: newCast, context)
|
||||||
|
context.erase(instruction: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -90,6 +90,14 @@ public struct Builder {
|
|||||||
return notifyNew(literal.getAs(IntegerLiteralInst.self))
|
return notifyNew(literal.getAs(IntegerLiteralInst.self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func createAllocRef(_ type: Type, isObjC: Bool = false, canAllocOnStack: Bool = false, isBare: Bool = false,
|
||||||
|
tailAllocatedTypes: TypeArray, tailAllocatedCounts: [Value]) -> AllocRefInst {
|
||||||
|
return tailAllocatedCounts.withBridgedValues { countsRef in
|
||||||
|
let dr = bridged.createAllocRef(type.bridged, isObjC, canAllocOnStack, isBare, tailAllocatedTypes.bridged, countsRef)
|
||||||
|
return notifyNew(dr.getAs(AllocRefInst.self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func createAllocStack(_ type: Type, hasDynamicLifetime: Bool = false,
|
public func createAllocStack(_ type: Type, hasDynamicLifetime: Bool = false,
|
||||||
isLexical: Bool = false, isFromVarDecl: Bool = false,
|
isLexical: Bool = false, isFromVarDecl: Bool = false,
|
||||||
usesMoveableValueDebugInfo: Bool = false) -> AllocStackInst {
|
usesMoveableValueDebugInfo: Bool = false) -> AllocStackInst {
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ extension Type: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct TypeArray : RandomAccessCollection, CustomReflectable {
|
public struct TypeArray : RandomAccessCollection, CustomReflectable {
|
||||||
private let bridged: BridgedSILTypeArray
|
public let bridged: BridgedSILTypeArray
|
||||||
|
|
||||||
public var startIndex: Int { return 0 }
|
public var startIndex: Int { return 0 }
|
||||||
public var endIndex: Int { return bridged.getCount() }
|
public var endIndex: Int { return bridged.getCount() }
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ This status table describes which of the following standard library features can
|
|||||||
| Integer parsing | No |
|
| Integer parsing | No |
|
||||||
| KeyPaths | Partial (only compile-time constant key paths to stored properties supported, only usable in MemoryLayout and UnsafePointer APIs) |
|
| KeyPaths | Partial (only compile-time constant key paths to stored properties supported, only usable in MemoryLayout and UnsafePointer APIs) |
|
||||||
| Lazy collections | No |
|
| Lazy collections | No |
|
||||||
|
| ManagedBuffer | Yes |
|
||||||
| Mirror (runtime reflection) | No, intentionally unsupported long-term |
|
| Mirror (runtime reflection) | No, intentionally unsupported long-term |
|
||||||
| Objective-C bridging | No, intentionally unsupported long-term |
|
| Objective-C bridging | No, intentionally unsupported long-term |
|
||||||
| Optional | Yes |
|
| Optional | Yes |
|
||||||
|
|||||||
@@ -804,9 +804,19 @@ struct BridgedSILTypeArray {
|
|||||||
BridgedSILTypeArray(llvm::ArrayRef<swift::SILType> silTypes)
|
BridgedSILTypeArray(llvm::ArrayRef<swift::SILType> silTypes)
|
||||||
: typeArray(silTypes) {}
|
: typeArray(silTypes) {}
|
||||||
|
|
||||||
|
BridgedSILTypeArray(BridgedArrayRef typeArray)
|
||||||
|
: typeArray(typeArray) {}
|
||||||
|
|
||||||
llvm::ArrayRef<swift::SILType> unbridged() const {
|
llvm::ArrayRef<swift::SILType> unbridged() const {
|
||||||
return typeArray.unbridged<swift::SILType>();
|
return typeArray.unbridged<swift::SILType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::ArrayRef<swift::SILType> getValues(llvm::SmallVectorImpl<swift::SILType> &storage) {
|
||||||
|
for (unsigned idx = 0; idx < getCount(); ++idx) {
|
||||||
|
storage.push_back(unbridged()[idx]);
|
||||||
|
}
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SwiftInt getCount() const { return SwiftInt(typeArray.Length); }
|
SwiftInt getCount() const { return SwiftInt(typeArray.Length); }
|
||||||
@@ -1254,6 +1264,11 @@ struct BridgedBuilder{
|
|||||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCondFail(BridgedValue condition,
|
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCondFail(BridgedValue condition,
|
||||||
BridgedStringRef message) const;
|
BridgedStringRef message) const;
|
||||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createIntegerLiteral(BridgedType type, SwiftInt value) const;
|
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createIntegerLiteral(BridgedType type, SwiftInt value) const;
|
||||||
|
|
||||||
|
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createAllocRef(BridgedType type,
|
||||||
|
bool objc, bool canAllocOnStack, bool isBare,
|
||||||
|
BridgedSILTypeArray elementTypes, BridgedValueArray elementCountOperands) const;
|
||||||
|
|
||||||
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction
|
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction
|
||||||
createAllocStack(BridgedType type, bool hasDynamicLifetime, bool isLexical,
|
createAllocStack(BridgedType type, bool hasDynamicLifetime, bool isLexical,
|
||||||
bool isFromVarDecl, bool wasMoved) const;
|
bool isFromVarDecl, bool wasMoved) const;
|
||||||
|
|||||||
@@ -1628,6 +1628,18 @@ BridgedInstruction BridgedBuilder::createIntegerLiteral(BridgedType type, SwiftI
|
|||||||
unbridged().createIntegerLiteral(regularLoc(), type.unbridged(), value)};
|
unbridged().createIntegerLiteral(regularLoc(), type.unbridged(), value)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BridgedInstruction BridgedBuilder::createAllocRef(BridgedType type,
|
||||||
|
bool objc, bool canAllocOnStack, bool isBare,
|
||||||
|
BridgedSILTypeArray elementTypes, BridgedValueArray elementCountOperands) const {
|
||||||
|
llvm::SmallVector<swift::SILType, 16> elementTypesValues;
|
||||||
|
llvm::SmallVector<swift::SILValue, 16> elementCountOperandsValues;
|
||||||
|
return {unbridged().createAllocRef(
|
||||||
|
regularLoc(), type.unbridged(), objc, canAllocOnStack, isBare,
|
||||||
|
elementTypes.getValues(elementTypesValues),
|
||||||
|
elementCountOperands.getValues(elementCountOperandsValues)
|
||||||
|
)};
|
||||||
|
}
|
||||||
|
|
||||||
BridgedInstruction BridgedBuilder::createAllocStack(BridgedType type,
|
BridgedInstruction BridgedBuilder::createAllocStack(BridgedType type,
|
||||||
bool hasDynamicLifetime,
|
bool hasDynamicLifetime,
|
||||||
bool isLexical,
|
bool isLexical,
|
||||||
|
|||||||
@@ -206,6 +206,15 @@ public func swift_dynamicCastClass(object: UnsafeMutableRawPointer, targetMetada
|
|||||||
return object
|
return object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@_cdecl("swift_dynamicCastClassUnconditional")
|
||||||
|
public func swift_dynamicCastClassUnconditional(object: UnsafeMutableRawPointer, targetMetadata: UnsafeRawPointer,
|
||||||
|
file: UnsafePointer<CChar>, line: CUnsignedInt, column: CUnsignedInt) -> UnsafeMutableRawPointer {
|
||||||
|
guard let result = swift_dynamicCastClass(object: object, targetMetadata: targetMetadata) else {
|
||||||
|
Builtin.int_trap()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
@_cdecl("swift_isUniquelyReferenced_native")
|
@_cdecl("swift_isUniquelyReferenced_native")
|
||||||
public func swift_isUniquelyReferenced_native(object: Builtin.RawPointer) -> Bool {
|
public func swift_isUniquelyReferenced_native(object: Builtin.RawPointer) -> Bool {
|
||||||
if !isValidPointerForNativeRetain(object: object) { return false }
|
if !isValidPointerForNativeRetain(object: object) { return false }
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ extension ManagedBuffer where Element: ~Copyable {
|
|||||||
/// an initial `Header`.
|
/// an initial `Header`.
|
||||||
@_preInverseGenerics
|
@_preInverseGenerics
|
||||||
@inlinable
|
@inlinable
|
||||||
|
#if $Embedded
|
||||||
|
@_transparent
|
||||||
|
#endif
|
||||||
public final class func create(
|
public final class func create(
|
||||||
minimumCapacity: Int,
|
minimumCapacity: Int,
|
||||||
makingHeaderWith factory: (ManagedBuffer<Header, Element>) throws -> Header
|
makingHeaderWith factory: (ManagedBuffer<Header, Element>) throws -> Header
|
||||||
@@ -290,7 +293,9 @@ public struct ManagedBufferPointer<
|
|||||||
@_preInverseGenerics
|
@_preInverseGenerics
|
||||||
@inlinable
|
@inlinable
|
||||||
public init(unsafeBufferObject buffer: AnyObject) {
|
public init(unsafeBufferObject buffer: AnyObject) {
|
||||||
|
#if !$Embedded
|
||||||
ManagedBufferPointer._checkValidBufferClass(type(of: buffer))
|
ManagedBufferPointer._checkValidBufferClass(type(of: buffer))
|
||||||
|
#endif
|
||||||
|
|
||||||
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
|
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
|
||||||
}
|
}
|
||||||
@@ -308,7 +313,10 @@ public struct ManagedBufferPointer<
|
|||||||
@_preInverseGenerics
|
@_preInverseGenerics
|
||||||
@inlinable
|
@inlinable
|
||||||
internal init(_uncheckedUnsafeBufferObject buffer: AnyObject) {
|
internal init(_uncheckedUnsafeBufferObject buffer: AnyObject) {
|
||||||
|
#if !$Embedded
|
||||||
ManagedBufferPointer._internalInvariantValidBufferClass(type(of: buffer))
|
ManagedBufferPointer._internalInvariantValidBufferClass(type(of: buffer))
|
||||||
|
#endif
|
||||||
|
|
||||||
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
|
self._nativeBuffer = Builtin.unsafeCastToNativeObject(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
test/SILOptimizer/simplify_alloc_ref_dynamic.sil
Normal file
35
test/SILOptimizer/simplify_alloc_ref_dynamic.sil
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=alloc_ref_dynamic | %FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
|
||||||
|
import Swift
|
||||||
|
import Builtin
|
||||||
|
|
||||||
|
class BaseClass {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubClass: BaseClass {
|
||||||
|
override init()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil [ossa] @test
|
||||||
|
// CHECK: bb0(%0 : $Int):
|
||||||
|
// CHECK: struct_extract %0 : $Int, #Int._value
|
||||||
|
// CHECK: builtin "truncOrBitCast_Int64_Word"({{.*}} : $Builtin.Int64) : $Builtin.Word
|
||||||
|
// CHECK: [[AL:%.*]] = alloc_ref [tail_elems $Int * {{.*}} : $Builtin.Word] $SubClass
|
||||||
|
// CHECK: [[UP:%.*]] = upcast [[AL]] : $SubClass to $BaseClass
|
||||||
|
// CHECK: [[MO:%.*]] = move_value [lexical] [var_decl] [[UP]] : $BaseClass
|
||||||
|
// CHECK: return [[MO]] : $BaseClass
|
||||||
|
// CHECK: } // end sil function 'test'
|
||||||
|
sil [ossa] @test : $@convention(thin) (Int) -> @owned BaseClass {
|
||||||
|
// %0 "minimumCapacity"
|
||||||
|
bb0(%0 : $Int):
|
||||||
|
%4 = metatype $@thick SubClass.Type
|
||||||
|
%5 = upcast %4 : $@thick SubClass.Type to $@thick BaseClass.Type
|
||||||
|
%10 = struct_extract %0 : $Int, #Int._value
|
||||||
|
%11 = builtin "truncOrBitCast_Int64_Word"(%10 : $Builtin.Int64) : $Builtin.Word
|
||||||
|
%12 = alloc_ref_dynamic [tail_elems $Int * %11 : $Builtin.Word] %5 : $@thick BaseClass.Type, $BaseClass
|
||||||
|
%13 = move_value [lexical] [var_decl] %12 : $BaseClass
|
||||||
|
return %13 : $BaseClass
|
||||||
|
}
|
||||||
72
test/embedded/managed-buffer2.swift
Normal file
72
test/embedded/managed-buffer2.swift
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s
|
||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo -O) | %FileCheck %s
|
||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo -Osize) | %FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: optimized_stdlib
|
||||||
|
// REQUIRES: OS=macosx || OS=linux-gnu
|
||||||
|
|
||||||
|
struct CountAndCapacity {
|
||||||
|
var count: Int
|
||||||
|
let capacity: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
final class TestManagedBuffer<T> : ManagedBuffer<CountAndCapacity, T> {
|
||||||
|
class func create(_ capacity: Int) -> TestManagedBuffer {
|
||||||
|
let r = super.create(minimumCapacity: capacity) {
|
||||||
|
CountAndCapacity(count: 0, capacity: $0.capacity)
|
||||||
|
}
|
||||||
|
return r as! TestManagedBuffer
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var count: Int {
|
||||||
|
get { return header.count }
|
||||||
|
set { header.count = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
var myCapacity: Int {
|
||||||
|
return header.capacity
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
teardown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func teardown() {
|
||||||
|
let count = self.count
|
||||||
|
|
||||||
|
withUnsafeMutablePointerToElements { (x: UnsafeMutablePointer<T>) -> () in
|
||||||
|
for i in stride(from: 0, to: count, by: 2) {
|
||||||
|
(x + i).deinitialize(count: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func append(_ x: T) {
|
||||||
|
let count = self.count
|
||||||
|
precondition(count + 1 <= myCapacity)
|
||||||
|
|
||||||
|
withUnsafeMutablePointerToElements { (p: UnsafeMutablePointer<T>) -> () in
|
||||||
|
(p + count).initialize(to: x)
|
||||||
|
}
|
||||||
|
self.count = count + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Main {
|
||||||
|
static func main() {
|
||||||
|
let s = TestManagedBuffer<Int>.create(10)
|
||||||
|
s.append(42)
|
||||||
|
s.append(777)
|
||||||
|
s.withUnsafeMutablePointerToElements {
|
||||||
|
for i in 0 ..< s.count {
|
||||||
|
print($0[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// CHECK: 42
|
||||||
|
// CHECK: 777
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user