blob: e51198847ea00c2295228ba2d86b186a7568bdcc [file] [log] [blame]
// RUN: %target-sil-opt -silgen-cleanup %s | %FileCheck %s
import Builtin
sil_stage raw
import Swift
import SwiftShims
// CHECK-LABEL: sil [ossa] @struct_extract_load_to_load_struct_element_addr
// CHECK: bb0([[IN:%[0-9]+]] : $*UInt8):
// CHECK-NEXT: [[IN_GEP:%[0-9]+]] = struct_element_addr [[IN]] : $*UInt8, #UInt8._value
// CHECK-NEXT: [[IN_LOADED:%[0-9]+]] = load [trivial] [[IN_GEP]] : $*Builtin.Int8
// CHECK-NEXT: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int8, 1
// CHECK-NEXT: [[UINT8:%.*]] = struct $UInt8 ([[LITERAL]] : $Builtin.Int8)
// CHECK-NEXT: store [[UINT8]] to [trivial] [[IN]] : $*UInt8
// CHECK-NEXT: return [[IN_LOADED]] : $Builtin.Int8
sil [ossa] @struct_extract_load_to_load_struct_element_addr : $@convention(thin) (@inout UInt8) -> (Builtin.Int8) {
bb0(%0 : $*UInt8):
%1 = load [trivial] %0 : $*UInt8
%2 = integer_literal $Builtin.Int8, 1
%3 = struct_element_addr %0 : $*UInt8, #UInt8._value
store %2 to [trivial] %3 : $*Builtin.Int8
%5 = struct_extract %1 : $UInt8, #UInt8._value
return %5 : $Builtin.Int8
}
// CHECK-LABEL: sil [ossa] @tuple_extract_load_to_load_tuple_element_addr
// CHECK: bb0([[IN:%[0-9]+]] : $*(Builtin.Int8, Builtin.Int8)):
// CHECK-NEXT: [[IN_GEP:%[0-9]+]] = tuple_element_addr [[IN]] : $*(Builtin.Int8, Builtin.Int8), 0
// CHECK-NEXT: [[IN_LOADED:%[0-9]+]] = load [trivial] [[IN_GEP]] : $*Builtin.Int8
// CHECK-NEXT: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int8, 1
// CHECK-NEXT: [[IN_STORE_GEP:%[0-9]+]] = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
// CHECK-NEXT: store [[LITERAL]] to [trivial] [[IN_STORE_GEP]] : $*Builtin.Int8
// CHECK-NEXT: return [[IN_LOADED]] : $Builtin.Int8
sil [ossa] @tuple_extract_load_to_load_tuple_element_addr : $@convention(thin) (@inout (Builtin.Int8, Builtin.Int8)) -> (Builtin.Int8) {
bb0(%0 : $*(Builtin.Int8, Builtin.Int8)):
%1 = load [trivial] %0 : $*(Builtin.Int8, Builtin.Int8)
%2 = integer_literal $Builtin.Int8, 1
%3 = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
store %2 to [trivial] %3 : $*Builtin.Int8
%5 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int8), 0
return %5 : $Builtin.Int8
}
// Do not perform the optimization of the input load has multiple uses.
//
// CHECK-LABEL: sil [ossa] @multiple_use_struct_extract_load_to_load_struct_element_addr
// CHECK: bb0([[IN:%[0-9]+]] : $*UInt8):
// CHECK-NEXT: load
// CHECK-NEXT: integer_literal
// CHECK-NEXT: struct
// CHECK-NEXT: store
// CHECK-NEXT: struct_extract
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @multiple_use_struct_extract_load_to_load_struct_element_addr : $@convention(thin) (@inout UInt8) -> (UInt8, Builtin.Int8) {
bb0(%0 : $*UInt8):
%1 = load [trivial] %0 : $*UInt8
%2 = integer_literal $Builtin.Int8, 1
%3 = struct_element_addr %0 : $*UInt8, #UInt8._value
store %2 to [trivial] %3 : $*Builtin.Int8
%5 = struct_extract %1 : $UInt8, #UInt8._value
%6 = tuple (%1 : $UInt8, %5 : $Builtin.Int8)
return %6 : $(UInt8, Builtin.Int8)
}
// Do not perform the optimization of the input load has multiple uses.
//
// CHECK-LABEL: sil [ossa] @multiple_use_tuple_extract_load_to_load_tuple_element_addr
// CHECK: bb0
// CHECK-NEXT: load
// CHECK-NEXT: integer_literal
// CHECK-NEXT: tuple_element_addr
// CHECK-NEXT: store
// CHECK-NEXT: tuple_extract
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @multiple_use_tuple_extract_load_to_load_tuple_element_addr : $@convention(thin) (@inout (Builtin.Int8, Builtin.Int8)) -> ((Builtin.Int8, Builtin.Int8), Builtin.Int8) {
bb0(%0 : $*(Builtin.Int8, Builtin.Int8)):
%1 = load [trivial] %0 : $*(Builtin.Int8, Builtin.Int8)
%2 = integer_literal $Builtin.Int8, 1
%3 = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
store %2 to [trivial] %3 : $*Builtin.Int8
%5 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int8), 0
%6 = tuple (%1 : $(Builtin.Int8, Builtin.Int8), %5 : $Builtin.Int8)
return %6 : $((Builtin.Int8, Builtin.Int8), Builtin.Int8)
}
// Handle a combination of trivial and nontrivial elements.
struct X1 {
@_hasStorage @_hasInitialValue let a: Int { get }
@_hasStorage @_hasInitialValue var obj1: AnyObject { get set }
@_hasStorage @_hasInitialValue var obj2: AnyObject { get set }
init(a: Int, obj1: AnyObject, obj2: AnyObject)
}
// CHECK-LABEL: sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned AnyObject, @owned AnyObject) {
// CHECK-LABEL: bb0(%0 : $*X1):
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] %0 : $*X1
// CHECK: [[AA:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.a
// CHECK: load [trivial] [[AA]] : $*Int
// CHECK: [[OA1:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.obj1
// CHECK: [[OV1:%.*]] = load [copy] [[OA1]] : $*AnyObject
// CHECK: [[OA2:%.*]] = struct_element_addr [[ACCESS]] : $*X1, #X1.obj2
// CHECK: [[OV2:%.*]] = load [copy] [[OA2]] : $*AnyObject
// CHECK: end_access [[ACCESS]] : $*X1
// CHECK: [[B1:%.*]] = begin_borrow [[OV1]] : $AnyObject
// CHECK: copy_value [[B1]] : $AnyObject
// CHECK: end_borrow [[B1]] : $AnyObject
// CHECK: [[B2:%.*]] = begin_borrow [[OV2]] : $AnyObject
// CHECK: copy_value [[B2]] : $AnyObject
// CHECK: end_borrow [[B2]] : $AnyObject
// CHECK: return
// CHECK-LABEL: } // end sil function 'testLoadNontrivial'
sil private [ossa] @testLoadNontrivial : $@convention(thin) (@inout_aliasable X1) -> (Int, @owned AnyObject, @owned AnyObject) {
bb0(%0 : $*X1):
%access = begin_access [read] [unknown] %0 : $*X1
%load = load [copy] %access : $*X1
end_access %access : $*X1
%borrowa = begin_borrow %load : $X1
%a = struct_extract %borrowa : $X1, #X1.a
end_borrow %borrowa : $X1
%borrow1 = begin_borrow %load : $X1
%o1 = struct_extract %borrow1 : $X1, #X1.obj1
%copy1 = copy_value %o1 : $AnyObject
end_borrow %borrow1 : $X1
%borrow2 = begin_borrow %load : $X1
%o2 = struct_extract %borrow2 : $X1, #X1.obj2
%copy2 = copy_value %o2 : $AnyObject
end_borrow %borrow2 : $X1
destroy_value %load : $X1
%result = tuple (%a : $Int, %copy1 : $AnyObject, %copy2 : $AnyObject)
return %result : $(Int, AnyObject, AnyObject)
}
struct X2 {
@_hasStorage @_hasInitialValue var obj: AnyObject { get set }
}
struct X3 {
@_hasStorage @_hasInitialValue var x2: X2 { get set }
}
// CHECK-LABEL: sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed AnyObject) -> () {
// CHECK-LABEL: bb0(%0 : $*X3, %1 : @guaranteed $AnyObject):
// CHECK: [[CP:%.*]] = copy_value %1 : $AnyObject
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] %0 : $*X3
// CHECK: [[X2:%.*]] = struct $X2 ([[CP]] : $AnyObject)
// CHECK: [[X3:%.*]] = struct $X3 ([[X2]] : $X2)
// CHECK: store [[X3]] to [assign] [[ACCESS]] : $*X3
// CHECK: end_access [[ACCESS]] : $*X3
// CHECK-LABEL: } // end sil function 'testStoreNontrivial'
sil private [ossa] @testStoreNontrivial : $@convention(thin) (@inout X3, @guaranteed AnyObject) -> () {
bb0(%0 : $*X3, %1 : @guaranteed $AnyObject):
%4 = copy_value %1 : $AnyObject
%5 = begin_access [modify] [unknown] %0 : $*X3
%6 = struct_element_addr %5 : $*X3, #X3.x2
%7 = struct_element_addr %6 : $*X2, #X2.obj
store %4 to [assign] %7 : $*AnyObject
end_access %5 : $*X3
%12 = tuple ()
return %12 : $()
}