Files
swift-mirror/test/SILOptimizer/moveonly_temp_allocation_elim.sil
Michael Gottesman 170ba67bd3 [move-only] Eliminate some temporary copies inserted by SILGen when accessing fields of lets.
In the next commit, I am modifying the move only checker to ensure that we
always error when partially invalidating. While doing this I discovered that
these copies were getting in the way of emitting good diagnostics in that case.
2023-06-27 13:41:31 -07:00

191 lines
7.9 KiB
Plaintext

// RUN: %target-sil-opt -sil-verify-all -sil-move-only-temp-allocation-from-let-tester %s | %FileCheck %s
sil_stage raw
public class Klass {}
public struct Empty : ~Copyable {}
public struct SingleFieldLoadable : ~Copyable {
var e: Empty
var k: Klass
}
public enum LoadableEnum : ~Copyable {
case first(Empty)
case second(Klass)
}
public struct LoadableType : ~Copyable {
var e: Empty
var l: SingleFieldLoadable
var k: Klass
var lEnum: LoadableEnum
}
public protocol P {}
public struct SingleFieldAddressOnly : ~Copyable {
var e: Empty
var k: P
var en: AddressOnlyEnum
}
public struct SingleFieldAddressOnly2 : ~Copyable {
var e: Empty
var k: P
var en: AddressOnlyEnum
var s2: SingleFieldAddressOnly
}
public enum AddressOnlyEnum : ~Copyable {
case first(Empty)
case second(P)
}
public struct AddressOnlyType : ~Copyable {
var e: Empty
var l: SingleFieldAddressOnly2
var l2: SingleFieldAddressOnly
var k: P
var lEnum: AddressOnlyEnum
}
sil @get_addressonly_type : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
sil @sideeffect : $@convention(thin) () -> ()
/////////////////
// MARK: Tests //
/////////////////
// CHECK-LABEL: sil hidden [ossa] @accessGrandLoadableField : $@convention(thin) () -> () {
// CHECK: [[ALLOC:%.*]] = alloc_stack
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ALLOC]]
// CHECK: apply {{%.*}}([[MARK]], {{%.*}})
// CHECK: [[GEP1:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[GEP2:%.*]] = struct_element_addr [[GEP1]]
// CHECK: [[GEP3:%.*]] = struct_element_addr [[GEP2]]
// CHECK: [[LOAD:%.*]] = load [copy] [[GEP3]]
// CHECK: move_value [[LOAD]]
// CHECK: } // end sil function 'accessGrandLoadableField'
sil hidden [ossa] @accessGrandLoadableField : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack [lexical] $AddressOnlyType, let, name "x"
%1 = mark_must_check [consumable_and_assignable] %0 : $*AddressOnlyType
%2 = metatype $@thin AddressOnlyType.Type
%3 = function_ref @get_addressonly_type : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%4 = apply %3(%1, %2) : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%5 = struct_element_addr %1 : $*AddressOnlyType, #AddressOnlyType.l
%6 = alloc_stack $SingleFieldAddressOnly2
copy_addr %5 to [init] %6 : $*SingleFieldAddressOnly2
%8 = struct_element_addr %6 : $*SingleFieldAddressOnly2, #SingleFieldAddressOnly2.s2
%9 = alloc_stack $SingleFieldAddressOnly
copy_addr %8 to [init] %9 : $*SingleFieldAddressOnly
destroy_addr %6 : $*SingleFieldAddressOnly2
%12 = struct_element_addr %9 : $*SingleFieldAddressOnly, #SingleFieldAddressOnly.e
%13 = load [copy] %12 : $*Empty
destroy_addr %9 : $*SingleFieldAddressOnly
%15 = move_value %13 : $Empty
destroy_value %15 : $Empty
dealloc_stack %9 : $*SingleFieldAddressOnly
dealloc_stack %6 : $*SingleFieldAddressOnly2
destroy_addr %1 : $*AddressOnlyType
dealloc_stack %0 : $*AddressOnlyType
%21 = tuple ()
return %21 : $()
}
// CHECK-LABEL: sil hidden [ossa] @accessChildLoadableField : $@convention(thin) () -> () {
// CHECK: [[ALLOC:%.*]] = alloc_stack
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ALLOC]]
// CHECK: apply {{%.*}}([[MARK]], {{%.*}})
// CHECK: [[GEP1:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[GEP2:%.*]] = struct_element_addr [[GEP1]]
// CHECK: [[LOAD:%.*]] = load [copy] [[GEP2]]
// CHECK: move_value [[LOAD]]
// CHECK: } // end sil function 'accessChildLoadableField'
sil hidden [ossa] @accessChildLoadableField : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack [lexical] $AddressOnlyType, let, name "x"
%1 = mark_must_check [consumable_and_assignable] %0 : $*AddressOnlyType
%2 = metatype $@thin AddressOnlyType.Type
%3 = function_ref @get_addressonly_type : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%4 = apply %3(%1, %2) : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%5 = struct_element_addr %1 : $*AddressOnlyType, #AddressOnlyType.l
%6 = alloc_stack $SingleFieldAddressOnly2
copy_addr %5 to [init] %6 : $*SingleFieldAddressOnly2
%8 = struct_element_addr %6 : $*SingleFieldAddressOnly2, #SingleFieldAddressOnly2.e
%9 = load [copy] %8 : $*Empty
destroy_addr %6 : $*SingleFieldAddressOnly2
%11 = move_value %9 : $Empty
destroy_value %11 : $Empty
dealloc_stack %6 : $*SingleFieldAddressOnly2
destroy_addr %1 : $*AddressOnlyType
dealloc_stack %0 : $*AddressOnlyType
%16 = tuple ()
return %16 : $()
}
// CHECK-LABEL: sil hidden [ossa] @accessChildLoadableFieldWithBlockingSideEffect : $@convention(thin) () -> () {
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ALLOC]]
// CHECK: apply {{%.*}}([[MARK]], {{%.*}})
// CHECK: [[GEP1:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[TEMP:%.*]] = alloc_stack $SingleFieldAddressOnly2
// CHECK: copy_addr [[GEP1]] to [init] [[TEMP]]
// CHECK: apply {{%.*}}() :
// CHECK: [[GEP2:%.*]] = struct_element_addr [[TEMP]]
// CHECK: [[LOAD:%.*]] = load [copy] [[GEP2]]
// CHECK: move_value [[LOAD]]
// CHECK: } // end sil function 'accessChildLoadableFieldWithBlockingSideEffect'
sil hidden [ossa] @accessChildLoadableFieldWithBlockingSideEffect : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack [lexical] $AddressOnlyType, let, name "x"
%1 = mark_must_check [consumable_and_assignable] %0 : $*AddressOnlyType
%2 = metatype $@thin AddressOnlyType.Type
%3 = function_ref @get_addressonly_type : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%4 = apply %3(%1, %2) : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%5 = struct_element_addr %1 : $*AddressOnlyType, #AddressOnlyType.l
%6 = alloc_stack $SingleFieldAddressOnly2
// This is our original copy_addr. If there is a side effect in between it
// and %9 (our final use), then we conservatively bail.
copy_addr %5 to [init] %6 : $*SingleFieldAddressOnly2
%f = function_ref @sideeffect : $@convention(thin) () -> ()
apply %f() : $@convention(thin) () -> ()
%8 = struct_element_addr %6 : $*SingleFieldAddressOnly2, #SingleFieldAddressOnly2.e
%9 = load [copy] %8 : $*Empty
destroy_addr %6 : $*SingleFieldAddressOnly2
%11 = move_value %9 : $Empty
destroy_value %11 : $Empty
dealloc_stack %6 : $*SingleFieldAddressOnly2
destroy_addr %1 : $*AddressOnlyType
dealloc_stack %0 : $*AddressOnlyType
%16 = tuple ()
return %16 : $()
}
// CHECK-LABEL: sil hidden [ossa] @copyableAddressOnlyTest : $@convention(thin) () -> () {
// CHECK: [[ALLOC:%.*]] = alloc_stack
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ALLOC]]
// CHECK: apply {{%.*}}([[MARK]], {{%.*}})
// CHECK: [[GEP1:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[GEP2:%.*]] = struct_element_addr [[GEP1]]
// CHECK: [[RESULT:%.*]] = alloc_stack $any P
// CHECK: copy_addr [[GEP2]] to [init] [[RESULT]]
// CHECK: } // end sil function 'copyableAddressOnlyTest'
sil hidden [ossa] @copyableAddressOnlyTest : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack [lexical] $AddressOnlyType, let, name "x"
%1 = mark_must_check [consumable_and_assignable] %0 : $*AddressOnlyType
%2 = metatype $@thin AddressOnlyType.Type
%3 = function_ref @get_addressonly_type : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%4 = apply %3(%1, %2) : $@convention(method) (@thin AddressOnlyType.Type) -> @out AddressOnlyType
%5 = struct_element_addr %1 : $*AddressOnlyType, #AddressOnlyType.l
%6 = alloc_stack $SingleFieldAddressOnly2
copy_addr %5 to [init] %6 : $*SingleFieldAddressOnly2
%8 = struct_element_addr %6 : $*SingleFieldAddressOnly2, #SingleFieldAddressOnly2.k
%9 = alloc_stack $any P
copy_addr %8 to [init] %9 : $*any P
destroy_addr %6 : $*SingleFieldAddressOnly2
destroy_addr %9 : $*any P
dealloc_stack %9 : $*any P
dealloc_stack %6 : $*SingleFieldAddressOnly2
destroy_addr %1 : $*AddressOnlyType
dealloc_stack %0 : $*AddressOnlyType
%17 = tuple ()
return %17 : $()
}