| // RUN: %target-sil-opt %s -accessed-storage-dump -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: @testStructPhiCommon |
| // CHECK: store |
| // CHECK: Argument %0 = argument of bb0 : $*MyStruct |
| // CHECK: Base: %0 = argument of bb0 : $*MyStruct |
| // CHECK: Storage: Argument %0 = argument of bb0 : $*MyStruct |
| // CHECK: Path: (#0) |
| sil hidden @testStructPhiCommon : $@convention(thin) (@inout MyStruct) -> () { |
| bb0(%0 : $*MyStruct): |
| %2 = struct_element_addr %0 : $*MyStruct, #MyStruct.i |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %3 = address_to_pointer %2 : $*Int64 to $Builtin.RawPointer |
| br bb3(%3 : $Builtin.RawPointer) |
| |
| bb2: |
| %5 = address_to_pointer %2 : $*Int64 to $Builtin.RawPointer |
| br bb3(%5 : $Builtin.RawPointer) |
| |
| bb3(%6 : $Builtin.RawPointer) : |
| %7 = pointer_to_address %6 : $Builtin.RawPointer to $*Int64 |
| %8 = integer_literal $Builtin.Int64, 2 |
| %9 = struct $Int64 (%8 : $Builtin.Int64) |
| store %9 to %7 : $*Int64 |
| %22 = tuple () |
| return %22 : $() |
| } |
| |
| // A pointer phi leading to different access paths should be |
| // considered illegal, but we don't have a way to verify it yet. |
| // |
| // CHECK-LABEL: @testStructPhiDivergent |
| // CHECK: store |
| // CHECK: INVALID |
| // CHECK: INVALID |
| sil hidden @testStructPhiDivergent : $@convention(thin) (@inout MyStruct) -> () { |
| bb0(%0 : $*MyStruct): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %2 = struct_element_addr %0 : $*MyStruct, #MyStruct.i |
| %3 = address_to_pointer %2 : $*Int64 to $Builtin.RawPointer |
| br bb3(%3 : $Builtin.RawPointer) |
| |
| bb2: |
| %4 = struct_element_addr %0 : $*MyStruct, #MyStruct.j |
| %5 = address_to_pointer %4 : $*Int64 to $Builtin.RawPointer |
| br bb3(%5 : $Builtin.RawPointer) |
| |
| bb3(%6 : $Builtin.RawPointer) : |
| %7 = pointer_to_address %6 : $Builtin.RawPointer to $*Int64 |
| %8 = integer_literal $Builtin.Int64, 2 |
| %9 = struct $Int64 (%8 : $Builtin.Int64) |
| store %9 to %7 : $*Int64 |
| %22 = tuple () |
| return %22 : $() |
| } |
| |
| // Test FindPhiStorageVisitor with a combination of |
| // - valid storage for address_to_pointer %1 |
| // - invalid common definition between #MyStruct.i and #MyStruct.j |
| // |
| // Make sure that visiting the invalid common definition also |
| // invalidates storage. |
| // |
| // CHECK-LABEL: @testStructPhiChained |
| // CHECK: store |
| // CHECK: INVALID |
| // CHECK: INVALID |
| sil hidden @testStructPhiChained : $@convention(thin) (@inout MyStruct, @inout Int64) -> () { |
| bb0(%0 : $*MyStruct, %1 : $*Int64): |
| cond_br undef, bb1, bb5 |
| |
| bb1: |
| cond_br undef, bb2, bb3 |
| |
| bb2: |
| %2 = address_to_pointer %1 : $*Int64 to $Builtin.RawPointer |
| br bb4(%2 : $Builtin.RawPointer) |
| |
| bb3: |
| %3 = struct_element_addr %0 : $*MyStruct, #MyStruct.i |
| %4 = address_to_pointer %3 : $*Int64 to $Builtin.RawPointer |
| br bb4(%4 : $Builtin.RawPointer) |
| |
| bb4(%6 : $Builtin.RawPointer) : |
| br bb6(%6 : $Builtin.RawPointer) |
| |
| bb5: |
| %7 = struct_element_addr %0 : $*MyStruct, #MyStruct.j |
| %8 = address_to_pointer %7 : $*Int64 to $Builtin.RawPointer |
| br bb6(%8 : $Builtin.RawPointer) |
| |
| bb6(%9 : $Builtin.RawPointer) : |
| %10 = pointer_to_address %9 : $Builtin.RawPointer to $*Int64 |
| %11 = integer_literal $Builtin.Int64, 2 |
| %12 = struct $Int64 (%11 : $Builtin.Int64) |
| store %12 to %10 : $*Int64 |
| %22 = tuple () |
| return %22 : $() |
| } |
| |
| struct _MyBridgeStorage { |
| @_hasStorage var rawValue : Builtin.BridgeObject |
| } |
| |
| struct _MyArrayBuffer<T> { |
| @_hasStorage var _storage : _MyBridgeStorage |
| } |
| |
| |
| struct MyArray<T> { |
| @_hasStorage var _buffer : _MyArrayBuffer<T> |
| } |
| |
| // CHECK-LABEL: @arrayValue |
| // CHECK: load [trivial] %{{.*}} : $*Builtin.Int64 |
| // CHECK: Tail %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Base: %{{.*}} = ref_tail_addr [immutable] %{{.*}} : $__ContiguousArrayStorageBase, $Int64 |
| // CHECK: Storage: Tail %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Path: (@3,#0) |
| // CHECK: load [trivial] %{{.*}} : $*Builtin.Int64 |
| // CHECK: Tail %{{.*}} = struct_extract %5 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Base: %{{.*}} = ref_tail_addr [immutable] %{{.*}} : $__ContiguousArrayStorageBase, $Int64 |
| // CHECK: Storage: Tail %{{.*}} = struct_extract %5 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Path: (@4,#0) |
| sil [ossa] @arrayValue : $@convention(thin) (@guaranteed MyArray<Int64>) -> Int64 { |
| bb0(%0 : @guaranteed $MyArray<Int64>): |
| %1 = integer_literal $Builtin.Word, 3 |
| %2 = integer_literal $Builtin.Word, 4 |
| %3 = integer_literal $Builtin.Int1, -1 |
| %4 = struct_extract %0 : $MyArray<Int64>, #MyArray._buffer |
| %5 = struct_extract %4 : $_MyArrayBuffer<Int64>, #_MyArrayBuffer._storage |
| %6 = struct_extract %5 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| %7 = unchecked_ref_cast %6 : $Builtin.BridgeObject to $__ContiguousArrayStorageBase |
| %8 = ref_tail_addr [immutable] %7 : $__ContiguousArrayStorageBase, $Int64 |
| %9 = index_addr %8 : $*Int64, %1 : $Builtin.Word |
| %10 = struct_element_addr %9 : $*Int64, #Int64._value |
| %11 = load [trivial] %10 : $*Builtin.Int64 |
| %12 = index_addr %8 : $*Int64, %2 : $Builtin.Word |
| %13 = struct_element_addr %12 : $*Int64, #Int64._value |
| %14 = load [trivial] %13 : $*Builtin.Int64 |
| %15 = builtin "sadd_with_overflow_Int64"(%11 : $Builtin.Int64, %14 : $Builtin.Int64, %3 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) |
| %16 = tuple_extract %15 : $(Builtin.Int64, Builtin.Int1), 0 |
| %17 = tuple_extract %15 : $(Builtin.Int64, Builtin.Int1), 1 |
| cond_fail %17 : $Builtin.Int1, "arithmetic overflow" |
| %19 = struct $Int64 (%16 : $Builtin.Int64) |
| return %19 : $Int64 |
| } |
| |
| // CHECK-LABEL: @staticIndexAddrChain |
| // CHECK: %{{.*}} = load [trivial] %{{.*}} : $*Int64 |
| // 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: (@1,#0) |
| // CHECK: %{{.*}} = load [trivial] %{{.*}} : $*Int64 |
| // CHECK: Argument %{{.*}} = argument of bb0 : $Builtin.RawPointer |
| // CHECK: Base: %0 = argument of bb0 : $Builtin.RawPointer |
| // CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer |
| // CHECK: Path: (@2,#0) |
| sil [ossa] @staticIndexAddrChain : $@convention(thin) (Builtin.RawPointer) -> () { |
| bb0(%0 : $Builtin.RawPointer): |
| %1 = pointer_to_address %0 : $Builtin.RawPointer to $*MyStruct |
| %2 = integer_literal $Builtin.Word, 1 |
| %3 = index_addr %1 : $*MyStruct, %2 : $Builtin.Word |
| %4 = struct_element_addr %3 : $*MyStruct, #MyStruct.i |
| %5 = load [trivial] %4 : $*Int64 |
| %6 = index_addr %3 : $*MyStruct, %2 : $Builtin.Word |
| %7 = struct_element_addr %6 : $*MyStruct, #MyStruct.i |
| %8 = load [trivial] %7 : $*Int64 |
| %99 = tuple () |
| return %99 : $() |
| } |
| |
| // CHECK-LABEL: @staticIndexAddrSubobject |
| // CHECK: ###For MemOp: %5 = load [trivial] %4 : $*Int64 |
| // CHECK: Argument %0 = argument of bb0 : $Builtin.RawPointer |
| // CHECK: INVALID |
| sil [ossa] @staticIndexAddrSubobject : $@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 = integer_literal $Builtin.Word, 1 |
| %4 = index_addr %2 : $*Int64, %3 : $Builtin.Word |
| %5 = load [trivial] %4 : $*Int64 |
| %99 = tuple () |
| return %99 : $() |
| } |
| |
| // CHECK-LABEL: @dynamicIndexAddrChain |
| // CHECK: %{{.*}} = load [trivial] %{{.*}} : $*Int64 |
| // 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: (@Unknown,#0) |
| // CHECK: %{{.*}} = load [trivial] %{{.*}} : $*Int64 |
| // 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: (@Unknown,#0) |
| sil [ossa] @dynamicIndexAddrChain : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () { |
| bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word): |
| %2 = pointer_to_address %0 : $Builtin.RawPointer to $*MyStruct |
| %3 = index_addr %2 : $*MyStruct, %1 : $Builtin.Word |
| %4 = struct_element_addr %3 : $*MyStruct, #MyStruct.i |
| %5 = load [trivial] %4 : $*Int64 |
| %6 = integer_literal $Builtin.Word, 1 |
| %7 = index_addr %3 : $*MyStruct, %6 : $Builtin.Word |
| %8 = struct_element_addr %7 : $*MyStruct, #MyStruct.i |
| %9 = load [trivial] %8 : $*Int64 |
| %99 = tuple () |
| return %99 : $() |
| } |
| |
| // CHECK-LABEL: @staticIndexAddrCancel |
| // CHECK: %{{.*}} = load [trivial] %{{.*}} : $*Int64 |
| // 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: (@1,#0) |
| // CHECK: %{{.*}} = load [trivial] %{{.*}} : $*Int64 |
| // 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: (@2,#0) |
| sil [ossa] @staticIndexAddrCancel : $@convention(thin) (Builtin.RawPointer) -> () { |
| bb0(%0 : $Builtin.RawPointer): |
| %1 = pointer_to_address %0 : $Builtin.RawPointer to $*MyStruct |
| %2 = integer_literal $Builtin.Word, 1 |
| %3 = index_addr %1 : $*MyStruct, %2 : $Builtin.Word |
| %4 = struct_element_addr %3 : $*MyStruct, #MyStruct.i |
| %5 = load [trivial] %4 : $*Int64 |
| %6 = integer_literal $Builtin.Word, -1 |
| %7 = index_addr %3 : $*MyStruct, %2 : $Builtin.Word |
| %8 = struct_element_addr %7 : $*MyStruct, #MyStruct.i |
| %9 = load [trivial] %8 : $*Int64 |
| %99 = tuple () |
| return %99 : $() |
| } |
| |
| class A { |
| var prop0: Int64 |
| } |
| class B : A { |
| var prop1: Int64 |
| } |
| |
| // CHECK-LABEL: @testNonUniquePropertyIndex |
| // CHECK: store %0 to %{{.*}} : $*Int64 |
| // CHECK: Class %{{.*}} = alloc_ref $B |
| // CHECK: Field: var prop1: Int64 Index: 1 |
| // CHECK: Base: %{{.*}} = ref_element_addr %{{.*}} : $B, #B.prop1 |
| // CHECK: Storage: Class %{{.*}} = alloc_ref $B |
| // CHECK: Field: var prop1: Int64 Index: 1 |
| // CHECK: Path: () |
| // CHECK: store %0 to %{{.*}} : $*Int64 |
| // CHECK: Class %{{.*}} = alloc_ref $B |
| // CHECK: Field: var prop0: Int64 Index: 0 |
| // CHECK: Base: %{{.*}} = ref_element_addr %{{.*}} : $A, #A.prop0 |
| // CHECK: Storage: Class %{{.*}} = alloc_ref $B |
| // CHECK: Field: var prop0: Int64 Index: 0 |
| // CHECK: Path: () |
| sil @testNonUniquePropertyIndex : $@convention(thin) (Int64) -> () { |
| bb0(%0 : $Int64): |
| %1 = alloc_ref $B |
| %2 = ref_element_addr %1 : $B, #B.prop1 |
| store %0 to %2 : $*Int64 |
| %4 = upcast %1 : $B to $A |
| %5 = ref_element_addr %4 : $A, #A.prop0 |
| store %0 to %5 : $*Int64 |
| %99 = tuple () |
| return %99 : $() |
| } |
| |
| // CHECK-LABEL: @testRefTailAndStruct0 |
| // CHECK: %{{.*}} = load %{{.*}} : $*Builtin.Int64 |
| // CHECK: Class %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Index: 0 |
| // CHECK: Base: %{{.*}} = ref_element_addr [immutable] %{{.*}} : $__ContiguousArrayStorageBase, #__ContiguousArrayStorageBase.countAndCapacity |
| // CHECK: Storage: Class %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Index: 0 |
| // CHECK: Path: (#0,#0,#0) |
| // CHECK: %{{.*}} = load %{{.*}} : $*_StringGuts |
| // CHECK: Tail %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Base: %{{.*}} = ref_tail_addr [immutable] %{{.*}} : $__ContiguousArrayStorageBase, $String |
| // CHECK: Storage: Tail %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Path: (#0) |
| // CHECK: %{{.*}} = load %{{.*}} : $*String |
| // CHECK: Tail %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Base: %{{.*}} = ref_tail_addr [immutable] %{{.*}} : $__ContiguousArrayStorageBase, $String |
| // CHECK: Storage: Tail %{{.*}} = struct_extract %{{.*}} : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| // CHECK: Path: () |
| sil hidden [noinline] @testRefTailAndStruct0 : $@convention(thin) (@owned MyArray<String>) -> () { |
| bb0(%0 : $MyArray<String>): |
| %1 = struct_extract %0 : $MyArray<String>, #MyArray._buffer |
| %2 = struct_extract %1 : $_MyArrayBuffer<String>, #_MyArrayBuffer._storage |
| %3 = struct_extract %2 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue |
| %4 = unchecked_ref_cast %3 : $Builtin.BridgeObject to $__ContiguousArrayStorageBase |
| %5 = ref_element_addr [immutable] %4 : $__ContiguousArrayStorageBase, #__ContiguousArrayStorageBase.countAndCapacity |
| %6 = struct_element_addr %5 : $*_ArrayBody, #_ArrayBody._storage |
| %7 = struct_element_addr %6 : $*_SwiftArrayBodyStorage, #_SwiftArrayBodyStorage.count |
| %8 = struct_element_addr %7 : $*Int, #Int._value |
| %9 = load %8 : $*Builtin.Int64 |
| %10 = ref_tail_addr [immutable] %4 : $__ContiguousArrayStorageBase, $String |
| %11 = struct_element_addr %10 : $*String, #String._guts |
| %12 = load %11 : $*_StringGuts |
| %13 = load %10 : $*String |
| %14 = tuple () |
| return %14 : $() |
| } |
| |
| // CHECK-LABEL: @testPointerDynamicIndex |
| // CHECK: ###For MemOp: %{{.*}} = load [trivial] %{{.*}} : $*MyStruct |
| // CHECK: Base: %0 = argument of bb0 : $Builtin.RawPointer |
| // CHECK: Storage: Argument %0 = argument of bb0 : $Builtin.RawPointer |
| // CHECK: Path: (@Unknown) |
| sil [serialized] [ossa] @testPointerDynamicIndex : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () { |
| bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word): |
| %2 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*MyStruct |
| %3 = index_addr %2 : $*MyStruct, %1 : $Builtin.Word |
| %4 = address_to_pointer %3 : $*MyStruct to $Builtin.RawPointer |
| %5 = pointer_to_address %4 : $Builtin.RawPointer to [strict] $*MyStruct |
| %6 = load [trivial] %5 : $*MyStruct |
| %7 = tuple () |
| return %7 : $() |
| } |
| |
| // CHECK-LABEL: @testAddressToPointer |
| // CHECK: ###For MemOp: %3 = load [trivial] %{{.*}} : $*MyStruct |
| // CHECK: Base: %0 = argument of bb0 : $*MyStruct |
| // CHECK: Storage: Argument %0 = argument of bb0 : $*MyStruct |
| // CHECK: Path: () |
| // CHECK: ###For MemOp: %5 = load [trivial] %4 : $*Int64 |
| // CHECK: Base: %0 = argument of bb0 : $*MyStruct |
| // CHECK: Storage: Argument %0 = argument of bb0 : $*MyStruct |
| // CHECK: Path: (#0) |
| sil [serialized] [ossa] @testAddressToPointer : $@convention(thin) (@in MyStruct) -> () { |
| bb18(%0 : $*MyStruct): |
| %1 = address_to_pointer %0 : $*MyStruct to $Builtin.RawPointer |
| %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*MyStruct |
| %3 = load [trivial] %2 : $*MyStruct |
| %4 = struct_element_addr %0 : $*MyStruct, #MyStruct.i |
| %5 = load [trivial] %4 : $*Int64 |
| %6 = tuple () |
| return %6 : $() |
| } |
| |
| // CHECK-LABEL: @testIndexLoop |
| // CHECK: ###For MemOp: %3 = load %2 : $*AnyObject |
| // CHECK: Base: %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue |
| // CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue |
| // CHECK: Path: () |
| // CHECK: ###For MemOp: %7 = load %6 : $*AnyObject |
| // CHECK: Base: %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue |
| // CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue |
| // CHECK: Path: (@Unknown) |
| // CHECK: ###For MemOp: store %7 to %6 : $*AnyObject // id: %8 |
| // CHECK: Base: %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue |
| // CHECK: Storage: Unidentified %1 = struct_extract %0 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue |
| // CHECK: Path: (@Unknown) |
| sil shared @testIndexLoop : $@convention(thin) (UnsafeMutablePointer<AnyObject>) -> UnsafeMutablePointer<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 |
| %11 = address_to_pointer %10 : $*AnyObject to $Builtin.RawPointer |
| cond_br undef, bb2, bb3(%11 : $Builtin.RawPointer) |
| |
| bb2: |
| br bb1(%11 : $Builtin.RawPointer) |
| |
| bb3(%14 : $Builtin.RawPointer): |
| %15 = struct $UnsafeMutablePointer<AnyObject> (%14 : $Builtin.RawPointer) |
| return %15 : $UnsafeMutablePointer<AnyObject> |
| } |
| |
| // Handle index_addr boundary conditions |
| // Most will end up as "unknown" offset, but we shouldn't crash. |
| // CHECK-LABEL: @indexAddrBoundaries |
| // CHECK: ###For MemOp: %4 = load %3 : $*Int |
| // CHECK: Path: (@Unknown) |
| // CHECK: ###For MemOp: %7 = load %6 : $*Int |
| // CHECK: Path: (@Unknown) |
| // CHECK: ###For MemOp: %10 = load %9 : $*Int |
| // CHECK: Path: (@Unknown) |
| // CHECK: ###For MemOp: %13 = load %12 : $*Int |
| // CHECK: Path: (@Unknown) |
| // CHECK: ###For MemOp: %16 = load %15 : $*Int |
| // CHECK: Path: (@1073741823) |
| // CHECK: ###For MemOp: %19 = load %18 : $*Int |
| // CHECK: Path: (@Unknown) |
| // CHECK: ###For MemOp: %22 = load %21 : $*Int |
| // CHECK: Path: (@Unknown) |
| // CHECK: ###For MemOp: %25 = load %24 : $*Int |
| // CHECK: Path: (@-1073741823) |
| // CHECK: ###For MemOp: %28 = load %27 : $*Int |
| // CHECK: Path: (@-1) |
| sil @indexAddrBoundaries : $@convention(thin) (Builtin.RawPointer) -> () { |
| bb0(%0 : $Builtin.RawPointer): |
| %1 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Int |
| // INT_MIN (IndexTrie root) |
| %2 = integer_literal $Builtin.Word, 2147483648 // '0x80000000' |
| %3 = index_addr %1 : $*Int, %2 : $Builtin.Word |
| %4 = load %3 : $*Int |
| // INT_MIN (IndexTrie root) |
| %5 = integer_literal $Builtin.Word, -2147483648 // '0x80000000' |
| %6 = index_addr %1 : $*Int, %5 : $Builtin.Word |
| %7 = load %6 : $*Int |
| // INT_MAX (TailIndex) |
| %8 = integer_literal $Builtin.Word, 2147483647 // '0x7fffffff' |
| %9 = index_addr %1 : $*Int, %8 : $Builtin.Word |
| %10 = load %9 : $*Int |
| // Largest unsigned offset + 1 |
| %11 = integer_literal $Builtin.Word, 1073741824 // '0x40000000' |
| %12 = index_addr %1 : $*Int, %11 : $Builtin.Word |
| %13 = load %12 : $*Int |
| // Largest unsigned offset |
| %14 = integer_literal $Builtin.Word, 1073741823 // '0x3fffffff' |
| %15 = index_addr %1 : $*Int, %14 : $Builtin.Word |
| %16 = load %15 : $*Int |
| // Smallest signed offset - 1 |
| %17 = integer_literal $Builtin.Word, -1073741825 // '0xbfffffff' |
| %18 = index_addr %1 : $*Int, %17 : $Builtin.Word |
| %19 = load %18 : $*Int |
| // Smallest signed offset (Unknown offset) |
| %20 = integer_literal $Builtin.Word, -1073741824 // '0xc0000000' |
| %21 = index_addr %1 : $*Int, %20 : $Builtin.Word |
| %22 = load %21 : $*Int |
| // Smallest signed offset + 1 (concrete offset) |
| %23 = integer_literal $Builtin.Word, -1073741823 // '0xc0000001' |
| %24 = index_addr %1 : $*Int, %23 : $Builtin.Word |
| %25 = load %24 : $*Int |
| // Largest Negative |
| %26 = integer_literal $Builtin.Word, -1 // '0xffffffff' |
| %27 = index_addr %1 : $*Int, %26 : $Builtin.Word |
| %28 = load %27 : $*Int |
| // |
| %99 = tuple () |
| return %99 : $() |
| } |