Files
swift-mirror/test/SILOptimizer/basic-aa.sil
Erik Eckstein f9b524b1cb AliasAnalysis: a complete overhaul of alias- and memory-behavior analysis
The main changes are:

*) Rewrite everything in swift. So far, parts of memory-behavior analysis were already implemented in swift. Now everything is done in swift and lives in `AliasAnalysis.swift`. This is a big code simplification.

*) Support many more instructions in the memory-behavior analysis - especially OSSA instructions, like `begin_borrow`, `end_borrow`, `store_borrow`, `load_borrow`. The computation of end_borrow effects is now much more precise. Also, partial_apply is now handled more precisely.

*) Simplify and reduce type-based alias analysis (TBAA). The complexity of the old TBAA comes from old days where the language and SIL didn't have strict aliasing and exclusivity rules (e.g. for inout arguments). Now TBAA is only needed for code using unsafe pointers. The new TBAA handles this - and not more. Note that TBAA for classes is already done in `AccessBase.isDistinct`.

*) Handle aliasing in `begin_access [modify]` scopes. We already supported truly immutable scopes like `begin_access [read]` or `ref_element_addr [immutable]`. For `begin_access [modify]` we know that there are no other reads or writes to the access-address within the scope.

*) Don't cache memory-behavior results. It turned out that the hit-miss rate was pretty bad (~ 1:7). The overhead of the cache lookup took as long as recomputing the memory behavior.
2024-07-29 17:33:46 +02:00

729 lines
26 KiB
Plaintext

// RUN: %target-sil-opt %s -dump-alias-info -o /dev/null | %FileCheck %s
// REQUIRES: asserts
// REQUIRES: swift_in_compiler
// 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: MayAlias
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:
fix_lifetime %214 : $*Int
fix_lifetime %2114 : $*Int
%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: MayAlias
// 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):
fix_lifetime %0 : $*Builtin.NativeObject
fix_lifetime %1 : $*Builtin.NativeObject
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: @inout_args_may_not_alias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = argument of bb0
// CHECK-NEXT: %1 = argument of bb0
// CHECK-NEXT: NoAlias
sil @inout_args_may_not_alias: $@convention(thin) (@inout Builtin.NativeObject, @inout Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject, %1 : $*Builtin.NativeObject):
fix_lifetime %0 : $*Builtin.NativeObject
fix_lifetime %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: MayAlias
// 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: MayAlias
// CHECK: PAIR #3.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %3 = struct_element_addr %0 : $*StructLvl1, #StructLvl1.x
// CHECK-NEXT: MayAlias
// CHECK: PAIR #4.
// CHECK-NEXT: %0 = alloc_stack $StructLvl1
// CHECK-NEXT: %4 = struct_element_addr %2 : $*StructLvl2, #StructLvl2.tup
// CHECK-NEXT: MayAlias
// CHECK: PAIR #21.
// CHECK-NEXT: %1 = alloc_stack $StructLvl1
// CHECK-NEXT: %9 = struct_element_addr %7 : $*StructLvl2, #StructLvl2.tup
// CHECK-NEXT: MayAlias
// CHECK: PAIR #22.
// CHECK-NEXT: %1 = alloc_stack $StructLvl1
// CHECK-NEXT: %10 = tuple_element_addr %9 : $*(Builtin.Int64, Builtin.Int32), 0
// CHECK-NEXT: MayAlias
// CHECK: PAIR #23.
// CHECK-NEXT: %1 = alloc_stack $StructLvl1
// CHECK-NEXT: %11 = tuple_element_addr %9 : $*(Builtin.Int64, Builtin.Int32), 1
// CHECK-NEXT: MayAlias
// 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: MayAlias
// 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: MayAlias
// 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: MayAlias
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
fix_lifetime %2 : $*StructLvl2
fix_lifetime %3 : $*Builtin.Int64
fix_lifetime %5 : $*Builtin.Int64
fix_lifetime %6 : $*Builtin.Int32
fix_lifetime %8 : $*Builtin.Int64
fix_lifetime %10 : $*Builtin.Int64
fix_lifetime %11 : $*Builtin.Int32
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 #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
fix_lifetime %0 : $Builtin.NativeObject
fix_lifetime %1 : $Builtin.NativeObject
fix_lifetime %2 : $*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: MayAlias
// 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 #19.
// CHECK-NEXT: %1 = argument of bb0 : $Builtin.NativeObject
// CHECK-NEXT: %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
// CHECK-NEXT: NoAlias
// 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
// 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
// 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: MayAlias
// 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: NoAlias
// CHECK: PAIR #49.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> Builtin.NativeObject
// CHECK-NEXT: %9 = apply %7(%8) : $@convention(thin) (Builtin.NativeObject) -> ()
// CHECK-NEXT: NoAlias
// Test %8 (the escaping load)
// CHECK: PAIR #60.
// CHECK-NEXT: %8 = load %3 : $*Builtin.NativeObject
// CHECK-NEXT: %8 = load %3 : $*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
fix_lifetime %1 : $Builtin.NativeObject
fix_lifetime %5 : $Builtin.NativeObject
fix_lifetime %6 : $Builtin.NativeObject
fix_lifetime %9 : $()
%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: MayAlias
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
fix_lifetime %3: $*Builtin.Int32
fix_lifetime %6: $*Builtin.Int32
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: MayAlias
// 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
fix_lifetime %0 : $*Builtin.Int32
fix_lifetime %1 : $*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
fix_lifetime %0 : $*Builtin.Int32
fix_lifetime %1 : $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: MayAlias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: %1 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: MayAlias
// CHECK: PAIR #2.
// CHECK-NEXT: %0 = global_addr @sil_global3 : $*Int32
// CHECK-NEXT: %2 = struct_element_addr %1 : $*Int32, #Int32._value
// CHECK-NEXT: MayAlias
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 {
@_hasStorage final var a: Int { get set }
@_hasStorage 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{{.*}}
// CHECK-NEXT: %0 = alloc_ref $C{{.*}}
// CHECK-NEXT: MayAlias
// CHECK: PAIR #1.
// CHECK-NEXT: %0 = alloc_ref $C{{.*}}
// CHECK-NEXT: %1 = ref_element_addr %0 : $C, #C.a
// CHECK-NEXT: MayAlias
sil @ref_element_addr_and_object_itself : $@convention(thin) () -> () {
bb0:
%0 = alloc_ref $C
%1 = ref_element_addr %0 : $C, #C.a
fix_lifetime %1 : $*Int
%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
fix_lifetime %6 : $*Int
fix_lifetime %8 : $*Int
return %2 : $Int
}
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{{.*}}
// 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>
fix_lifetime %1 : $*Optional<C>
dealloc_stack %0 : $*C
%2 = tuple()
return %2 : $()
}
struct TwoInts {
var a: Int
var b: Int
}
struct StructWithOptional {
var i: Optional<TwoInts>
}
// CHECK-LABEL: @init_enum_data_addr
// CHECK: PAIR #3.
// CHECK-NEXT: %0 = argument of bb0 : $*StructWithOptional
// CHECK-NEXT: %3 = init_enum_data_addr %2 : $*Optional<TwoInts>, #Optional.some!enumelt
// CHECK-NEXT: NoAlias
// CHECK: PAIR #4.
// CHECK-NEXT: %0 = argument of bb0 : $*StructWithOptional
// CHECK-NEXT: %4 = struct_element_addr %3 : $*TwoInts, #TwoInts.a
// CHECK-NEXT: NoAlias
// CHECK: PAIR #5.
// CHECK-NEXT: %0 = argument of bb0 : $*StructWithOptional
// CHECK-NEXT: %5 = struct_element_addr %3 : $*TwoInts, #TwoInts.b
// CHECK-NEXT: NoAlias
// CHECK: PAIR #14.
// CHECK-NEXT: %2 = struct_element_addr %1 : $*StructWithOptional, #StructWithOptional.i
// CHECK-NEXT: %3 = init_enum_data_addr %2 : $*Optional<TwoInts>, #Optional.some!enumelt
// CHECK-NEXT: MayAlias
// CHECK: PAIR #15.
// CHECK-NEXT: %2 = struct_element_addr %1 : $*StructWithOptional, #StructWithOptional.i
// CHECK-NEXT: %4 = struct_element_addr %3 : $*TwoInts, #TwoInts.a
// CHECK-NEXT: MayAlias
// CHECK: PAIR #16.
// CHECK-NEXT: %2 = struct_element_addr %1 : $*StructWithOptional, #StructWithOptional.i
// CHECK-NEXT: %5 = struct_element_addr %3 : $*TwoInts, #TwoInts.b
// CHECK-NEXT: MayAlias
// CHECK: PAIR #19.
// CHECK-NEXT: %3 = init_enum_data_addr %2 : $*Optional<TwoInts>, #Optional.some!enumelt
// CHECK-NEXT: %4 = struct_element_addr %3 : $*TwoInts, #TwoInts.a
// CHECK-NEXT: MayAlias
// CHECK: PAIR #20.
// CHECK-NEXT: %3 = init_enum_data_addr %2 : $*Optional<TwoInts>, #Optional.some!enumelt
// CHECK-NEXT: %5 = struct_element_addr %3 : $*TwoInts, #TwoInts.b
// CHECK-NEXT: MayAlias
// CHECK: PAIR #23.
// CHECK-NEXT: %4 = struct_element_addr %3 : $*TwoInts, #TwoInts.a
// CHECK-NEXT: %5 = struct_element_addr %3 : $*TwoInts, #TwoInts.b
// CHECK-NEXT: NoAlias
sil @init_enum_data_addr : $@convention(thin) (@in_guaranteed StructWithOptional) -> () {
bb0(%0 : $*StructWithOptional):
%1 = alloc_stack $StructWithOptional
%2 = struct_element_addr %1 : $*StructWithOptional, #StructWithOptional.i
%3 = init_enum_data_addr %2 : $*Optional<TwoInts>, #Optional.some!enumelt
%4 = struct_element_addr %3 : $*TwoInts, #TwoInts.a
%5 = struct_element_addr %3 : $*TwoInts, #TwoInts.b
fix_lifetime %0 : $*StructWithOptional
fix_lifetime %4 : $*Int
fix_lifetime %5 : $*Int
dealloc_stack %1 : $*StructWithOptional
%6 = tuple ()
return %6 : $()
}
protocol P {}
struct S : P {
var i: Int
}
// CHECK-LABEL: @init_existential_addr
// CHECK: PAIR #3.
// CHECK-NEXT: %0 = argument of bb0 : $any P
// CHECK-NEXT: %3 = init_existential_addr %2 : $*any P, $S
// CHECK-NEXT: NoAlias
// CHECK: PAIR #12.
// CHECK-NEXT: %2 = alloc_stack $any P
// CHECK-NEXT: %3 = init_existential_addr %2 : $*any P, $S
// CHECK-NEXT: MayAlias
// CHECK: PAIR #13.
// CHECK-NEXT: %2 = alloc_stack $any P
// CHECK-NEXT: %4 = struct_element_addr %3 : $*S, #S.i
// CHECK-NEXT: MayAlias
// CHECK: PAIR #16.
// CHECK-NEXT: %3 = init_existential_addr %2 : $*any P, $S
// CHECK-NEXT: %4 = struct_element_addr %3 : $*S, #S.i
// CHECK-NEXT: MayAlias
sil @init_existential_addr : $@convention(thin) (P) -> () {
bb0(%0 : $P):
%1 = alloc_stack $S
%2 = alloc_stack $P
%3 = init_existential_addr %2 : $*P, $S
%4 = struct_element_addr %3 : $*S, #S.i
fix_lifetime %0 : $P
fix_lifetime %4 : $*Int
dealloc_stack %2 : $*P
dealloc_stack %1 : $*S
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: @testCowMutation
// CHECK: PAIR #23.
// CHECK-NEXT: %4 = ref_tail_addr %0 : $X, $Int32
// CHECK-NEXT: %5 = ref_tail_addr %3 : $X, $Int32
// CHECK-NEXT: MayAlias
sil @testCowMutation : $@convention(thin) () -> () {
bb0:
%0 = alloc_ref $X
(%1, %2) = begin_cow_mutation %0 : $X
%3 = end_cow_mutation %2 : $X
%4 = ref_tail_addr %0 : $X, $Int32
%5 = ref_tail_addr %3 : $X, $Int32
fix_lifetime %4 : $*Int32
fix_lifetime %5 : $*Int32
%99 = tuple ()
return %99 : $()
}
class GenericClass<T> {
var x : T
}
// CHECK-LABEL: @test_generic_class
// CHECK: PAIR #10.
// CHECK-NEXT: %2 = ref_element_addr %0 : $GenericClass<T>, #GenericClass.x
// CHECK-NEXT: %3 = ref_element_addr %1 : $GenericClass<Int>, #GenericClass.x
// CHECK-NEXT: MayAlias
sil [ossa] @test_generic_class : $@convention(thin) <T> (@guaranteed GenericClass<T>, @guaranteed GenericClass<Int>) -> () {
bb0(%0 : @guaranteed $GenericClass<T>, %1 : @guaranteed $GenericClass<Int>):
%2 = ref_element_addr %0 : $GenericClass<T>, #GenericClass.x
%3 = ref_element_addr %1 : $GenericClass<Int>, #GenericClass.x
fix_lifetime %2 : $*T
fix_lifetime %3 : $*Int
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: @test_bound_generic_class
// CHECK: PAIR #10.
// CHECK-NEXT: %2 = ref_element_addr %0 : $GenericClass<Int32>, #GenericClass.x
// CHECK-NEXT: %3 = ref_element_addr %1 : $GenericClass<Int>, #GenericClass.x
// CHECK-NEXT: NoAlias
sil [ossa] @test_bound_generic_class : $@convention(thin) (@guaranteed GenericClass<Int32>, @guaranteed GenericClass<Int>) -> () {
bb0(%0 : @guaranteed $GenericClass<Int32>, %1 : @guaranteed $GenericClass<Int>):
%2 = ref_element_addr %0 : $GenericClass<Int32>, #GenericClass.x
%3 = ref_element_addr %1 : $GenericClass<Int>, #GenericClass.x
fix_lifetime %2 : $*Int32
fix_lifetime %3 : $*Int
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: @test_store_borrow
// CHECK: PAIR #7.
// CHECK-NEXT: %1 = alloc_stack $X
// CHECK-NEXT: %2 = store_borrow %0 to %1 : $*X
// CHECK-NEXT: MayAlias
// CHECK: PAIR #13.
// CHECK-NEXT: %2 = store_borrow %0 to %1 : $*X
// CHECK-NEXT: %4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*X
// CHECK-NEXT: MayAlias
sil [ossa] @test_store_borrow : $@convention(thin) (@guaranteed X) -> () {
bb0(%0 : @guaranteed $X):
%1 = alloc_stack $X
%2 = store_borrow %0 to %1 : $*X
%3 = address_to_pointer %2 : $*X to $Builtin.RawPointer
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*X
fix_lifetime %4 : $*X
end_borrow %2 : $*X
dealloc_stack %1 : $*X
%7 = tuple ()
return %7 : $()
}