mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
271 lines
8.0 KiB
Plaintext
271 lines
8.0 KiB
Plaintext
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -licm | %FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
// CHECK-LABEL: @memset
|
|
|
|
// CHECK: bb0
|
|
// CHECK: load %0
|
|
// CHECK: br bb2
|
|
|
|
// CHECK: bb2({{.*}}):
|
|
// CHECK-NOT: load
|
|
// CHECK-NOT: fix_lifetime
|
|
// CHECK: cond_br
|
|
|
|
sil @memset : $@convention(thin) (@inout Builtin.NativeObject, Int) -> () {
|
|
bb0(%0 : $*Builtin.NativeObject, %1 : $Int):
|
|
%5 = integer_literal $Builtin.Int1, -1
|
|
%46 = integer_literal $Builtin.Word, 0
|
|
br bb2(%46 : $Builtin.Word)
|
|
|
|
bb1:
|
|
%52 = tuple ()
|
|
return %52 : $()
|
|
|
|
bb2(%54 : $Builtin.Word):
|
|
%55 = integer_literal $Builtin.Word, 1
|
|
%57 = builtin "sadd_with_overflow_Word"(%54 : $Builtin.Word, %55 : $Builtin.Word, %5 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
|
|
%58 = tuple_extract %57 : $(Builtin.Word, Builtin.Int1), 0
|
|
%59 = load %0 : $*Builtin.NativeObject
|
|
%60 = integer_literal $Builtin.Word, 100
|
|
%96 = ref_to_raw_pointer %59 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
%97 = index_raw_pointer %96 : $Builtin.RawPointer, %58 : $Builtin.Word
|
|
%98 = pointer_to_address %97 : $Builtin.RawPointer to [strict] $*Int
|
|
%99 = index_addr %98 : $*Int, %54 : $Builtin.Word
|
|
fix_lifetime %59: $Builtin.NativeObject
|
|
store %1 to %99 : $*Int
|
|
%101 = builtin "cmp_eq_Word"(%58 : $Builtin.Word, %60 : $Builtin.Word) : $Builtin.Int1
|
|
cond_br %101, bb1, bb2(%58 : $Builtin.Word)
|
|
}
|
|
|
|
// CHECK-LABEL: @must_move_condfail
|
|
|
|
// CHECK: bb0
|
|
// CHECK: load %0
|
|
// CHECK: cond_fail
|
|
// CHECK: [[INVARIANTADDR:%.*]] = pointer_to_address
|
|
// CHECK: load [[INVARIANTADDR]]
|
|
// CHECK: br bb2
|
|
|
|
// CHECK: bb2({{.*}}):
|
|
// The address computation of the load was guarded by the cond_fail. If we hoist
|
|
// the load we must also hoist the cond_fail.
|
|
// CHECK-NOT: cond_fail
|
|
// CHECK-NOT: load
|
|
// CHECK: cond_br
|
|
|
|
sil @must_move_condfail : $@convention(thin) (@inout Builtin.NativeObject, Int, Builtin.Word) -> () {
|
|
bb0(%0 : $*Builtin.NativeObject, %1 : $Int, %2: $Builtin.Word):
|
|
%5 = integer_literal $Builtin.Int1, -1
|
|
%6 = load %0 : $*Builtin.NativeObject
|
|
%46 = integer_literal $Builtin.Word, 0
|
|
br bb2(%46 : $Builtin.Word)
|
|
|
|
bb1:
|
|
%102 = tuple ()
|
|
return %102 : $()
|
|
|
|
bb2(%48 : $Builtin.Word):
|
|
%51 = builtin "sadd_with_overflow_Word"(%2 : $Builtin.Word, %46 : $Builtin.Word, %5 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
|
|
%52 = tuple_extract %51 : $(Builtin.Word, Builtin.Int1), 0
|
|
%53 = tuple_extract %51 : $(Builtin.Word, Builtin.Int1), 1
|
|
cond_fail %53 : $Builtin.Int1
|
|
%55 = integer_literal $Builtin.Word, 1
|
|
%57 = builtin "sadd_with_overflow_Word"(%48 : $Builtin.Word, %55 : $Builtin.Word, %5 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
|
|
%58 = tuple_extract %57 : $(Builtin.Word, Builtin.Int1), 0
|
|
%60 = integer_literal $Builtin.Word, 100
|
|
%61 = ref_to_raw_pointer %6 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
%62 = index_raw_pointer %61 : $Builtin.RawPointer, %52 : $Builtin.Word
|
|
%63 = pointer_to_address %62 : $Builtin.RawPointer to [strict] $*Builtin.NativeObject
|
|
%64 = load %63 : $*Builtin.NativeObject
|
|
%96 = ref_to_raw_pointer %64 : $Builtin.NativeObject to $Builtin.RawPointer
|
|
%97 = index_raw_pointer %96 : $Builtin.RawPointer, %58 : $Builtin.Word
|
|
%98 = pointer_to_address %97 : $Builtin.RawPointer to [strict] $*Int
|
|
%99 = index_addr %98 : $*Int, %48 : $Builtin.Word
|
|
store %1 to %99 : $*Int
|
|
%101 = builtin "cmp_eq_Word"(%58 : $Builtin.Word, %60 : $Builtin.Word) : $Builtin.Int1
|
|
cond_br %101, bb1, bb2(%58 : $Builtin.Word)
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil @hoist_outer_loop
|
|
// CHECK: bb0([[ADDR:%.*]] : $*Builtin.Int1
|
|
// CHECK: load [[ADDR]]
|
|
// CHECK: integer_literal $Builtin.Word, 101
|
|
// CHECK: br bb1
|
|
// CHECK: return
|
|
|
|
sil @hoist_outer_loop : $@convention(thin) (@inout Builtin.Int1, Int) -> () {
|
|
bb0(%0 : $*Builtin.Int1, %1 : $Int):
|
|
%2 = integer_literal $Builtin.Int1, -1
|
|
%3 = integer_literal $Builtin.Word, 0
|
|
br bb1
|
|
|
|
// Outer loop.
|
|
bb1:
|
|
%5 = load %0 : $*Builtin.Int1
|
|
%6 = integer_literal $Builtin.Word, 101
|
|
cond_br %5, bb2, bb3
|
|
|
|
bb2:
|
|
cond_br %5, bb4, bb1
|
|
|
|
// Inner loop.
|
|
bb3:
|
|
cond_br %5, bb2, bb3
|
|
|
|
bb4:
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_hoist_outer_loop
|
|
// CHECK: bb0([[ADDR:%.*]] : $*Builtin.Int1
|
|
// CHECK: integer_literal $Builtin.Word, 101
|
|
// CHECK: br bb1
|
|
// CHECK: bb1:
|
|
// CHECK: load [[ADDR]]
|
|
// CHECK: return
|
|
|
|
sil @dont_hoist_outer_loop : $@convention(thin) (@inout Builtin.Int1, Int) -> () {
|
|
bb0(%0 : $*Builtin.Int1, %1 : $Int):
|
|
%2 = integer_literal $Builtin.Int1, -1
|
|
%3 = integer_literal $Builtin.Word, 0
|
|
br bb1
|
|
|
|
// Outer loop.
|
|
bb1:
|
|
%5 = load %0 : $*Builtin.Int1
|
|
%6 = integer_literal $Builtin.Word, 101
|
|
cond_br %5, bb2, bb3
|
|
|
|
bb2:
|
|
cond_br %5, bb4, bb1
|
|
|
|
// Inner loop.
|
|
bb3:
|
|
store %2 to %0 : $*Builtin.Int1
|
|
cond_br %5, bb2, bb3
|
|
|
|
bb4:
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
sil [_semantics "array.get_count"] @getCount : $@convention(method) (@guaranteed Array<Int>) -> Int
|
|
sil @user : $@convention(thin) (Int) -> ()
|
|
|
|
// CHECK-LABEL: sil @dont_hoist_get_count_on_low_level_sil
|
|
// CHECK: {{^}}bb1:
|
|
// CHECK: apply
|
|
// CHECK: apply
|
|
// CHECK: {{^}}bb2:
|
|
// CHECK: return
|
|
sil @dont_hoist_get_count_on_low_level_sil : $@convention(thin) (@guaranteed Array<Int>) -> () {
|
|
bb0(%0 : $Array<Int>):
|
|
br bb1
|
|
|
|
bb1:
|
|
%f1 = function_ref @getCount : $@convention(method) (@guaranteed Array<Int>) -> Int
|
|
%f2 = function_ref @user : $@convention(thin) (Int) -> ()
|
|
%c1 = apply %f1(%0) : $@convention(method) (@guaranteed Array<Int>) -> Int
|
|
%c2 = apply %f2(%c1) : $@convention(thin) (Int) -> ()
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb2:
|
|
%r1 = tuple ()
|
|
return %r1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_hoist_aliased_stack_location
|
|
// CHECK: {{^}}bb0
|
|
// CHECK-NOT: load
|
|
// CHECK: {{^}}bb1:
|
|
// CHECK: store
|
|
// CHECK: load
|
|
// CHECK: {{^}}bb2:
|
|
// CHECK: return
|
|
sil @dont_hoist_aliased_stack_location : $@convention(thin) (Int32) -> () {
|
|
bb0(%0 : $Int32):
|
|
%313 = alloc_stack $Int32
|
|
br bb1
|
|
|
|
bb1:
|
|
store %0 to %313 : $*Int32
|
|
%l1 = load %313 : $*Int32
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb2:
|
|
dealloc_stack %313 : $*Int32
|
|
%52 = tuple ()
|
|
return %52 : $()
|
|
}
|
|
|
|
public protocol P : class {
|
|
func foo() -> Int32
|
|
func boo() -> Int32
|
|
}
|
|
|
|
// Check that LICM does not hoist a metatype instruction before
|
|
// the open_existential instruction which creates the archtype,
|
|
// because this would break the dominance relation between them.
|
|
// CHECK-LABEL: sil @dont_hoist_metatype
|
|
// CHECK-NOT: metatype
|
|
// CHECK-NOT: witness_method
|
|
// CHECK: bb1({{%.*}} : $P)
|
|
// CHECK-NOT: metatype
|
|
// CHECK-NOT: witness_method
|
|
// CHECK: open_existential_ref
|
|
// CHECK: metatype
|
|
// CHECK: witness_method
|
|
// CHECK: cond_br
|
|
sil @dont_hoist_metatype : $@convention(thin) (@inout Builtin.Int1, @owned P) -> () {
|
|
bb0(%0 : $*Builtin.Int1, %1 : $P):
|
|
br bb1(%1 : $P)
|
|
|
|
// Loop
|
|
bb1(%existential : $P):
|
|
%2 = open_existential_ref %existential : $P to $@opened("C4960DBA-02C5-11E6-BE1B-B8E856428C60") P
|
|
%3 = metatype $@thick (@opened("C4960DBA-02C5-11E6-BE1B-B8E856428C60") P).Type
|
|
%4 = witness_method $@opened("C4960DBA-02C5-11E6-BE1B-B8E856428C60") P, #P.foo!1, %2 : $@opened("C4960DBA-02C5-11E6-BE1B-B8E856428C60") P : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> Int32
|
|
%5 = apply %4<@opened("C4960DBA-02C5-11E6-BE1B-B8E856428C60") P>(%2) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> Int32
|
|
%6 = load %0 : $*Builtin.Int1
|
|
cond_br %6, bb3, bb1(%existential : $P)
|
|
|
|
bb3:
|
|
br bb4
|
|
|
|
bb4:
|
|
strong_release %1 : $P
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: dont_hoist_existential_meta_type
|
|
// CHECK: bb0({{.*}}:
|
|
// CHECK-NOT: existential_metatype
|
|
// CHECK: bb1:
|
|
// CHECK: existential_metatype
|
|
// CHECK: cond_br
|
|
// CHECK: bb2:
|
|
sil @dont_hoist_existential_meta_type : $@convention(thin) (@in P) -> () {
|
|
bb0(%0 : $*P):
|
|
%1 = alloc_stack $P
|
|
br bb1
|
|
|
|
bb1:
|
|
copy_addr %0 to [initialization] %1 : $*P
|
|
%2 = existential_metatype $@thick P.Type, %1 : $*P
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb2:
|
|
dealloc_stack %1 : $*P
|
|
destroy_addr %0 : $*P
|
|
%52 = tuple ()
|
|
return %52 : $()
|
|
}
|