Files
swift-mirror/test/SILOptimizer/objectoutliner.sil
Erik Eckstein 71a642e51b stdlib, SIL optimizer: use the SIL copy-on-write representation in the Array types.
Use the new builtins for COW representation in Array, ContiguousArray and ArraySlice.
The basic idea is to strictly separate code which mutates an array buffer from code which reads from an array.
The concept is explained in more detail in docs/SIL.rst, section "Copy-on-Write Representation".

The main change is to use beginCOWMutation() instead of isUniquelyReferenced() and insert endCOWMutation() at the end of all mutating functions. Also, reading from the array buffer must be done differently, depending on if the buffer is in a mutable or immutable state.

All the required invariants are enforced by runtime checks - but only in an assert-build of the library: a bit in the buffer object side-table indicates if the buffer is mutable or not.

Along with the library changes, also two optimizations needed to be updated: COWArrayOpt and ObjectOutliner.
2020-06-08 15:02:22 +02:00

281 lines
9.0 KiB
Plaintext

// RUN: %target-sil-opt -enable-sil-verify-all %s -object-outliner | %FileCheck %s
//
sil_stage canonical
import Builtin
import Swift
class Base { }
class Obj : Base {
@_hasStorage var value: Int64
}
// CHECK-LABEL: sil_global private @outline_global_simpleTv_ : $Obj = {
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 1
// CHECK-NEXT: %1 = struct $Int64 (%0 : $Builtin.Int64)
// CHECK-NEXT: %initval = object $Obj (%1 : $Int64)
// CHECK-NEXT: }
// CHECK-LABEL: sil_global private @outline_global_tailelemsTv_ : $Obj = {
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 3
// CHECK-NEXT: %1 = struct $Int64 (%0 : $Builtin.Int64)
// CHECK-NEXT: %2 = integer_literal $Builtin.Int64, 2
// CHECK-NEXT: %3 = struct $Int64 (%2 : $Builtin.Int64)
// CHECK-NEXT: %4 = integer_literal $Builtin.Int64, 1
// CHECK-NEXT: %5 = struct $Int64 (%4 : $Builtin.Int64)
// CHECK-NEXT: %initval = object $Obj (%5 : $Int64, [tail_elems] %3 : $Int64, %1 : $Int64)
// CHECK-NEXT: }
// CHECK-LABEL: sil @outline_global_simple
// CHECK: [[G:%[0-9]+]] = global_value @outline_global_simpleTv_ : $Obj
// CHECK: strong_retain [[G]] : $Obj
// CHECK-NOT: store
// CHECK: strong_release [[G]] : $Obj
// CHECK: return
sil @outline_global_simple : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 0
%1 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%1 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%10 = end_cow_mutation %7 : $Obj
strong_release %10 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @outline_global_with_upcast
// CHECK: [[G:%[0-9]+]] = global_value @outline_global_with_upcastTv_ : $Obj
// CHECK: strong_retain [[G]] : $Obj
// CHECK: [[C:%[0-9]+]] = upcast [[G]] : $Obj to $Base
// CHECK-NOT: store
// CHECK: strong_release [[C]] : $Base
// CHECK: return
sil @outline_global_with_upcast : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 0
%1 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%1 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%8 = upcast %7 : $Obj to $Base
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%10 = end_cow_mutation %8 : $Base
strong_release %10 : $Base
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @outline_global_tailelems
// CHECK: [[G:%[0-9]+]] = global_value @outline_global_tailelemsTv_ : $Obj
// CHECK: strong_retain [[G]] : $Obj
// CHECK-NOT: store
// CHECK: strong_release [[G]] : $Obj
// CHECK: return
sil @outline_global_tailelems : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 2
%1 = integer_literal $Builtin.Int64, 1
%2 = integer_literal $Builtin.Int64, 2
%3 = integer_literal $Builtin.Int64, 3
%4 = struct $Int64 (%1 : $Builtin.Int64)
%5 = struct $Int64 (%2 : $Builtin.Int64)
%6 = struct $Int64 (%3 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%15 = ref_tail_addr %7 : $Obj, $Int64
store %5 to %15 : $*Int64
%19 = integer_literal $Builtin.Word, 1
%20 = index_addr %15 : $*Int64, %19 : $Builtin.Word
store %6 to %20 : $*Int64
%21 = end_cow_mutation %7 : $Obj
strong_release %21 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @handle_deallocation
// CHECK: global_value
// CHECK-NEXT: strong_retain
// CHECK-NEXT: ref_element_addr
// CHECK-NEXT: strong_release
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @handle_deallocation : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 0
%3 = integer_literal $Builtin.Int64, 3
%4 = struct $Int64 (%3 : $Builtin.Int64)
%5 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%6 = ref_element_addr %5 : $Obj, #Obj.value
store %4 to %6 : $*Int64
%10 = end_cow_mutation %5 : $Obj
set_deallocating %10 : $Obj
dealloc_ref %10 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_outline_without_tail_elems
// CHECK: alloc_ref
// CHECK: store
// CHECK: return
sil @dont_outline_without_tail_elems : $@convention(thin) () -> () {
bb0:
%1 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%1 : $Builtin.Int64)
%7 = alloc_ref $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%10 = end_cow_mutation %7 : $Obj
strong_release %10 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_outline_global_double_store
// CHECK: alloc_ref
// CHECK: store
// CHECK: return
sil @dont_outline_global_double_store : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 0
%1 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%1 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
store %4 to %9 : $*Int64
%10 = end_cow_mutation %7 : $Obj
strong_release %10 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_outline_global_missing_store
// CHECK: alloc_ref
// CHECK: return
sil @dont_outline_global_missing_store : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 0
%1 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%1 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
%10 = end_cow_mutation %7 : $Obj
strong_release %10 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_outline_objc_allocation
// CHECK: alloc_ref
// CHECK: return
sil @dont_outline_objc_allocation : $@convention(thin) () -> () {
bb0:
%1 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%1 : $Builtin.Int64)
// A hack, because Obj is not really an ObjC class. But for the test it should be ok.
%7 = alloc_ref [objc] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%10 = end_cow_mutation %7 : $Obj
strong_release %10 : $Obj
%r = tuple ()
return %r : $()
}
sil @take_pointer : $@convention(thin) (Builtin.RawPointer) -> ()
// CHECK-LABEL: sil @dont_outline_global_unknown_addr_use
// CHECK: alloc_ref
// CHECK: return
sil @dont_outline_global_unknown_addr_use : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 0
%1 = integer_literal $Builtin.Int64, 1
%4 = struct $Int64 (%1 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%10 = address_to_pointer %9 : $*Int64 to $Builtin.RawPointer
%f = function_ref @take_pointer : $@convention(thin) (Builtin.RawPointer) -> ()
%a = apply %f(%10) : $@convention(thin) (Builtin.RawPointer) -> ()
%12 = end_cow_mutation %7 : $Obj
strong_release %12 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_outline_global_escaping_obj
// CHECK: alloc_ref
// CHECK: return
sil @dont_outline_global_escaping_obj : $@convention(thin) (@inout Obj) -> () {
bb0(%0: $*Obj):
%1 = integer_literal $Builtin.Int64, 1
%2 = integer_literal $Builtin.Word, 0
%4 = struct $Int64 (%1 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %2 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
store %7 to %0 : $*Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_outline_global_missing_tailelem_store
// CHECK: alloc_ref
// CHECK: return
sil @dont_outline_global_missing_tailelem_store : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 2
%1 = integer_literal $Builtin.Int64, 1
%2 = integer_literal $Builtin.Int64, 2
%3 = integer_literal $Builtin.Int64, 3
%4 = struct $Int64 (%1 : $Builtin.Int64)
%5 = struct $Int64 (%2 : $Builtin.Int64)
%6 = struct $Int64 (%3 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%15 = ref_tail_addr %7 : $Obj, $Int64
store %5 to %15 : $*Int64
%16 = end_cow_mutation %7 : $Obj
strong_release %16 : $Obj
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @dont_outline_global_double_tailelem_store
// CHECK: alloc_ref
// CHECK: return
sil @dont_outline_global_double_tailelem_store : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 2
%1 = integer_literal $Builtin.Int64, 1
%2 = integer_literal $Builtin.Int64, 2
%3 = integer_literal $Builtin.Int64, 3
%4 = struct $Int64 (%1 : $Builtin.Int64)
%5 = struct $Int64 (%2 : $Builtin.Int64)
%6 = struct $Int64 (%3 : $Builtin.Int64)
%7 = alloc_ref [tail_elems $Int64 * %0 : $Builtin.Word] $Obj
%9 = ref_element_addr %7 : $Obj, #Obj.value
store %4 to %9 : $*Int64
%15 = ref_tail_addr %7 : $Obj, $Int64
store %5 to %15 : $*Int64
store %5 to %15 : $*Int64
%19 = integer_literal $Builtin.Word, 1
%20 = index_addr %15 : $*Int64, %19 : $Builtin.Word
store %6 to %20 : $*Int64
%21 = end_cow_mutation %7 : $Obj
strong_release %21 : $Obj
%r = tuple ()
return %r : $()
}