blob: 6557725bf8a32c8bf88acac4e10c51d0c5431719 [file] [log] [blame]
// RUN: %target-sil-opt %s -accessed-storage-dump -enable-accessed-storage-dump-uses -enable-sil-verify-all -o /dev/null | %FileCheck %s
// RUN: %target-sil-opt %s -access-path-verification -o /dev/null
// REQUIRES: PTRSIZE=64
sil_stage canonical
import Builtin
import Swift
import SwiftShims
struct MyStruct {
@_hasStorage @_hasInitialValue var i: Int64 { get set }
@_hasStorage @_hasInitialValue var j: Int64 { get set }
}
// CHECK-LABEL: @testInnerUse
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Inner Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK: }
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Path: (#0)
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: Inner Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK: }
sil [serialized] [ossa] @testInnerUse : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%2 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*MyStruct
%3 = load [trivial] %2 : $*MyStruct
%4 = struct_element_addr %2 : $*MyStruct, #MyStruct.i
%5 = load [trivial] %4 : $*Int64
%6 = tuple ()
return %6 : $()
}
// unknown offset contains subobject indices
// CHECK-LABEL: @testDynamicIndexWithSubObject
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK: Path: (#0)
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: Inner Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK: Path: (@Unknown)
// CHECK-NEXT: Exact Uses {
// CHECK-NEXT: }
// CHECK-NEXT: Inner Uses {
// CHECK-NEXT: }
// CHECK-NEXT: Overlapping Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %3 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
sil [serialized] [ossa] @testDynamicIndexWithSubObject : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%2 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*MyStruct
%3 = struct_element_addr %2 : $*MyStruct, #MyStruct.i
%4 = load [trivial] %3 : $*Int64
%5 = index_addr %2 : $*MyStruct, %1 : $Builtin.Word
%6 = load [trivial] %5 : $*MyStruct
%7 = tuple ()
return %7 : $()
}
// The index load should be reported as an overlapping uses, not an
// exact or inner use.
// CHECK: ###For MemOp: %3 = load [trivial] %2 : $*MyStruct
// CHECK: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Base: %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK-NEXT: Inner Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK-NEXT: Overlapping Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK-NEXT: Path: INVALID
// CHECK-NEXT: }
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*Int64
// CHECK: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: INVALID
sil [serialized] [ossa] @testDynamicIndexInsideSubObject : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%2 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*MyStruct
%3 = load [trivial] %2 : $*MyStruct
%4 = struct_element_addr %2 : $*MyStruct, #MyStruct.i
%5 = index_addr %4 : $*Int64, %1 : $Builtin.Word
%6 = load [trivial] %5 : $*Int64
%7 = tuple ()
return %7 : $()
}
// An unknown offset contains known offsets.
// CHECK-LABEL: @testDynamicIndexWithStaticIndex
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK: Path: (@1)
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@1)
// CHECK-NEXT: }
// CHECK: Inner Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@1)
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@1)
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK: Path: (@Unknown)
// CHECK: Exact Uses {
// CHECK-NEXT: }
// CHECK: Inner Uses {
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@1)
// CHECK-NEXT: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
sil [serialized] [ossa] @testDynamicIndexWithStaticIndex : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%2 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*MyStruct
%3 = integer_literal $Builtin.Word, 1
%4 = index_addr %2 : $*MyStruct, %3 : $Builtin.Word
%5 = load [trivial] %4 : $*MyStruct
%6 = index_addr %2 : $*MyStruct, %1 : $Builtin.Word
%7 = load [trivial] %6 : $*MyStruct
%8 = tuple ()
return %8 : $()
}
// Even though the static offset does not match the first load, the
// dynamic offset should cancel it.
// CHECK-LABEL: @testChainedStaticDynamicIndex
// CHECK: ###For MemOp: %3 = load [trivial] %2 : $*MyStruct
// CHECK: Exact Uses {
// CHECK-NEXT: %3 = load [trivial] %2 : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load [trivial] %2 : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %8 = load [trivial] %7 : $*MyStruct
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: %6 = load [trivial] %5 : $*MyStruct
// CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Path: (@1)
// CHECK: Exact Uses {
// CHECK-NEXT: %6 = load [trivial] %5 : $*MyStruct
// CHECK-NEXT: Path: (@1)
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %6 = load [trivial] %5 : $*MyStruct
// CHECK-NEXT: Path: (@1)
// CHECK-NEXT: %8 = load [trivial] %7 : $*MyStruct
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: %8 = load [trivial] %7 : $*MyStruct
// CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Path: (@Unknown)
// CHECK: Exact Uses {
// CHECK-NEXT: }
// CHECK: Inner Uses {
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load [trivial] %2 : $*MyStruct
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %6 = load [trivial] %5 : $*MyStruct
// CHECK-NEXT: Path: (@1)
// CHECK-NEXT: %8 = load [trivial] %7 : $*MyStruct
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
sil [serialized] [ossa] @testChainedStaticDynamicIndex : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%2 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*MyStruct
%3 = load [trivial] %2 : $*MyStruct
%4 = integer_literal $Builtin.Word, 1
%5 = index_addr %2 : $*MyStruct, %4 : $Builtin.Word
%6 = load [trivial] %5 : $*MyStruct
%7 = index_addr %5 : $*MyStruct, %1 : $Builtin.Word
%8 = load [trivial] %7 : $*MyStruct
%9 = tuple ()
return %9 : $()
}
// Static indices cancel.
// Unknown offset overlaps with subobject projections.
//
// CHECK-LABEL: @staticIndexAddrCancel
// CHECK: ###For MemOp: %3 = load [trivial] %2 : $*Int64
// CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Path: (#0)
// CHECK: Exact Uses {
// CHECK-NEXT: %3 = load [trivial] %2 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: %9 = load [trivial] %8 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load [trivial] %2 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: %9 = load [trivial] %8 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: ###For MemOp: %9 = load [trivial] %8 : $*Int64
// CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer
// CHECK: Path: (#0)
// CHECK: Exact Uses {
// CHECK-NEXT: %3 = load [trivial] %2 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: %9 = load [trivial] %8 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load [trivial] %2 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: %9 = load [trivial] %8 : $*Int64
// CHECK-NEXT: Path: (#0)
// CHECK-NEXT: }
sil [ossa] @staticIndexAddrCancel : $@convention(thin) (Builtin.RawPointer) -> () {
bb0(%0 : $Builtin.RawPointer):
%1 = pointer_to_address %0 : $Builtin.RawPointer to $*MyStruct
%2 = struct_element_addr %1 : $*MyStruct, #MyStruct.i
%3 = load [trivial] %2 : $*Int64
%4 = integer_literal $Builtin.Word, 1
%5 = index_addr %1 : $*MyStruct, %4 : $Builtin.Word
%6 = integer_literal $Builtin.Word, -1
%7 = index_addr %5 : $*MyStruct, %6 : $Builtin.Word
%8 = struct_element_addr %7 : $*MyStruct, #MyStruct.i
%9 = load [trivial] %8 : $*Int64
%99 = tuple ()
return %99 : $()
}
// Increment an indexable address by one in a loop, with subobject
// uses inside and outside the loop.
//
// CHECK-LABEL: @testIndexLoop
// CHECK: ###For MemOp: %3 = load %2 : $*AnyObject
// CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: %3 = load %2 : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load %2 : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %7 = load %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %10 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: cond_br undef, bb2, bb3(%12 : $Builtin.RawPointer)
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: %7 = load %6 : $*AnyObject
// CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue
// CHECK: Path: (@Unknown)
// CHECK: Exact Uses {
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load %2 : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %7 = load %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %10 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: cond_br undef, bb2, bb3(%12 : $Builtin.RawPointer)
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: store %7 to %6 : $*AnyObject
// CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue
// CHECK: Path: (@Unknown)
// CHECK: Exact Uses {
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load %2 : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %7 = load %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %10 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: cond_br undef, bb2, bb3(%12 : $Builtin.RawPointer)
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: store %7 to %10 : $*AnyObject
// CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue
// CHECK: Path: (@Unknown)
// CHECK: Exact Uses {
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load %2 : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %7 = load %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %10 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: cond_br undef, bb2, bb3(%12 : $Builtin.RawPointer)
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
// CHECK: ###For MemOp: %17 = load %16 : $*AnyObject
// CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue
// CHECK: Path: (@Unknown)
// CHECK: Exact Uses {
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %3 = load %2 : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %7 = load %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %6 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: store %7 to %10 : $*AnyObject
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: cond_br undef, bb2, bb3(%12 : $Builtin.RawPointer)
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: }
sil shared @testIndexLoop : $@convention(thin) (UnsafeMutablePointer<AnyObject>) -> AnyObject {
bb0(%0 : $UnsafeMutablePointer<AnyObject>):
%1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue
%2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*AnyObject
%3 = load %2 : $*AnyObject
br bb1(%1 : $Builtin.RawPointer)
bb1(%5 : $Builtin.RawPointer):
%6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*AnyObject
%7 = load %6 : $*AnyObject
store %7 to %6 : $*AnyObject
%9 = integer_literal $Builtin.Word, 1
%10 = index_addr %6 : $*AnyObject, %9 : $Builtin.Word
store %7 to %10 : $*AnyObject
%12 = address_to_pointer %10 : $*AnyObject to $Builtin.RawPointer
cond_br undef, bb2, bb3(%12 : $Builtin.RawPointer)
bb2:
br bb1(%12 : $Builtin.RawPointer)
bb3(%15 : $Builtin.RawPointer):
%16 = pointer_to_address %15 : $Builtin.RawPointer to [strict] $*AnyObject
%17 = load %16 : $*AnyObject
return %17 : $AnyObject
}
enum IntTEnum<T> {
indirect case int(Int)
case other(T)
var getValue: Int {get }
}
// CHECK-LABEL: @testEnumUses
// CHECK: ###For MemOp: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: Storage: Argument %0 = argument of bb0 : $*IntTEnum<T>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: debug_value_addr %0 : $*IntTEnum<T>, let, name "self", argno 1
// CHECK-NEXT: Path: ()
// CHECK-NEXT: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: debug_value_addr %0 : $*IntTEnum<T>, let, name "self", argno 1
// CHECK-NEXT: Path: ()
// CHECK-NEXT: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Storage: Stack %2 = alloc_stack $IntTEnum<T>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %8 = load [trivial] %7 : $*Int
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: destroy_addr %13 : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %8 = load [trivial] %7 : $*Int
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: destroy_addr %13 : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %2 : $*IntTEnum<T>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: ###For MemOp: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: Storage: Stack %2 = alloc_stack $IntTEnum<T>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: Overlapping Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: ###For MemOp: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: Storage: Stack %2 = alloc_stack $IntTEnum<T>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: Overlapping Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: ###For MemOp: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: Storage: Stack %2 = alloc_stack $IntTEnum<T>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: Overlapping Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: ###For MemOp: %8 = load [trivial] %7 : $*Int
// CHECK: Storage: Stack %2 = alloc_stack $IntTEnum<T>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: Overlapping Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: ###For MemOp: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: Storage: Stack %2 = alloc_stack $IntTEnum<T>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
// CHECK: Overlapping Uses {
// CHECK: copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
// CHECK: switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
// CHECK: %5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
// CHECK: %6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
// CHECK: %8 = load [trivial] %7 : $*Int
// CHECK: %13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
// CHECK: }
sil hidden [ossa] @testEnumUses : $@convention(method) <T> (@in_guaranteed IntTEnum<T>) -> Int {
bb0(%0 : $*IntTEnum<T>):
debug_value_addr %0 : $*IntTEnum<T>, let, name "self", argno 1
%2 = alloc_stack $IntTEnum<T>
copy_addr %0 to [initialization] %2 : $*IntTEnum<T>
switch_enum_addr %2 : $*IntTEnum<T>, case #IntTEnum.int!enumelt: bb1, case #IntTEnum.other!enumelt: bb2
bb1:
%5 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.int!enumelt
%6 = load [take] %5 : $*<Ï„_0_0> { var Int } <T>
%7 = project_box %6 : $<Ï„_0_0> { var Int } <T>, 0
%8 = load [trivial] %7 : $*Int
debug_value %8 : $Int, let, name "x"
destroy_value %6 : $<Ï„_0_0> { var Int } <T>
dealloc_stack %2 : $*IntTEnum<T>
br bb3(%8 : $Int)
bb2:
%13 = unchecked_take_enum_data_addr %2 : $*IntTEnum<T>, #IntTEnum.other!enumelt
%14 = integer_literal $Builtin.Int64, 0
%15 = struct $Int (%14 : $Builtin.Int64)
destroy_addr %13 : $*T
dealloc_stack %2 : $*IntTEnum<T>
br bb3(%15 : $Int)
bb3(%19 : $Int):
return %19 : $Int
}
class Storage {}
// Test that tail_addr is always an unknown offset.
//
// CHECK-LABEL: @inlinedArrayProp
// CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*Int
// CHECK: Tail %0 = argument of bb0 : $Storage
// CHECK: Base: %{{.*}} = ref_tail_addr %0 : $Storage, $UInt
// CHECK: Storage: Tail %0 = argument of bb0 : $Storage
// CHECK: Path: (@Unknown)
// CHECK: Exact Uses {
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: %8 = load [trivial] %7 : $*Int
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: end_access %7 : $*Int
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: end_access %5 : $*Int
// CHECK-NEXT: Path: (@Unknown)
// CHECK-NEXT: end_access %2 : $*UInt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
sil hidden [ossa] @inlinedArrayProp : $@convention(thin) (@guaranteed Storage) -> Int {
bb0(%0 : @guaranteed $Storage):
%1 = ref_tail_addr %0 : $Storage, $UInt
%2 = begin_access [read] [static] %1 : $*UInt
%3 = integer_literal $Builtin.Word, 1
%4 = tail_addr %2 : $*UInt, %3 : $Builtin.Word, $Int
%5 = begin_access [read] [static] %4 : $*Int
%6 = index_addr %5 : $*Int, %3 : $Builtin.Word
%7 = begin_access [read] [static] %6 : $*Int
%8 = load [trivial] %7 : $*Int
end_access %7 : $*Int
end_access %5 : $*Int
end_access %2 : $*UInt
return %8 : $Int
}
// CHECK-LABEL: @testBeginAccessUses
// CHECK: ###For MemOp: copy_addr [take] %1 to [initialization] %{{.*}} : $*T
// CHECK: Storage: Argument %1 = argument of bb0 : $*T
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: copy_addr [take] %1 to [initialization] %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: copy_addr [take] %1 to [initialization] %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Storage: Stack %{{.*}} = alloc_stack $T, var, name "$value"
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: copy_addr [take] %1 to [initialization] %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: copy_addr %{{.*}} to [initialization] %0 : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: end_access %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: destroy_addr %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: copy_addr [take] %1 to [initialization] %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: copy_addr %{{.*}} to [initialization] %0 : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: end_access %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: destroy_addr %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: ###For MemOp: copy_addr %{{.*}} to [initialization] %0 : $*T
// CHECK: Storage: Stack %{{.*}} = alloc_stack $T, var, name "$value"
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: copy_addr [take] %1 to [initialization] %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: copy_addr %{{.*}} to [initialization] %0 : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: end_access %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: destroy_addr %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: copy_addr [take] %1 to [initialization] %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: copy_addr %{{.*}} to [initialization] %0 : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: end_access %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: destroy_addr %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %{{.*}} : $*T
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
sil [ossa] @testBeginAccessUses : $@convention(thin) <T where T : Comparable> (@in T) -> @out T {
bb0(%0 : $*T, %1 : $*T):
%2 = alloc_stack $T, var, name "$value"
copy_addr [take] %1 to [initialization] %2 : $*T
%4 = begin_access [modify] [static] %2 : $*T
copy_addr %4 to [initialization] %0 : $*T
end_access %4 : $*T
destroy_addr %2 : $*T
dealloc_stack %2 : $*T
%10 = tuple ()
return %10 : $()
}
// Test reference root casts.
class A {
var prop0: Int64
}
class B : A {
var alsoProp0: Int64
}
// CHECK-LABEL: @testReferenceRootCast
// CHECK: ###For MemOp: store %0 to [[ADR0:%.*]] : $*Int64
// CHECK: Class %{{.*}} = alloc_ref $B
// CHECK: Field: var prop0: Int64 Index: 0
// CHECK: Base: [[ADR0]] = ref_element_addr %{{.*}} : $A, #A.prop0
// CHECK: Storage: Class %1 = alloc_ref $B
// CHECK: Field: var prop0: Int64 Index: 0
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: store %0 to [[ADR0]] : $*Int64
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: store %0 to [[ADR0]] : $*Int64
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: ###For MemOp: store %0 to [[ADR1:%.*]] : $*Int64
// CHECK-NEXT: Class %{{.*}} = alloc_ref $B
// CHECK-NEXT: Field: var alsoProp0: Int64 Index: 1
// CHECK-NEXT: Base: [[ADR1]] = ref_element_addr %10 : $B, #B.alsoProp0
// CHECK-NEXT: Storage: Class %{{.*}} = alloc_ref $B
// CHECK-NEXT: Field: var alsoProp0: Int64 Index: 1
// CHECK-NEXT: Path: ()
// CHECK-NEXT: Exact Uses {
// CHECK-NEXT: store %0 to [[ADR1]] : $*Int64
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: Overlapping Uses {
// CHECK-NEXT: store %0 to [[ADR1]] : $*Int64
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
sil @testReferenceRootCast : $@convention(thin) (Int64) -> () {
bb0(%0 : $Int64):
%1 = alloc_ref $B
cond_br undef, bb1, bb2
bb1:
%3 = upcast %1 : $B to $A
br bb3(%3 : $A)
bb2:
%5 = upcast %1 : $B to $A
br bb3(%5 : $A)
bb3(%7 : $A):
%8 = ref_element_addr %7 : $A, #A.prop0
store %0 to %8 : $*Int64
%10 = unchecked_ref_cast %7 : $A to $B
%11 = ref_element_addr %10 : $B, #B.alsoProp0
store %0 to %11 : $*Int64
%99 = tuple ()
return %99 : $()
}
// Test a phi cycle where the phi itself is the root (there is no common phi reference).
// CHECK-LABEL: @testRootPhiCycle
// CHECK: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
// CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
// CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
sil @testRootPhiCycle : $@convention(thin) (Builtin.BridgeObject, Builtin.BridgeObject) -> () {
bb0(%0 : $Builtin.BridgeObject, %1 : $Builtin.BridgeObject):
cond_br undef, bb1, bb2
bb1:
br bb3(%0 : $Builtin.BridgeObject)
bb2:
br bb3(%1 : $Builtin.BridgeObject)
bb3(%820 : $Builtin.BridgeObject):
%834 = unchecked_ref_cast %820 : $Builtin.BridgeObject to $C
%844 = ref_tail_addr [immutable] %834 : $C, $Double
%853 = load %844 : $*Double
%943 = load %844 : $*Double
cond_br undef, bb4, bb5
bb4:
br bb3(%820 : $Builtin.BridgeObject)
bb5:
%999 = tuple ()
return %999 : $()
}
class C {}
// Test a CoW mutation followed by a phi cycle.
//
// Note: FindReferenceRoot currently does not see past CoW mutation,
// but probably should.
// CHECK: @testCowMutationPhi
// CHECK: ###For MemOp: (%{{.*}}, %{{.*}}) = begin_cow_mutation [native] %0 : $Builtin.BridgeObject
// CHECK-NEXT: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
// CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
// CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
sil @testCowMutationPhi : $@convention(thin) (Builtin.BridgeObject) -> () {
bb0(%0 : $Builtin.BridgeObject):
cond_br undef, bb1, bb2
bb1:
br bb3(%0 : $Builtin.BridgeObject)
bb2:
(%3, %4) = begin_cow_mutation [native] %0 : $Builtin.BridgeObject
%5 = end_cow_mutation [keep_unique] %4 : $Builtin.BridgeObject
br bb3(%5 : $Builtin.BridgeObject)
bb3(%820 : $Builtin.BridgeObject):
%834 = unchecked_ref_cast %820 : $Builtin.BridgeObject to $C
%844 = ref_tail_addr [immutable] %834 : $C, $Double
%853 = load %844 : $*Double
%943 = load %844 : $*Double
cond_br undef, bb4, bb5
bb4:
br bb3(%820 : $Builtin.BridgeObject)
bb5:
%999 = tuple ()
return %999 : $()
}
// CHECK-LABEL: @test_init_enum_addr
// CHECK: ###For MemOp: store %0 to [init] %2 : $*AnyObject
// CHECK: Stack %1 = alloc_stack $Optional<AnyObject>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: store %0 to [init] %{{.*}} : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: inject_enum_addr %1 : $*Optional<AnyObject>, #Optional.some!enumelt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load [copy] %1 : $*Optional<AnyObject>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %1 : $*Optional<AnyObject>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: ###For MemOp: inject_enum_addr %1 : $*Optional<AnyObject>, #Optional.some!enumelt
// CHECK: Stack %1 = alloc_stack $Optional<AnyObject>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: store %0 to [init] %{{.*}} : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: inject_enum_addr %1 : $*Optional<AnyObject>, #Optional.some!enumelt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load [copy] %1 : $*Optional<AnyObject>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %1 : $*Optional<AnyObject>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
// CHECK: ###For MemOp: %5 = load [copy] %1 : $*Optional<AnyObject>
// CHECK: Stack %1 = alloc_stack $Optional<AnyObject>
// CHECK: Path: ()
// CHECK: Exact Uses {
// CHECK-NEXT: store %0 to [init] %{{.*}} : $*AnyObject
// CHECK-NEXT: Path: ()
// CHECK-NEXT: inject_enum_addr %1 : $*Optional<AnyObject>, #Optional.some!enumelt
// CHECK-NEXT: Path: ()
// CHECK-NEXT: %{{.*}} = load [copy] %1 : $*Optional<AnyObject>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: dealloc_stack %1 : $*Optional<AnyObject>
// CHECK-NEXT: Path: ()
// CHECK-NEXT: }
sil [ossa] @test_init_enum_addr : $@convention(thin) (@owned AnyObject) -> @owned Optional<AnyObject> {
bb0(%0 : @owned $AnyObject):
%1 = alloc_stack $Optional<AnyObject>
%2 = init_enum_data_addr %1 : $*Optional<AnyObject>, #Optional.some!enumelt
store %0 to [init] %2 : $*AnyObject
inject_enum_addr %1 : $*Optional<AnyObject>, #Optional.some!enumelt
%5 = load [copy] %1 : $*Optional<AnyObject>
dealloc_stack %1 : $*Optional<AnyObject>
return %5 : $Optional<AnyObject>
}