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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
// RUN: %target-swift-emit-silgen -parse-as-library -module-name Swift -parse-stdlib %s | %FileCheck %s
// This test checks specific codegen related to normal arguments being passed at
// +0. Eventually, it should be merged into normal SILGen tests.
/////////////////
// Fake Stdlib //
/////////////////
precedencegroup AssignmentPrecedence {
assignment: true
}
public protocol ExpressibleByNilLiteral {
init(nilLiteral: ())
}
protocol IteratorProtocol {
associatedtype Element
mutating func next() -> Element?
}
protocol Sequence {
associatedtype Element
associatedtype Iterator : IteratorProtocol where Iterator.Element == Element
func makeIterator() -> Iterator
}
enum Optional<T> {
case none
case some(T)
}
extension Optional : ExpressibleByNilLiteral {
public init(nilLiteral: ()) {
self = .none
}
}
func _diagnoseUnexpectedNilOptional(_filenameStart: Builtin.RawPointer,
_filenameLength: Builtin.Word,
_filenameIsASCII: Builtin.Int1,
_line: Builtin.Word) {
// This would usually contain an assert, but we don't need one since we are
// just emitting SILGen.
}
class Klass {
init() {}
}
struct Buffer {
var k: Klass
init(inK: Klass) {
k = inK
}
}
public typealias AnyObject = Builtin.AnyObject
protocol Protocol {
associatedtype AssocType
static func useInput(_ input: Builtin.Int32, into processInput: (AssocType) -> ())
}
struct FakeArray<Element> {
// Just to make this type non-trivial
var k: Klass
// We are only interested in this being called. We are not interested in its
// implementation.
mutating func append(_ t: Element) {}
}
struct FakeDictionary<Key, Value> {
}
struct FakeDictionaryIterator<Key, Value> {
var dictionary: FakeDictionary<Key, Value>?
init(_ newDictionary: FakeDictionary<Key, Value>) {
dictionary = newDictionary
}
}
extension FakeDictionaryIterator : IteratorProtocol {
public typealias Element = (Key, Value)
public mutating func next() -> Element? {
return .none
}
}
extension FakeDictionary : Sequence {
public typealias Element = (Key, Value)
public typealias Iterator = FakeDictionaryIterator<Key, Value>
public func makeIterator() -> FakeDictionaryIterator<Key, Value> {
return FakeDictionaryIterator(self)
}
}
public struct Unmanaged<Instance : AnyObject> {
internal unowned(unsafe) var _value: Instance
}
///////////
// Tests //
///////////
class KlassWithBuffer {
var buffer: Buffer
// Make sure that the allocating init forwards into the initializing init at +1.
// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$ss15KlassWithBufferC3inKABs0A0C_tcfC : $@convention(method) (@owned Klass, @thick KlassWithBuffer.Type) -> @owned KlassWithBuffer {
// CHECK: bb0([[ARG:%.*]] : @owned $Klass,
// CHECK: [[INITIALIZING_INIT:%.*]] = function_ref @$ss15KlassWithBufferC3inKABs0A0C_tcfc : $@convention(method) (@owned Klass, @owned KlassWithBuffer) -> @owned KlassWithBuffer
// CHECK: apply [[INITIALIZING_INIT]]([[ARG]],
// CHECK: } // end sil function '$ss15KlassWithBufferC3inKABs0A0C_tcfC'
init(inK: Klass = Klass()) {
buffer = Buffer(inK: inK)
}
// This test makes sure that we:
//
// 1. Are able to propagate a +0 value buffer.k into a +0 value and that
// we then copy that +0 value into a +1 value, before we begin the epilog and
// then return that value.
// CHECK-LABEL: sil hidden [ossa] @$ss15KlassWithBufferC03getC14AsNativeObjectBoyF : $@convention(method) (@guaranteed KlassWithBuffer) -> @owned Builtin.NativeObject {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $KlassWithBuffer):
// CHECK: [[METHOD:%.*]] = class_method [[SELF]] : $KlassWithBuffer, #KlassWithBuffer.buffer!getter
// CHECK: [[BUF:%.*]] = apply [[METHOD]]([[SELF]])
// CHECK: [[BUF_BORROW:%.*]] = begin_borrow [[BUF]]
// CHECK: [[K:%.*]] = struct_extract [[BUF_BORROW]] : $Buffer, #Buffer.k
// CHECK: [[COPIED_K:%.*]] = copy_value [[K]]
// CHECK: end_borrow [[BUF_BORROW]]
// CHECK: [[CASTED_COPIED_K:%.*]] = unchecked_ref_cast [[COPIED_K]]
// CHECK: destroy_value [[BUF]]
// CHECK: return [[CASTED_COPIED_K]]
// CHECK: } // end sil function '$ss15KlassWithBufferC03getC14AsNativeObjectBoyF'
func getBufferAsNativeObject() -> Builtin.NativeObject {
return Builtin.unsafeCastToNativeObject(buffer.k)
}
}
struct StructContainingBridgeObject {
var rawValue: Builtin.BridgeObject
// CHECK-LABEL: sil hidden [ossa] @$ss28StructContainingBridgeObjectV8swiftObjAByXl_tcfC : $@convention(method) (@owned AnyObject, @thin StructContainingBridgeObject.Type) -> @owned StructContainingBridgeObject {
// CHECK: bb0([[ARG:%.*]] : @owned $AnyObject,
// CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK: [[COPIED_ARG:%.*]] = copy_value [[BORROWED_ARG]]
// CHECK: [[CASTED_ARG:%.*]] = unchecked_ref_cast [[COPIED_ARG]] : $AnyObject to $Builtin.BridgeObject
// CHECK: assign [[CASTED_ARG]] to
// CHECK: } // end sil function '$ss28StructContainingBridgeObjectV8swiftObjAByXl_tcfC'
init(swiftObj: AnyObject) {
rawValue = Builtin.reinterpretCast(swiftObj)
}
}
struct ReabstractionThunkTest : Protocol {
typealias AssocType = Builtin.Int32
static func useInput(_ input: Builtin.Int32, into processInput: (AssocType) -> ()) {
processInput(input)
}
}
// Make sure that we provide a cleanup to x properly before we pass it to
// result.
extension FakeDictionary {
// CHECK-LABEL: sil hidden [ossa] @$ss14FakeDictionaryV20makeSureToCopyTuplesyyF : $@convention(method) <Key, Value> (FakeDictionary<Key, Value>) -> () {
// CHECK: [[X:%.*]] = alloc_stack [lexical] [var_decl] $(Key, Value), let, name "x"
// CHECK: [[INDUCTION_VAR:%.*]] = unchecked_take_enum_data_addr {{%.*}} : $*Optional<(Key, Value)>, #Optional.some!enumelt
// CHECK: [[INDUCTION_VAR_0:%.*]] = tuple_element_addr [[INDUCTION_VAR]] : $*(Key, Value), 0
// CHECK: [[INDUCTION_VAR_1:%.*]] = tuple_element_addr [[INDUCTION_VAR]] : $*(Key, Value), 1
// CHECK: [[X_0:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 0
// CHECK: [[X_1:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 1
// CHECK: copy_addr [take] [[INDUCTION_VAR_0]] to [init] [[X_0]]
// CHECK: copy_addr [take] [[INDUCTION_VAR_1]] to [init] [[X_1]]
// CHECK: [[X_0:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 0
// CHECK: [[X_1:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 1
// CHECK: [[TMP_X:%.*]] = alloc_stack $(Key, Value)
// CHECK: [[TMP_X_0:%.*]] = tuple_element_addr [[TMP_X]] : $*(Key, Value), 0
// CHECK: [[TMP_X_1:%.*]] = tuple_element_addr [[TMP_X]] : $*(Key, Value), 1
// CHECK: [[TMP_0:%.*]] = alloc_stack $Key
// CHECK: copy_addr [[X_0]] to [init] [[TMP_0]]
// CHECK: copy_addr [take] [[TMP_0]] to [init] [[TMP_X_0]]
// CHECK: [[TMP_1:%.*]] = alloc_stack $Value
// CHECK: copy_addr [[X_1]] to [init] [[TMP_1]]
// CHECK: copy_addr [take] [[TMP_1]] to [init] [[TMP_X_1]]
// CHECK: [[FUNC:%.*]] = function_ref @$ss9FakeArrayV6appendyyxF : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout FakeArray<τ_0_0>) -> ()
// CHECK: apply [[FUNC]]<(Key, Value)>([[TMP_X]],
// CHECK: } // end sil function '$ss14FakeDictionaryV20makeSureToCopyTuplesyyF'
func makeSureToCopyTuples() {
var result = FakeArray<Element>(k: Klass())
for x in self {
result.append(x)
}
}
}
// Make sure that we properly forward x into memory and don't crash.
public func forwardIntoMemory(fromNative x: AnyObject, y: Builtin.Word) -> Builtin.BridgeObject {
// y would normally be 0._builtinWordValue. We don't want to define that
// conformance.
let object = Builtin.castToBridgeObject(x, y)
return object
}
public struct StructWithOptionalAddressOnlyField<T> {
public let newValue: T?
}
func useStructWithOptionalAddressOnlyField<T>(t: T) -> StructWithOptionalAddressOnlyField<T> {
return StructWithOptionalAddressOnlyField<T>(newValue: t)
}
|