mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
In contrast to `ref_element_addr`, tail addresses can also be obtained via a superclass (in case the derived class doesn't add any stored properties). Therefore if the instance types differ by sub-superclass relationship, they may alias. Fixes a miscompile
748 lines
26 KiB
Plaintext
748 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 Derived: X {}
|
|
|
|
// CHECK-LABEL: @test_tail_addr_and_upcast
|
|
// CHECK: PAIR #10.
|
|
// CHECK-NEXT: %2 = ref_tail_addr %1 : $X, $Int32
|
|
// CHECK-NEXT: %3 = ref_tail_addr %0 : $Derived, $Int32
|
|
// CHECK-NEXT: MayAlias
|
|
sil @test_tail_addr_and_upcast : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_ref $Derived
|
|
%1 = upcast %0 to $X
|
|
%2 = ref_tail_addr %1, $Int32
|
|
%3 = ref_tail_addr %0, $Int32
|
|
fix_lifetime %2
|
|
fix_lifetime %3
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
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 : $()
|
|
}
|
|
|