mirror of
https://github.com/apple/swift.git
synced 2026-02-27 18:26:24 +01:00
339 lines
14 KiB
Swift
339 lines
14 KiB
Swift
// RUN: %target-swiftc_driver -O -Rpass-missed=sil-assembly-vision-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xfrontend -enable-copy-propagation -emit-sil %s -o /dev/null -Xfrontend -verify
|
|
// REQUIRES: optimized_stdlib,swift_stdlib_no_asserts
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
public class Klass {
|
|
var next: Klass? = nil
|
|
}
|
|
|
|
// TODO: Change global related code to be implicit/autogenerated (as
|
|
// appropriate) so we don't emit this remark.
|
|
public var global = Klass() // expected-remark {{heap allocated ref of type 'Klass'}}
|
|
|
|
@inline(never)
|
|
public func getGlobal() -> Klass {
|
|
return global // expected-remark @:5 {{retain of type 'Klass'}}
|
|
// expected-note @-5:12 {{of 'global'}}
|
|
// expected-remark @-2:12 {{begin exclusive access to value of type 'Klass'}}
|
|
// expected-note @-7:12 {{of 'global'}}
|
|
// expected-remark @-4:12 {{end exclusive access to value of type 'Klass'}}
|
|
// expected-note @-9:12 {{of 'global'}}
|
|
}
|
|
|
|
// Make sure that the retain msg is at the beginning of the print and the
|
|
// releases are the end of the print.
|
|
//
|
|
// The heap allocated ref is for the temporary array and the release that is
|
|
// unannotated is for that array as well. We make sure that the heap allocated
|
|
// ref is on the argument that necessitated its creation.
|
|
public func useGlobal() {
|
|
let x = getGlobal()
|
|
print(x) // expected-remark @:12 {{release of type}}
|
|
// expected-remark @-1:11 {{heap allocated ref of type}}
|
|
// expected-remark @-2:12 {{release of type}}
|
|
// expected-note@-4{{of 'x'}}
|
|
// expected-remark @-4:5 {{retain of type}}
|
|
// expected-note@-6{{of 'x'}}
|
|
}
|
|
|
|
public enum TrivialState {
|
|
case first
|
|
case second
|
|
case third
|
|
}
|
|
|
|
struct StructWithOwner {
|
|
var owner = Klass()
|
|
var state = TrivialState.first
|
|
}
|
|
|
|
func printStructWithOwner(x : StructWithOwner) {
|
|
print(x) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1 {{retain of type 'Klass'}}
|
|
// expected-note @-3:27 {{of 'x.owner'}}
|
|
// expected-remark @-3:12 {{release of type}}
|
|
}
|
|
|
|
func printStructWithOwnerOwner(x : StructWithOwner) {
|
|
print(x.owner) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1 {{retain of type 'Klass'}}
|
|
// expected-note @-3:32 {{of 'x.owner'}}
|
|
// expected-remark @-3:18 {{release of type}}
|
|
}
|
|
|
|
func returnStructWithOwnerOwner(x: StructWithOwner) -> Klass {
|
|
return x.owner // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2:33 {{of 'x.owner'}}
|
|
}
|
|
|
|
func callingAnInitializerStructWithOwner(x: Klass) -> StructWithOwner {
|
|
return StructWithOwner(owner: x) // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2:42 {{of 'x'}}
|
|
}
|
|
|
|
struct KlassPair {
|
|
var lhs: Klass
|
|
var rhs: Klass
|
|
}
|
|
|
|
func printKlassPair(x : KlassPair) {
|
|
// We pattern match columns to ensure we get retain on the p and release on
|
|
// the end ')'
|
|
print(x) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-5:21 {{of 'x.lhs'}}
|
|
// expected-remark @-3:5 {{retain of type 'Klass'}}
|
|
// expected-note @-7:21 {{of 'x.rhs'}}
|
|
// expected-remark @-5:12 {{release of type}}
|
|
}
|
|
|
|
func printKlassPairLHS(x : KlassPair) {
|
|
// We print the remarks at the 'p' and at the ending ')'.
|
|
print(x.lhs) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-4:24 {{of 'x.lhs'}}
|
|
// expected-remark @-3:16 {{release of type}}
|
|
}
|
|
|
|
// We put the retain on the return here since it is part of the result
|
|
// convention.
|
|
func returnKlassPairLHS(x: KlassPair) -> Klass {
|
|
return x.lhs // expected-remark @:5 {{retain of type 'Klass'}}
|
|
// expected-note @-2:25 {{of 'x.lhs'}}
|
|
}
|
|
|
|
func callingAnInitializerKlassPair(x: Klass, y: Klass) -> KlassPair {
|
|
return KlassPair(lhs: x, rhs: y) // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2:36 {{of 'x'}}
|
|
// expected-remark @-2:5 {{retain of type 'Klass'}}
|
|
// expected-note @-4:46 {{of 'y'}}
|
|
}
|
|
|
|
func printKlassTuplePair(x : (Klass, Klass)) {
|
|
// We pattern match columns to ensure we get retain on the p and release on
|
|
// the end ')'
|
|
print(x) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-5:26 {{of 'x'}}
|
|
// expected-remark @-3:5 {{retain of type 'Klass'}}
|
|
// expected-note @-7:26 {{of 'x'}}
|
|
// expected-remark @-5:12 {{release of type}}
|
|
}
|
|
|
|
func printKlassTupleLHS(x : (Klass, Klass)) {
|
|
// We print the remarks at the 'p' and at the ending ')'.
|
|
print(x.0) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-4:25 {{of 'x'}}
|
|
// Release on Array<Any> for print.
|
|
// expected-remark @-4:14 {{release of type}}
|
|
}
|
|
|
|
func returnKlassTupleLHS(x: (Klass, Klass)) -> Klass {
|
|
return x.0 // expected-remark @:5 {{retain of type 'Klass'}}
|
|
// expected-note @-2:26 {{of 'x'}}
|
|
}
|
|
|
|
func callingAnInitializerKlassTuplePair(x: Klass, y: Klass) -> (Klass, Klass) {
|
|
return (x, y) // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2:41 {{of 'x'}}
|
|
// expected-remark @-2:5 {{retain of type 'Klass'}}
|
|
// expected-note @-4:51 {{of 'y'}}
|
|
}
|
|
|
|
public class SubKlass : Klass {
|
|
@inline(never)
|
|
final func doSomething() {}
|
|
}
|
|
|
|
func lookThroughCast(x: SubKlass) -> Klass {
|
|
return x as Klass // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2:22 {{of 'x.upcast<$Klass>'}}
|
|
}
|
|
|
|
func lookThroughRefCast(x: Klass) -> SubKlass {
|
|
return x as! SubKlass // expected-remark {{retain of type 'SubKlass'}}
|
|
}
|
|
|
|
func lookThroughEnum(x: Klass?) -> Klass {
|
|
return x! // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2:22 {{of 'x.some'}}
|
|
}
|
|
|
|
func castAsQuestion(x: Klass) -> SubKlass? {
|
|
x as? SubKlass // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2:21 {{of 'x'}}
|
|
}
|
|
|
|
func castAsQuestionDiamond(x: Klass) -> SubKlass? {
|
|
guard let y = x as? SubKlass else {
|
|
return nil
|
|
}
|
|
|
|
y.doSomething()
|
|
return y // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-7:28 {{of 'x'}}
|
|
}
|
|
|
|
func castAsQuestionDiamondGEP(x: KlassPair) -> SubKlass? {
|
|
guard let y = x.lhs as? SubKlass else {
|
|
return nil
|
|
}
|
|
|
|
y.doSomething()
|
|
// We eliminate the rhs retain/release.
|
|
return y // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-8:31 {{of 'x.lhs'}}
|
|
}
|
|
|
|
// We don't handle this test case as well.
|
|
func castAsQuestionDiamondGEP2(x: KlassPair) {
|
|
switch (x.lhs as? SubKlass, x.rhs as? SubKlass) { // expected-remark @:39 {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x.lhs'}}
|
|
// expected-remark @-2:19 {{retain of type 'Klass'}}
|
|
// expected-note @-4 {{of 'x.rhs'}}
|
|
case let (.some(x1), .some(x2)):
|
|
print(x1, x2) // expected-remark @:15 {{heap allocated ref of type}}
|
|
// expected-remark @-1 {{retain of type}}
|
|
// expected-remark @-2 {{retain of type}}
|
|
// expected-remark @-3 {{release of type}}
|
|
// expected-remark @-4 {{release of type}}
|
|
// expected-remark @-5 {{release of type}}
|
|
case let (.some(x1), nil):
|
|
print(x1) // expected-remark @:15 {{heap allocated ref of type}}
|
|
// expected-remark @-1 {{retain of type}}
|
|
// expected-remark @-2 {{release of type}}
|
|
// expected-remark @-3 {{release of type}}
|
|
case let (nil, .some(x2)):
|
|
print(x2) // expected-remark @:15 {{heap allocated ref of type}}
|
|
// expected-remark @-1 {{retain of type}}
|
|
// expected-remark @-2 {{release of type}}
|
|
// expected-remark @-3 {{release of type}}
|
|
case (nil, nil):
|
|
break
|
|
}
|
|
}
|
|
|
|
func inoutKlassPairArgument(x: inout KlassPair) -> Klass {
|
|
return x.lhs // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x.lhs'}}
|
|
}
|
|
|
|
func inoutKlassTuplePairArgument(x: inout (Klass, Klass)) -> Klass {
|
|
return x.0 // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x.0'}}
|
|
}
|
|
|
|
func inoutKlassOptionalArgument(x: inout Klass?) -> Klass {
|
|
return x! // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x.some'}}
|
|
}
|
|
|
|
func inoutKlassBangCastArgument(x: inout Klass) -> SubKlass {
|
|
return x as! SubKlass // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x'}}
|
|
}
|
|
|
|
func inoutKlassQuestionCastArgument(x: inout Klass) -> SubKlass? {
|
|
return x as? SubKlass // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x'}}
|
|
}
|
|
|
|
func inoutKlassBangCastArgument2(x: inout Klass?) -> SubKlass {
|
|
return x as! SubKlass // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x.some'}}
|
|
}
|
|
|
|
func inoutKlassQuestionCastArgument2(x: inout Klass?) -> SubKlass? {
|
|
return x as? SubKlass // expected-remark {{retain of type 'Klass'}}
|
|
// expected-note @-2 {{of 'x.some'}}
|
|
}
|
|
|
|
// We should have 1x rr remark here on calleeX for storing it into the array to
|
|
// print. Release is from the array. We don't pattern match it due to the actual
|
|
// underlying Array type name changing under the hood in between platforms.
|
|
@inline(__always)
|
|
func alwaysInlineCallee(_ calleeX: Klass) {
|
|
print(calleeX) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-3:27 {{of 'calleeX'}}
|
|
// expected-remark @-3:18 {{release of type}}
|
|
}
|
|
|
|
// We should have 3x rr remarks here on callerX and none on calleeX. All of the
|
|
// releases are for the temporary array that we pass into print.
|
|
//
|
|
// TODO: Should we print out as notes the whole inlined call stack?
|
|
func alwaysInlineCaller(_ callerX: Klass) {
|
|
alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-3:27 {{of 'callerX'}}
|
|
// expected-remark @-3:31 {{release of type}}
|
|
print(callerX) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-7:27 {{of 'callerX'}}
|
|
// expected-remark @-3:18 {{release of type}}
|
|
alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type 'Klass'}}
|
|
// expected-note @-11:27 {{of 'callerX'}}
|
|
// expected-remark @-3:31 {{release of type}}
|
|
}
|
|
|
|
func allocateValue() {
|
|
// Remark should be on Klass and note should be on k.
|
|
let k = Klass() // expected-remark @:13 {{heap allocated ref of type 'Klass'}}
|
|
// expected-note @-1:9 {{of 'k'}}
|
|
print(k) // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:5 {{retain of type}}
|
|
// expected-note @-4:9 {{of 'k'}}
|
|
// expected-remark @-3:12 {{release of type}}
|
|
// expected-remark @-4:12 {{release of type}}
|
|
// expected-note @-7:9 {{of 'k'}}
|
|
}
|
|
|
|
@inline(never)
|
|
func simpleInOutUser<T>(_ x: inout T) {
|
|
}
|
|
|
|
func simpleInOut() -> Klass {
|
|
let x = Klass() // expected-remark @:13 {{heap allocated ref of type 'Klass'}}
|
|
// expected-note @-1:9 {{of 'x'}}
|
|
simpleInOutUser(&x.next) // expected-remark @:5 {{begin exclusive access to value of type 'Optional<Klass>'}}
|
|
// expected-note @-3:9 {{of 'x.next'}}
|
|
// expected-remark @-2:28 {{end exclusive access to value of type 'Optional<Klass>'}}
|
|
// expected-note @-5:9 {{of 'x.next'}}
|
|
return x
|
|
}
|
|
|
|
|
|
@inline(never)
|
|
@_semantics("optimize.sil.specialize.generic.size.never")
|
|
public func use<T>(_ t: inout T) { // expected-note @:22 {{from location 't'}}
|
|
print(t); // expected-remark @:11 {{heap allocated ref of type}}
|
|
// expected-remark @-1:11 {{Memory copy of value with type 'T'}}
|
|
// expected-remark @-2:12 {{release of type}}
|
|
}
|
|
|
|
@inline(never)
|
|
@_assemblyVision
|
|
public func genericFunc<T>(_ t: T) { // expected-note @:30 {{from location 't'}}
|
|
var temp: T = t // expected-note @:9 {{to location 'temp'}}
|
|
// expected-remark @-1:9 {{Memory destroy of value with type 'T'}}
|
|
// expected-note @-2:9 {{in memory location of 'temp'}}
|
|
// expected-remark @-3:19 {{Memory copy of value with type 'T'}}
|
|
use(&temp)
|
|
use(&temp)
|
|
}
|
|
|
|
@_assemblyVision
|
|
public func forEach<T>(_ elements: Array<T>, body: (borrowing T) -> Void) {
|
|
elements.withUnsafeBufferPointer { buffer in
|
|
for i in buffer.indices { // expected-remark @:5 {{Specialized function "Swift.IndexingIterator.next()" with type (@inout IndexingIterator<Range<Int>>) -> Optional<Int>}}
|
|
// expected-remark @-1:14 {{Specialized function "Swift.Collection<>.makeIterator()" with type (Range<Int>) -> IndexingIterator<Range<Int>>}}
|
|
body(/* copy */ buffer[i]) // expected-remark @:29 {{Memory copy of value with type 'T'}}
|
|
// expected-remark @-1:32 {{Memory destroy of value with type 'T'}}
|
|
// destroy of T
|
|
}
|
|
}
|
|
}
|