Files
swift-mirror/test/SILOptimizer/basic-aa.sil
Andrew Trick cf962e0148 [SILVerifier] Disallow address-type block arguments in raw SIL.
As a structural SIL property, we disallow address-type block
arguments. Supporting them would prevent reliably reasoning about the
underlying storage of memory access. This reasoning is important for
diagnosing violations of memory access rules and supporting future
optimizations such as bitfield packing. Address-type block arguments
also create unnecessary complexity for SIL optimization passes that
need to reason about memory aliasing.

This must be enforced in RAW SIL for diagnosing exclusive memory
access. The optimizer currently breaks the invariant in three places:
1. Normal Simplify CFG during conditional branch simplification
   (sneaky jump threading).
2. Simplify CFG via Jump Threading.
3. Loop Rotation.
2018-02-27 09:53:13 -08:00

582 lines
21 KiB
Plaintext

// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enforce-exclusivity=none -module-name Swift %s -aa-kind=basic-aa -aa-dump -o /dev/null | %FileCheck %s
// REQUIRES: asserts
// Declare this SIL to be canonical because some tests break raw SIL
// conventions. e.g. address-type block args. -enforce-exclusivity=none is also
// required to allow address-type block args in canonical SIL.
sil_stage canonical
import Builtin
struct Int {
var _value: Builtin.Int64
}
struct Int32 {
var _value: Builtin.Int32
}
enum Optional<T> {
case none
case some(T)
}
// CHECK-LABEL: @index_addr_inst_with_unknown_index
// CHECK: PAIR #16.
// CHECK-NEXT: %3 = index_addr %2 : $*Int, %1 : $Builtin.Word
// CHECK-NEXT: %4 = index_addr %2 : $*Int, %1 : $Builtin.Word
// CHECK-NEXT: MayAlias
sil @index_addr_inst_with_unknown_index : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%212 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Int
%214 = index_addr %212 : $*Int, %1 : $Builtin.Word
%2114 = index_addr %212 : $*Int, %1 : $Builtin.Word
br bb1
bb1:
%3 = tuple()
return %3 : $()
}
// CHECK-LABEL: @index_addr_inst_with_same_constant_index
// CHECK: PAIR #16.
// CHECK-NEXT: %3 = index_addr %2 : $*Int, %1 : $Builtin.Word
// CHECK-NEXT: %4 = index_addr %2 : $*Int, %1 : $Builtin.Word
// CHECK-NEXT: MustAlias
sil @index_addr_inst_with_same_constant_index : $@convention(thin) (Builtin.RawPointer) -> () {
bb0(%0 : $Builtin.RawPointer):
%6 = integer_literal $Builtin.Word, 2
%212 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Int
%214 = index_addr %212 : $*Int, %6 : $Builtin.Word
%2114 = index_addr %212 : $*Int, %6 : $Builtin.Word
br bb1
bb1:
%3 = tuple()
return %3 : $()
}
// CHECK-LABEL: @index_addr_inst_with_different_constant_index
// CHECK: PAIR #23.
// CHECK-NEXT: %4 = index_addr %3 : $*Int, %1 : $Builtin.Word
// CHECK-NEXT: %5 = index_addr %3 : $*Int, %2 : $Builtin.Word
// CHECK-NEXT: NoAlias
sil @index_addr_inst_with_different_constant_index : $@convention(thin) (Builtin.RawPointer) -> () {
bb0(%0 : $Builtin.RawPointer):
%6 = integer_literal $Builtin.Word, 2
%7 = integer_literal $Builtin.Word, 3
%212 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Int
%214 = index_addr %212 : $*Int, %6 : $Builtin.Word
%2114 = index_addr %212 : $*Int, %7 : $Builtin.Word
br bb1
bb1:
%3 = tuple()
return %3 : $()
}
// Address Arguments don't alias if they are arguments to the first BB.
//
// CHECK-LABEL: @address_args_dont_alias_in_first_bb
// CHECK: PAIR #0.
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: MustAlias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = argument of bb0
// CHECK-NEXT: %1 = argument of bb0
// CHECK-NEXT: NoAlias
sil @address_args_dont_alias_in_first_bb : $@convention(thin) (@in Builtin.NativeObject, @in Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject, %1 : $*Builtin.NativeObject):
%2 = tuple()
return %2 : $()
}
// Address Arguments may alias if they are arguments to a BB besides the first.
//
// FIXME: Once we support looking through PHIs, we will allow for must alias here.
//
// CHECK-LABEL: @address_args_may_alias_in_non_first_bb
// CHECK-NOT: NoAlias
sil @address_args_may_alias_in_non_first_bb : $@convention(thin) (@inout Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject):
br bb1(%0 : $*Builtin.NativeObject, %0 : $*Builtin.NativeObject)
bb1(%1 : $*Builtin.NativeObject, %2 : $*Builtin.NativeObject):
%3 = tuple()
return %3 : $()
}
// Assume that inout arguments alias to preserve memory safety.
//
// CHECK-LABEL: @inout_args_may_alias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = argument of bb0
// CHECK-NEXT: %1 = argument of bb0
// CHECK-NEXT: MayAlias
sil @inout_args_may_alias: $@convention(thin) (@inout Builtin.NativeObject, @inout Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject, %1 : $*Builtin.NativeObject):
%2 = tuple()
return %2 : $()
}
struct StructLvl2 {
var tup : (Builtin.Int64, Builtin.Int32)
}
struct StructLvl1 {
var sub : StructLvl2
var x : Builtin.Int64
}
// Two values with different underlying alloc_stack cannot alias.
//
// CHECK-LABEL: @different_alloc_stack_dont_alias
// cannot alias non types.
// CHECK: PAIR #0.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: MustAlias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %1 = alloc_stack $StructLvl1
// CHECK-NEXT: NoAlias
// CHECK: PAIR #2.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %2 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #3.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %3 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.x
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #4.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %4 = struct_element_addr %2 : $*StructLvl2, #StructLvl2.tup
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #12.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %14 = tuple ()
// CHECK-NEXT: MayAlias
// CHECK: PAIR #21.
// CHECK-NEXT: %1 = alloc_stack $StructLvl1
// CHECK-NEXT: %9 = struct_element_addr %7 : $*StructLvl2, #StructLvl2.tup
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #22.
// CHECK-NEXT: %1 = alloc_stack $StructLvl1
// CHECK-NEXT: %10 = tuple_element_addr %9 : $*(Builtin.Int64, Builtin.Int32), 0
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #23.
// CHECK-NEXT: %1 = alloc_stack $StructLvl1
// CHECK-NEXT: %11 = tuple_element_addr %9 : $*(Builtin.Int64, Builtin.Int32), 1
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #26.
// CHECK-NEXT: %2 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
// CHECK-NEXT: %3 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.x
// CHECK-NEXT: NoAlias
// CHECK: PAIR #27.
// CHECK-NEXT: %2 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
// CHECK-NEXT: %4 = struct_element_addr %2 : $*StructLvl2, #StructLvl2.tup
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #28.
// CHECK-NEXT: %2 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
// CHECK-NEXT: %5 = tuple_element_addr %4 : $*(Builtin.Int64, Builtin.Int32), 0
// CHECK-NEXT: PartialAlias
// CHECK: PAIR #29.
// CHECK-NEXT: %2 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
// CHECK-NEXT: %6 = tuple_element_addr %4 : $*(Builtin.Int64, Builtin.Int32), 1
// CHECK-NEXT: PartialAlias
sil @different_alloc_stack_dont_alias : $@convention(thin) () -> () {
%0 = alloc_stack $StructLvl1
%1 = alloc_stack $StructLvl1
%2 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
%3 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.x
%4 = struct_element_addr %2 : $*StructLvl2, #StructLvl2.tup
%5 = tuple_element_addr %4 : $*(Builtin.Int64, Builtin.Int32), 0
%6 = tuple_element_addr %4 : $*(Builtin.Int64, Builtin.Int32), 1
%7 = struct_element_addr %1 : $*StructLvl1, #StructLvl1.sub
%8 = struct_element_addr %1 : $*StructLvl1, #StructLvl1.x
%9 = struct_element_addr %7 : $*StructLvl2, #StructLvl2.tup
%10 = tuple_element_addr %9 : $*(Builtin.Int64, Builtin.Int32), 0
%11 = tuple_element_addr %9 : $*(Builtin.Int64, Builtin.Int32), 1
dealloc_stack %1 : $*StructLvl1
dealloc_stack %0 : $*StructLvl1
%12 = tuple()
return %12 : $()
}
// Function Arguments cannot alias with no alias arguments or with identified
// function locals.
//
// CHECK-LABEL: @args_dont_alias_with_identified_function_locals
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: MayAlias
// CHECK: PAIR #2.
// CHECK-NEXT: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %2 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #3.
// CHECK-NEXT: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #4.
// CHECK-NEXT: %0 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %5 = tuple ()
// CHECK-NEXT: MayAlias
// CHECK: PAIR #6.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %2 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #7.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #10.
// CHECK-NEXT: %2 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
sil @args_dont_alias_with_identified_function_locals : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject, @in Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.NativeObject, %2 : $*Builtin.NativeObject):
%3 = alloc_stack $Builtin.NativeObject
dealloc_stack %3 : $*Builtin.NativeObject
%4 = tuple()
return %4 : $()
}
sil @create_native_object : $@convention(thin) () -> (Builtin.NativeObject)
sil @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
// For this test, we care about the following results:
// %1, %3, %5, %7, %8, %9
// Check every alias query involving those.
// CHECK-LABEL: @escapesource_functionlocal_test_escapesource_nonescapinglocal
// Test %0
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #2.
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: %2 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #3.
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #5.
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #8.
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.NativeObject
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: NoAlias
// Test %1 (the aliasing argument)
// CHECK: PAIR #11.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: MustAlias
// CHECK: PAIR #12.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %2 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #13.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #15.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: MayAlias
// CHECK: PAIR #16.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %6 = load %0 : $*Builtin.NativeObject
// CHECK-NEXT: MayAlias
// CHECK: PAIR #18.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: MayAlias
// CHECK: PAIR #19.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
// CHECK-NEXT: MayAlias
// Test %2
// CHECK: PAIR #22.
// CHECK-NEXT: %2 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #24.
// CHECK-NEXT: %2 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #25.
// CHECK-NEXT: %2 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %6 = load %0 : $*Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #27.
// CHECK-NEXT: %2 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #28.
// CHECK-NEXT: %2 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
// CHECK-NEXT: MayAlias
// Test %3 (the escaping alloca).
// CHECK: PAIR #32.
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #33.
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %6 = load %0 : $*Builtin.NativeObject
// CHECK-NEXT: NoAlias
// CHECK: PAIR #35.
// CHECK-NEXT: %3 = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: NoAlias
// Test %5 (the read write apply inst).
// CHECK: PAIR #45.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: MustAlias
// CHECK: PAIR #46.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: %6 = load %0 : $*Builtin.NativeObject
// CHECK-NEXT: MayAlias
// CHECK: PAIR #47.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: function_ref use_native_object
// CHECK-NEXT: %7 = function_ref @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
// CHECK-NEXT: MayAlias
// CHECK: PAIR #48.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: MayAlias
// CHECK: PAIR #49.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
// CHECK-NEXT: MayAlias
// Test %8 (the escaping load)
// CHECK: PAIR #60.
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: MustAlias
// CHECK: PAIR #61.
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
// CHECK-NEXT: MayAlias
sil @escapesource_functionlocal_test_escapesource_nonescapinglocal : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject, %1 : $Builtin.NativeObject):
%2 = alloc_stack $Builtin.NativeObject
%3 = alloc_stack $Builtin.NativeObject
%4 = function_ref @create_native_object : $@convention(thin) () -> Builtin.NativeObject
%5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
%6 = load %0 : $*Builtin.NativeObject
%7 = function_ref @use_native_object : $@convention(thin) (Builtin.NativeObject) -> ()
%8 = load %3 : $*Builtin.NativeObject
%9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
dealloc_stack %3 : $*Builtin.NativeObject
dealloc_stack %2 : $*Builtin.NativeObject
%12 = tuple ()
return %12 : $()
}
// CHECK-LABEL: @projections_from_the_same_source_with_the_same_projection_path_mustalias
// CHECK: PAIR #24.
// CHECK-NEXT: %3 = tuple_element_addr %2 : $*(Builtin.Int64, Builtin.Int32), 1
// CHECK-NEXT: %6 = tuple_element_addr %5 : $*(Builtin.Int64, Builtin.Int32), 1
// CHECK-NEXT: MustAlias
sil @projections_from_the_same_source_with_the_same_projection_path_mustalias : $@convention(thin) () -> () {
%0 = alloc_stack $StructLvl1
%1 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
%2 = struct_element_addr %1 : $*StructLvl2, #StructLvl2.tup
%3 = tuple_element_addr %2 : $*(Builtin.Int64, Builtin.Int32), 1
%4 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.sub
%5 = struct_element_addr %4 : $*StructLvl2, #StructLvl2.tup
%6 = tuple_element_addr %5 : $*(Builtin.Int64, Builtin.Int32), 1
dealloc_stack %0 : $*StructLvl1
%7 = tuple()
return %7 : $()
}
sil_global public @sil_global1 : $Builtin.Int32
sil_global public @sil_global2 : $Builtin.Int32
class X { }
// CHECK-LABEL: @globals_dont_alias
// CHECK: PAIR #0.
// CHECK-NEXT: %0 = global_addr @sil_global1 : $*Builtin.Int32
// CHECK-NEXT: %0 = global_addr @sil_global1 : $*Builtin.Int32
// CHECK-NEXT: MustAlias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = global_addr @sil_global1 : $*Builtin.Int32
// CHECK-NEXT: %1 = global_addr @sil_global2 : $*Builtin.Int32
// CHECK-NEXT: NoAlias
sil @globals_dont_alias : $@convention(thin) () -> () {
%0 = global_addr @sil_global1 : $*Builtin.Int32
%1 = global_addr @sil_global2 : $*Builtin.Int32
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: @globals_and_allocs_dont_alias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = global_addr @sil_global1 : $*Builtin.Int32
// CHECK-NEXT: %1 = alloc_ref $X
// CHECK-NEXT: NoAlias
sil @globals_and_allocs_dont_alias : $@convention(thin) () -> () {
%0 = global_addr @sil_global1 : $*Builtin.Int32
%1 = alloc_ref $X
%4 = tuple()
return %4 : $()
}
sil_global @sil_global3 : $Int32
// CHECK-LABEL: @globals_alias
// CHECK: PAIR #0.
// CHECK-NEXT: %0 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: %0 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: MustAlias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: %1 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: MustAlias
// CHECK: PAIR #2.
// CHECK-NEXT: %0 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: %2 = struct_element_addr %1 : $*Int32, #Int32._value
// CHECK-NEXT: PartialAlias
sil @globals_alias : $@convention(thin) () -> () {
%0 = global_addr @sil_global3 : $*Int32
%1 = global_addr @sil_global3 : $*Int32
%2 = struct_element_addr %1 : $*Int32, #Int32._value
%4 = tuple()
return %4 : $()
}
class HalfOpenRange {
final var current: Int32
final let end: Int32
init(start: Int32, end: Int32)
}
// CHECK-LABEL: @different_fields
// CHECK: PAIR #51.
// CHECK-NEXT: %5 = ref_element_addr %4 : $HalfOpenRange, #HalfOpenRange.current
// CHECK-NEXT: %7 = ref_element_addr %4 : $HalfOpenRange, #HalfOpenRange.end
// CHECK-NEXT: NoAlias
// CHECK: PAIR #64.
// CHECK-NEXT: %9 = struct_element_addr %5 : $*Int32, #Int32._value
// CHECK-NEXT: %10 = struct_element_addr %7 : $*Int32, #Int32._value
// CHECK-NEXT: NoAlias
sil @different_fields : $@convention(thin) () -> () {
%0 = integer_literal $Builtin.Int32, 0
%1 = struct $Int32 (%0 : $Builtin.Int32)
%2 = integer_literal $Builtin.Int32, 10
%3 = struct $Int32 (%2 : $Builtin.Int32)
%4 = alloc_ref $HalfOpenRange
%5 = ref_element_addr %4 : $HalfOpenRange, #HalfOpenRange.current
store %1 to %5 : $*Int32
%7 = ref_element_addr %4 : $HalfOpenRange, #HalfOpenRange.end
store %3 to %7 : $*Int32
%9 = struct_element_addr %5 : $*Int32, #Int32._value
%10 = struct_element_addr %7 : $*Int32, #Int32._value
%11 = load %9 : $*Builtin.Int32
%12 = load %10 : $*Builtin.Int32
%13 = tuple()
return %13 : $()
}
public final class C {
@sil_stored final var a: Int { get set }
@sil_stored final var b: Int { get set }
deinit
init()
}
// CHECK-LABEL: @ref_element_addr_and_object_itself
// CHECK: PAIR #0.
// CHECK-NEXT: %0 = alloc_ref $C{{.*}} // user: %1
// CHECK-NEXT: %0 = alloc_ref $C{{.*}} // user: %1
// CHECK-NEXT: MustAlias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = alloc_ref $C{{.*}} // user: %1
// CHECK-NEXT: %1 = ref_element_addr %0 : $C, #C.a
// CHECK-NEXT: PartialAlias
sil @ref_element_addr_and_object_itself : $@convention(thin) () -> () {
bb0:
%0 = alloc_ref $C
%1 = ref_element_addr %0 : $C, #C.a
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: @different_fields_of_different_refs
// CHECK: PAIR #13.
// CHECK-NEXT: %3 = ref_element_addr %0 : $C, #C.a
// CHECK-NEXT: %4 = ref_element_addr %1 : $C, #C.b
// CHECK-NEXT: NoAlias
sil @different_fields_of_different_refs : $@convention(thin) (@owned C, @owned C, Int) -> Int {
bb0(%0 : $C, %1 : $C, %2 : $Int):
%6 = ref_element_addr %0 : $C, #C.a
%8 = ref_element_addr %1 : $C, #C.b
return %2 : $Int
}
// CHECK-LABEL: @non_escaping_local_object_does_not_alias_with_unknown
// CHECK: PAIR #7.
// CHECK-NEXT: %1 = alloc_ref $X{{.*}} // user: %3
// CHECK-NEXT: %3 = apply %2(%1) : $@convention(thin) (X) -> X
// CHECK-NEXT: NoAlias
sil @non_escaping_local_object_does_not_alias_with_unknown : $@convention(thin) (X) -> () {
bb0(%0 : $X):
%1 = alloc_ref $X
%f = function_ref @not_escaping : $@convention(thin) (X) -> X
%2 = apply %f(%1) : $@convention(thin) (X) -> X
%12 = tuple()
return %12 : $()
}
sil @not_escaping: $@convention(thin) (X) -> X {
bb0(%0 : $X):
%1 = alloc_ref $X
return %1 : $X
}
// CHECK-LABEL: @alloc_stack_and_addr_cast
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = alloc_stack $C{{.*}} // users: %2, %1
// CHECK-NEXT: %1 = unchecked_addr_cast %0 : $*C to $*Optional<C>
// CHECK-NEXT: MayAlias
sil @alloc_stack_and_addr_cast : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $C
%1 = unchecked_addr_cast %0 : $*C to $*Optional<C>
dealloc_stack %0 : $*C
%2 = tuple()
return %2 : $()
}