mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Which consists of * removing redundant `address_to_pointer`-`pointer_to_address` pairs * optimize `index_raw_pointer` of a manually computed stride to `index_addr` * remove or increase the alignment based on a "assumeAlignment" builtin This is a big code cleanup but also has some functional differences for the `address_to_pointer`-`pointer_to_address` pair removal: * It's not done if the resulting SIL would result in a (detectable) use-after-dealloc_stack memory lifetime failure. * It's not done if `copy_value`s must be inserted or borrow-scopes must be extended to comply with ownership rules (this was the task of the OwnershipRAUWHelper). Inserting copies is bad anyway. Extending borrow-scopes would only be required if the original lifetime of the pointer extends a borrow scope - which shouldn't happen in save code. Therefore this is a very rare case which is not worth handling.
354 lines
18 KiB
Plaintext
354 lines
18 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-objc-interop -enforce-exclusivity=none -enable-sil-verify-all %s -sil-combine -sil-combine-disable-alloc-stack-opts | %FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
class Klass {}
|
|
|
|
sil @returnInt : $@convention(thin) () -> Builtin.Int32
|
|
sil @use_anyobject : $@convention(thin) (@guaranteed AnyObject) -> ()
|
|
sil @use_nativeobject : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
|
|
// CHECK-LABEL: sil @optimize_convert_escape_to_noescape :
|
|
// CHECK: [[FN:%.*]] = function_ref @returnInt
|
|
// CHECK: apply [[FN]]()
|
|
// CHECK: } // end sil function 'optimize_convert_escape_to_noescape'
|
|
sil @optimize_convert_escape_to_noescape : $@convention(thin) () -> Builtin.Int32 {
|
|
bb0:
|
|
%0 = function_ref @returnInt : $@convention(thin) () -> Builtin.Int32
|
|
%1 = thin_to_thick_function %0 : $@convention(thin) () -> Builtin.Int32 to $@callee_guaranteed () -> Builtin.Int32
|
|
%2 = convert_escape_to_noescape %1 : $@callee_guaranteed () -> Builtin.Int32 to $@noescape @callee_guaranteed () -> Builtin.Int32
|
|
%4 = apply %2() : $@noescape @callee_guaranteed () -> Builtin.Int32
|
|
return %4 : $Builtin.Int32
|
|
}
|
|
|
|
// We have an extra thin_to_thick_function here since we do not yet have the
|
|
// optimization for eliminating it enabled in OSSA yet.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @optimize_convert_escape_to_noescape_ossa :
|
|
// CHECK: [[FN:%.*]] = function_ref @returnInt
|
|
// CHECK: apply [[FN]]()
|
|
// CHECK: } // end sil function 'optimize_convert_escape_to_noescape_ossa'
|
|
sil [ossa] @optimize_convert_escape_to_noescape_ossa : $@convention(thin) () -> Builtin.Int32 {
|
|
bb0:
|
|
%0 = function_ref @returnInt : $@convention(thin) () -> Builtin.Int32
|
|
%1 = thin_to_thick_function %0 : $@convention(thin) () -> Builtin.Int32 to $@callee_guaranteed () -> Builtin.Int32
|
|
%2 = convert_escape_to_noescape %1 : $@callee_guaranteed () -> Builtin.Int32 to $@noescape @callee_guaranteed () -> Builtin.Int32
|
|
%4 = apply %2() : $@noescape @callee_guaranteed () -> Builtin.Int32
|
|
destroy_value %2 : $@noescape @callee_guaranteed () -> Builtin.Int32
|
|
return %4 : $Builtin.Int32
|
|
}
|
|
|
|
//////////////////////////////
|
|
// ref_to_raw_pointer tests //
|
|
//////////////////////////////
|
|
|
|
// RefToRawPointer pointer consumption.
|
|
//
|
|
// (ref_to_raw_pointer (unchecked_ref_cast x))
|
|
// -> (ref_to_raw_pointer x)
|
|
//
|
|
// CHECK-LABEL: sil @ref_to_raw_pointer_unchecked_ref_cast_composition : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: ref_to_raw_pointer
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'ref_to_raw_pointer_unchecked_ref_cast_composition'
|
|
sil @ref_to_raw_pointer_unchecked_ref_cast_composition : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer {
|
|
bb0(%0 : $Klass):
|
|
%1 = unchecked_ref_cast %0 : $Klass to $Builtin.NativeObject
|
|
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
return %2 : $Builtin.RawPointer
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_guaranteed : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: ref_to_raw_pointer
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_guaranteed'
|
|
sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_guaranteed : $@convention(thin) (@guaranteed Klass) -> Builtin.RawPointer {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = unchecked_ref_cast %0 : $Klass to $Builtin.NativeObject
|
|
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
return %2 : $Builtin.RawPointer
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_owned : $@convention(thin) (@owned Klass) -> Builtin.RawPointer
|
|
// CHECK: bb0([[ARG:%.*]] : @owned
|
|
// CHECK-NEXT: [[RESULT:%.*]] = ref_to_raw_pointer [[ARG]]
|
|
// CHECK-NEXT: [[CAST:%.*]] = unchecked_ref_cast [[ARG]]
|
|
// CHECK-NEXT: destroy_value [[CAST]]
|
|
// CHECK-NEXT: return [[RESULT]]
|
|
// CHECK: } // end sil function 'ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_owned'
|
|
sil [ossa] @ref_to_raw_pointer_unchecked_ref_cast_composition_ossa_owned : $@convention(thin) (@owned Klass) -> Builtin.RawPointer {
|
|
bb0(%0 : @owned $Klass):
|
|
%1 = unchecked_ref_cast %0 : $Klass to $Builtin.NativeObject
|
|
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
destroy_value %1 : $Builtin.NativeObject
|
|
return %2 : $Builtin.RawPointer
|
|
}
|
|
|
|
// CHECK-LABEL: sil @collapse_existential_pack_unpack_ref_to_raw_pointer :
|
|
// CHECK: bb0([[Ref:%.*]] : $Klass):
|
|
// CHECK-NOT: init_existential_ref
|
|
// CHECK-NOT: open_existential_ref
|
|
// CHECK: ref_to_raw_pointer [[Ref]]
|
|
// CHECK: } // end sil function 'collapse_existential_pack_unpack_ref_to_raw_pointer'
|
|
sil @collapse_existential_pack_unpack_ref_to_raw_pointer : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : $Klass):
|
|
%1 = init_existential_ref %0 : $Klass : $Klass, $AnyObject
|
|
%2 = open_existential_ref %1 : $AnyObject to $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self
|
|
%3 = ref_to_raw_pointer %2 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self to $Builtin.RawPointer
|
|
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Word
|
|
%5 = integer_literal $Builtin.Word, 5
|
|
store %5 to %4: $*Builtin.Word
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_guaranteed :
|
|
// CHECK: bb0([[Ref:%.*]] : @guaranteed $Klass):
|
|
// CHECK-NOT: init_existential_ref
|
|
// CHECK-NOT: open_existential_ref
|
|
// CHECK: ref_to_raw_pointer [[Ref]]
|
|
// CHECK: } // end sil function 'collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_guaranteed'
|
|
sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_guaranteed : $@convention(thin) (@guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass):
|
|
%1 = init_existential_ref %0 : $Klass : $Klass, $AnyObject
|
|
%2 = open_existential_ref %1 : $AnyObject to $@opened("3CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self
|
|
%3 = ref_to_raw_pointer %2 : $@opened("3CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self to $Builtin.RawPointer
|
|
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Word
|
|
%5 = integer_literal $Builtin.Word, 5
|
|
store %5 to [trivial] %4: $*Builtin.Word
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// We need to hoist the ref_to_raw_pointer above the init_existential_ref since
|
|
// that is where %0 is live.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_owned :
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $Klass):
|
|
// CHECK-NOT: init_existential_ref
|
|
// CHECK-NOT: open_existential_ref
|
|
// CHECK: [[PTR:%.*]] = ref_to_raw_pointer [[ARG]]
|
|
// CHECK: [[FORWARDED_ARG:%.*]] = init_existential_ref [[ARG]]
|
|
// CHECK: destroy_value [[FORWARDED_ARG]]
|
|
// CHECK: } // end sil function 'collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_owned'
|
|
sil [ossa] @collapse_existential_pack_unpack_ref_to_raw_pointer_ossa_owned : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass):
|
|
%1 = init_existential_ref %0 : $Klass : $Klass, $AnyObject
|
|
%f = function_ref @use_anyobject : $@convention(thin) (@guaranteed AnyObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@guaranteed AnyObject) -> ()
|
|
%2 = open_existential_ref %1 : $AnyObject to $@opened("4CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self
|
|
%3 = ref_to_raw_pointer %2 : $@opened("4CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self to $Builtin.RawPointer
|
|
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Word
|
|
%5 = integer_literal $Builtin.Word, 5
|
|
store %5 to [trivial] %4: $*Builtin.Word
|
|
destroy_value %2 : $@opened("4CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
|
|
// (ref_to_raw_pointer (unchecked_ref_cast x)) -> (unchecked_trivial_bit_cast x)
|
|
//
|
|
// CHECK-LABEL: sil @collapse_to_unchecked_trivial_bit_cast :
|
|
// CHECK: bb0([[Ref:%.*]] : $Optional<Klass>):
|
|
// CHECK: unchecked_trivial_bit_cast [[Ref]]
|
|
// CHECK-NOT: unchecked_ref_cast
|
|
// CHECK-NOT: ref_to_raw_pointer
|
|
// CHECK: } // end sil function 'collapse_to_unchecked_trivial_bit_cast'
|
|
sil @collapse_to_unchecked_trivial_bit_cast : $@convention(thin) (Optional<Klass>) -> (Builtin.RawPointer) {
|
|
bb0(%0 : $Optional<Klass>):
|
|
%1 = unchecked_ref_cast %0 : $Optional<Klass> to $Builtin.NativeObject
|
|
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
return %2 : $Builtin.RawPointer
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_guaranteed :
|
|
// CHECK: bb0([[Ref:%.*]] : @guaranteed $Optional<Klass>):
|
|
// CHECK: unchecked_trivial_bit_cast [[Ref]]
|
|
// CHECK-NOT: unchecked_ref_cast
|
|
// CHECK-NOT: ref_to_raw_pointer
|
|
// CHECK: } // end sil function 'collapse_to_unchecked_trivial_bit_cast_ossa_guaranteed'
|
|
sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_guaranteed : $@convention(thin) (@guaranteed Optional<Klass>) -> (Builtin.RawPointer) {
|
|
bb0(%0 : @guaranteed $Optional<Klass>):
|
|
%1 = unchecked_ref_cast %0 : $Optional<Klass> to $Builtin.NativeObject
|
|
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
return %2 : $Builtin.RawPointer
|
|
}
|
|
|
|
// We need to make sure that we hoist unchecked_trivial_bit_cast above
|
|
// unchecked_ref_cast since we are not eliminating it here due to an additional
|
|
// user.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_owned :
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $Optional<Klass>):
|
|
// CHECK: [[RESULT:%.*]] = unchecked_trivial_bit_cast [[ARG]]
|
|
// CHECK: [[FORWARDED_ARG:%.*]] = unchecked_ref_cast [[ARG]]
|
|
// CHECK: destroy_value [[FORWARDED_ARG]]
|
|
// CHECK: return [[RESULT]]
|
|
// CHECK: } // end sil function 'collapse_to_unchecked_trivial_bit_cast_ossa_owned'
|
|
sil [ossa] @collapse_to_unchecked_trivial_bit_cast_ossa_owned : $@convention(thin) (@owned Optional<Klass>) -> (Builtin.RawPointer) {
|
|
bb0(%0 : @owned $Optional<Klass>):
|
|
%1 = unchecked_ref_cast %0 : $Optional<Klass> to $Builtin.NativeObject
|
|
%f = function_ref @use_nativeobject : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
apply %f(%1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
%2 = ref_to_raw_pointer %1 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
destroy_value %1 : $Builtin.NativeObject
|
|
return %2 : $Builtin.RawPointer
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// SILCombiner::optimizeAlignment
|
|
//
|
|
// Optimize Builtin.assumeAlignment -> pointer_to_address
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Case #1. Literal zero = natural alignment
|
|
// %1 = integer_literal $Builtin.Int64, 0
|
|
// %2 = builtin "assumeAlignment"
|
|
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
|
|
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int
|
|
//
|
|
// Erases the `pointer_to_address` `[align=]` attribute:
|
|
//
|
|
// CHECK-LABEL: sil @test_zero_alignment : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
// CHECK: bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
// CHECK: [[PTR:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to $*T
|
|
// CHECK: copy_addr [[PTR]] to [init] %0 : $*T
|
|
// CHECK-LABEL: } // end sil function 'test_zero_alignment'
|
|
sil @test_zero_alignment : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
debug_value %1 : $Builtin.RawPointer, let, name "rawPointer", argno 1
|
|
debug_value %2 : $@thick T.Type, let, name "_1", argno 2
|
|
%5 = integer_literal $Builtin.Word, 0
|
|
%6 = builtin "assumeAlignment"(%1 : $Builtin.RawPointer, %5 : $Builtin.Word) : $Builtin.RawPointer
|
|
debug_value %6 : $Builtin.RawPointer, let, name "alignedPointer"
|
|
%8 = pointer_to_address %6 : $Builtin.RawPointer to [align=1] $*T
|
|
copy_addr %8 to [init] %0 : $*T
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
// Case #2. Literal nonzero = forced alignment.
|
|
//
|
|
// %1 = integer_literal $Builtin.Int64, 16
|
|
// %2 = builtin "assumeAlignment"
|
|
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
|
|
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int
|
|
//
|
|
// Promotes the `pointer_to_address` `[align=]` attribute to a higher value.
|
|
//
|
|
// CHECK-LABEL: sil @test_nonzero_alignment : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
// CHECK: bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
// CHECK: [[PTR:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to [align=8] $*T
|
|
// CHECK: copy_addr [[PTR]] to [init] %0 : $*T
|
|
// CHECK-LABEL: } // end sil function 'test_nonzero_alignment'
|
|
sil @test_nonzero_alignment : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
debug_value %1 : $Builtin.RawPointer, let, name "rawPointer", argno 1
|
|
debug_value %2 : $@thick T.Type, let, name "_1", argno 2
|
|
%5 = integer_literal $Builtin.Word, 8
|
|
%6 = builtin "assumeAlignment"(%1 : $Builtin.RawPointer, %5 : $Builtin.Word) : $Builtin.RawPointer
|
|
debug_value %6 : $Builtin.RawPointer, let, name "alignedPointer"
|
|
%8 = pointer_to_address %6 : $Builtin.RawPointer to [align=1] $*T
|
|
copy_addr %8 to [init] %0 : $*T
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
// Case #3. Folded dynamic alignment
|
|
//
|
|
// %1 = builtin "alignof"<T>(%0 : $@thin T.Type) : $Builtin.Word
|
|
// %2 = builtin "assumeAlignment"
|
|
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
|
|
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*T
|
|
//
|
|
// Erases the `pointer_to_address` `[align=]` attribute.
|
|
//
|
|
// CHECK-LABEL: sil @test_dynamic_alignment : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
// CHECK: bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
// CHECK-NOT: metatype
|
|
// CHECK-NOT: builtin "alignOf"
|
|
// CHECK-NOT: builtin "assumeAlignment"
|
|
// CHECK: [[PTR:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to $*T
|
|
// CHECK: copy_addr [[PTR]] to [init] %0 : $*T
|
|
// CHECK-LABEL: } // end sil function 'test_dynamic_alignment'
|
|
sil @test_dynamic_alignment : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
debug_value %1 : $Builtin.RawPointer, let, name "rawPointer", argno 1
|
|
debug_value %2 : $@thick T.Type, let, name "_1", argno 2
|
|
%5 = metatype $@thick T.Type
|
|
%6 = builtin "alignof"<T>(%5 : $@thick T.Type) : $Builtin.Word
|
|
%7 = builtin "sextOrBitCast_Word_Int64"(%6 : $Builtin.Word) : $Builtin.Int64
|
|
%8 = struct $Int64 (%7 : $Builtin.Int64)
|
|
debug_value %8 : $Int64, let, name "align"
|
|
%10 = builtin "truncOrBitCast_Int64_Word"(%7 : $Builtin.Int64) : $Builtin.Word
|
|
%11 = builtin "assumeAlignment"(%1 : $Builtin.RawPointer, %10 : $Builtin.Word) : $Builtin.RawPointer
|
|
debug_value %11 : $Builtin.RawPointer, let, name "alignedPointer"
|
|
%13 = pointer_to_address %11 : $Builtin.RawPointer to [align=1] $*T
|
|
copy_addr %13 to [init] %0 : $*T
|
|
%15 = tuple ()
|
|
return %15 : $()
|
|
}
|
|
|
|
// Case #3b. Folded dynamic alignment; 32-bit
|
|
//
|
|
// %1 = builtin "alignof"<T>(%0 : $@thin T.Type) : $Builtin.Word
|
|
// %2 = builtin "assumeAlignment"
|
|
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
|
|
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*T
|
|
//
|
|
// Erases the `pointer_to_address` `[align=]` attribute.
|
|
//
|
|
// CHECK-LABEL: sil @test_dynamic_alignment32 : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
// CHECK: bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
// CHECK-NOT: metatype
|
|
// CHECK-NOT: builtin "alignOf"
|
|
// CHECK-NOT: builtin "assumeAlignment"
|
|
// CHECK: [[PTR:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to $*T
|
|
// CHECK: copy_addr [[PTR]] to [init] %0 : $*T
|
|
// CHECK-LABEL: } // end sil function 'test_dynamic_alignment32'
|
|
sil @test_dynamic_alignment32 : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
|
|
bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
|
|
debug_value %1 : $Builtin.RawPointer, let, name "rawPointer", argno 1
|
|
debug_value %2 : $@thick T.Type, let, name "_1", argno 2
|
|
%5 = metatype $@thick T.Type
|
|
%6 = builtin "alignof"<T>(%5 : $@thick T.Type) : $Builtin.Word
|
|
%7 = builtin "truncOrBitCast_Word_Int32"(%6 : $Builtin.Word) : $Builtin.Int32
|
|
%8 = struct $Int32 (%7 : $Builtin.Int32)
|
|
debug_value %8 : $Int32, let, name "align"
|
|
%10 = builtin "sextOrBitCast_Int32_Word"(%7 : $Builtin.Int32) : $Builtin.Word
|
|
%11 = builtin "assumeAlignment"(%1 : $Builtin.RawPointer, %10 : $Builtin.Word) : $Builtin.RawPointer
|
|
debug_value %11 : $Builtin.RawPointer, let, name "alignedPointer"
|
|
%13 = pointer_to_address %11 : $Builtin.RawPointer to [align=1] $*T
|
|
copy_addr %13 to [init] %0 : $*T
|
|
%15 = tuple ()
|
|
return %15 : $()
|
|
}
|
|
|
|
public protocol AnyAction {
|
|
}
|
|
|
|
public struct MyAction : AnyAction {
|
|
}
|
|
|
|
// Make sure that we do not crash on this test case!
|
|
//
|
|
// TODO: Maybe we could handle this?
|
|
sil shared @cast_optimizer_metatype_crasher : $@convention(thin) (@thick MyAction.Type) -> @thick AnyAction.Type {
|
|
bb0(%0 : $@thick MyAction.Type):
|
|
%1 = alloc_stack $@thick AnyAction.Type
|
|
%2 = alloc_stack $@thick MyAction.Type
|
|
store %0 to %2 : $*@thick MyAction.Type
|
|
unconditional_checked_cast_addr MyAction.Type in %2 : $*@thick MyAction.Type to AnyAction.Type in %1 : $*@thick AnyAction.Type
|
|
dealloc_stack %2 : $*@thick MyAction.Type
|
|
%6 = tuple ()
|
|
%7 = load %1 : $*@thick AnyAction.Type
|
|
dealloc_stack %1 : $*@thick AnyAction.Type
|
|
return %7 : $@thick AnyAction.Type
|
|
}
|