mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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.
582 lines
21 KiB
Plaintext
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 : $()
|
|
}
|