Files
swift-mirror/test/IRGen/objc_block_storage.sil
Arnold Schwaighofer 3ae6d7cb4d runtime/IRGen: return the argument from swift_retain family of functions
On architectures where the calling convention uses the same argument register as
return register this allows the argument register to be live through the calls.

We use LLVM's 'returned' attribute on the parameter to facilitate this.

We used to perform this optimization via an optimization pass. This was ripped
out some time ago around commit 955e4ed652.
By using LLVM's 'returned' attribute on swift_*retain, we get the same
optimization from the LLVM backend.
2017-09-19 07:16:37 -07:00

171 lines
11 KiB
Plaintext

// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -gnone -sdk %S/Inputs %s -emit-ir | %FileCheck %s
// REQUIRES: CPU=x86_64
// REQUIRES: objc_interop
sil_stage canonical
import Builtin
import Swift
import gizmo
// CHECK: [[BLOCK_ISA:@_NSConcreteStackBlock]] = external global %objc_class
// CHECK: [[VOID_BLOCK_SIGNATURE:@.*]] = private unnamed_addr constant {{.*}} c"v8@?0\00"
// CHECK: [[TRIVIAL_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } {
// CHECK: i64 0,
// CHECK: i64 40,
// CHECK: i8* {{.*}} [[VOID_BLOCK_SIGNATURE]]
// CHECK: }
// CHECK: [[BLOCK_PARAM_BLOCK_SIGNATURE:@.*]] = private unnamed_addr constant {{.*}} c"v16@?0@?<q@?q>8\00"
// CHECK: [[BLOCK_PARAM_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } {
// CHECK: i64 0,
// CHECK: i64 40,
// CHECK: i8* {{.*}} [[BLOCK_PARAM_BLOCK_SIGNATURE]]
// CHECK: }
// CHECK: [[NONTRIVIAL_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } {
// CHECK: i64 0,
// CHECK: i64 40,
// CHECK: void ({ %objc_block, %swift.refcounted* }*, { %objc_block, %swift.refcounted* }*)* [[NONTRIVIAL_BLOCK_COPY:@[A-Za-z0-9_]+]],
// CHECK: void ({ %objc_block, %swift.refcounted* }*)* [[NONTRIVIAL_BLOCK_DISPOSE:@[A-Za-z0-9_]+]],
// CHECK: i8* {{.*}} [[VOID_BLOCK_SIGNATURE]]
// CHECK: }
// CHECK: [[NSRECT_BLOCK_SIGNATURE:@.*]] = private unnamed_addr constant {{.*}} c"{NSRect={NSPoint=dd}{NSSize=dd}}8@?0\00"
// CHECK: [[STRET_BLOCK_DESCRIPTOR:@.*]] = internal constant { {{.*}} } {
// CHECK: i64 0,
// CHECK: i64 40,
// CHECK: i8* {{.*}} [[NSRECT_BLOCK_SIGNATURE]]
// CHECK: }
// CHECK-LABEL: define{{( protected)?}} swiftcc i8* @project_block_storage({ %objc_block, i8* }* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-NEXT: entry:
// CHECK-NEXT: %1 = getelementptr inbounds { %objc_block, i8* }, { %objc_block, i8* }* %0, i32 0, i32 1
// CHECK-NEXT: %2 = load i8*, i8** %1, align 8
// CHECK-NEXT: ret i8* %2
// CHECK-NEXT: }
sil @project_block_storage : $@convention(thin) (@inout_aliasable @block_storage Builtin.RawPointer) -> Builtin.RawPointer {
entry(%0 : $*@block_storage Builtin.RawPointer):
%c = project_block_storage %0 : $*@block_storage Builtin.RawPointer
%p = load %c : $*Builtin.RawPointer
return %p : $Builtin.RawPointer
}
// CHECK-LABEL: define{{( protected)?}} swiftcc fp128 @overaligned_project_block_storage({ %objc_block, fp128 }* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-NEXT: entry:
// CHECK-NEXT: %1 = getelementptr inbounds { %objc_block, fp128 }, { %objc_block, fp128 }* %0, i32 0, i32 1
// CHECK-NEXT: %2 = load fp128, fp128* %1, align 16
// CHECK-NEXT: ret fp128 %2
// CHECK-NEXT: }
sil @overaligned_project_block_storage : $@convention(thin) (@inout_aliasable @block_storage Builtin.FPIEEE128) -> Builtin.FPIEEE128 {
entry(%0 : $*@block_storage Builtin.FPIEEE128):
%c = project_block_storage %0 : $*@block_storage Builtin.FPIEEE128
%p = load %c : $*Builtin.FPIEEE128
return %p : $Builtin.FPIEEE128
}
// CHECK-LABEL: define{{( protected)?}} swiftcc %objc_block* @init_block_header_trivial({ %objc_block, i8* }* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: [[HEADER:%.*]] = getelementptr inbounds { %objc_block, i8* }, { %objc_block, i8* }* %0, i32 0, i32 0
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 0
// CHECK: store %objc_class* [[BLOCK_ISA]], %objc_class** [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 1
// -- 0x4000_0000 -- HAS_SIGNATURE
// CHECK: store i32 1073741824, i32* [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 2
// CHECK: store i32 0, i32* [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 3
// CHECK: store i8* bitcast ({{.*}} @invoke_trivial to i8*), i8** [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 4
// CHECK: store i8* bitcast ({{.*}} [[TRIVIAL_BLOCK_DESCRIPTOR]] to i8*), i8** [[T0]]
// CHECK: [[RESULT:%.*]] = bitcast {{.*}} %0 to %objc_block*
// CHECK: ret %objc_block* [[RESULT]]
sil @init_block_header_trivial : $@convention(thin) (@inout_aliasable @block_storage Builtin.RawPointer) -> @convention(block) () -> () {
entry(%0 : $*@block_storage Builtin.RawPointer):
%i = function_ref @invoke_trivial : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> ()
%b = init_block_storage_header %0 : $*@block_storage Builtin.RawPointer, invoke %i : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> (), type $@convention(block) () -> ()
return %b : $@convention(block) () -> ()
}
// CHECK-LABEL: define{{( protected)?}} void @invoke_trivial(void (...)*) {{.*}} {
// CHECK: %1 = bitcast void (...)* %0 to { %objc_block, i8* }*
// CHECK: %2 = getelementptr inbounds { %objc_block, i8* }, { %objc_block, i8* }* %1, i32 0, i32 1
sil @invoke_trivial : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> () {
entry(%0 : $*@block_storage Builtin.RawPointer):
%c = project_block_storage %0 : $*@block_storage Builtin.RawPointer
return undef : $()
}
sil @init_block_header_trivial_block_param : $@convention(thin) (@inout_aliasable @block_storage Builtin.RawPointer) -> @convention(block) (@convention(block) (Int) -> Int) -> () {
entry(%0 : $*@block_storage Builtin.RawPointer):
%i = function_ref @invoke_trivial_block_param : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer, @convention(block) (Int) -> Int) -> ()
%b = init_block_storage_header %0 : $*@block_storage Builtin.RawPointer, invoke %i : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer, @convention(block) (Int) -> Int) -> (), type $@convention(block) (@convention(block) (Int) -> Int) -> ()
return %b : $@convention(block) (@convention(block) (Int) -> Int) -> ()
}
sil @invoke_trivial_block_param : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer, @convention(block) (Int) -> Int) -> ()
// CHECK-LABEL: define{{( protected)?}} i64 @invoke_trivial_with_arg(void (...)*, i64) {{.*}} {
// CHECK: ret i64 %1
sil @invoke_trivial_with_arg : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer, Int) -> Int {
entry(%0 : $*@block_storage Builtin.RawPointer, %1 : $Int):
return %1 : $Int
}
// CHECK-LABEL: define{{( protected)?}} swiftcc %objc_block* @init_block_header_nontrivial({ %objc_block, %swift.refcounted* }* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: [[HEADER:%.*]] = getelementptr inbounds
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 0
// CHECK: store %objc_class* [[BLOCK_ISA]], %objc_class** [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 1
// -- 0x4200_0000 -- HAS_SIGNATURE, HAS_COPY_DISPOSE
// CHECK: store i32 1107296256, i32* [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 2
// CHECK: store i32 0, i32* [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 3
// CHECK: store i8* bitcast ({{.*}} @invoke_nontrivial to i8*), i8** [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 4
// CHECK: store i8* bitcast ({{.*}} [[NONTRIVIAL_BLOCK_DESCRIPTOR]] to i8*), i8** [[T0]]
sil @init_block_header_nontrivial : $@convention(thin) (@inout_aliasable @block_storage Builtin.NativeObject) -> @convention(block) () -> () {
entry(%0 : $*@block_storage Builtin.NativeObject):
%i = function_ref @invoke_nontrivial : $@convention(c) (@inout_aliasable @block_storage Builtin.NativeObject) -> ()
%b = init_block_storage_header %0 : $*@block_storage Builtin.NativeObject, invoke %i : $@convention(c) (@inout_aliasable @block_storage Builtin.NativeObject) -> (), type $@convention(block) () -> ()
return %b : $@convention(block) () -> ()
}
// CHECK: define internal void [[NONTRIVIAL_BLOCK_COPY]]
// CHECK-NEXT: entry:
// CHECK-NEXT: %2 = getelementptr inbounds { %objc_block, %swift.refcounted* }, { %objc_block, %swift.refcounted* }* %0, i32 0, i32 1
// CHECK-NEXT: %3 = getelementptr inbounds { %objc_block, %swift.refcounted* }, { %objc_block, %swift.refcounted* }* %1, i32 0, i32 1
// CHECK-NEXT: %4 = load %swift.refcounted*, %swift.refcounted** %3, align 8
// CHECK-NEXT: call %swift.refcounted* @swift_rt_swift_retain(%swift.refcounted* returned %4) {{#[0-9]+}}
// CHECK-NEXT: store %swift.refcounted* %4, %swift.refcounted** %2, align 8
// CHECK-NEXT: ret void
// CHECK: define internal void [[NONTRIVIAL_BLOCK_DISPOSE]]
// CHECK-NEXT: entry:
// CHECK-NEXT: %1 = getelementptr inbounds { %objc_block, %swift.refcounted* }, { %objc_block, %swift.refcounted* }* %0, i32 0, i32 1
// CHECK-NEXT: %toDestroy = load %swift.refcounted*, %swift.refcounted** %1, align 8
// CHECK-NEXT: call void @swift_rt_swift_release(%swift.refcounted* %toDestroy) {{#[0-9]+}}
// CHECK-NEXT: ret void
sil public_external @invoke_nontrivial : $@convention(c) (@inout_aliasable @block_storage Builtin.NativeObject) -> ()
// CHECK-LABEL: define{{( protected)?}} swiftcc %objc_block* @init_block_header_stret({ %objc_block, i8* }* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: [[HEADER:%.*]] = getelementptr inbounds
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 0
// CHECK: store %objc_class* [[BLOCK_ISA]], %objc_class** [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 1
// -- 0x6000_0000 -- HAS_STRET, HAS_SIGNATURE
// CHECK: store i32 1610612736, i32* [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 2
// CHECK: store i32 0, i32* [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 3
// CHECK: store i8* bitcast ({{.*}} @invoke_stret to i8*), i8** [[T0]]
// CHECK: [[T0:%.*]] = getelementptr inbounds %objc_block, %objc_block* [[HEADER]], i32 0, i32 4
// CHECK: store i8* bitcast ({{.*}} [[STRET_BLOCK_DESCRIPTOR]] to i8*), i8** [[T0]]
sil @init_block_header_stret : $@convention(thin) (@inout_aliasable @block_storage Builtin.RawPointer) -> @convention(block) () -> NSRect {
entry(%0 : $*@block_storage Builtin.RawPointer):
%i = function_ref @invoke_stret : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> NSRect
%b = init_block_storage_header %0 : $*@block_storage Builtin.RawPointer, invoke %i : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> NSRect, type $@convention(block) () -> NSRect
return %b : $@convention(block) () -> NSRect
}
sil public_external @invoke_stret : $@convention(c) (@inout_aliasable @block_storage Builtin.RawPointer) -> NSRect