blob: 2630ab025f0c50d9aee9115476f7cde9ec1d6d39 [file] [log] [blame]
// RUN: %target-sil-opt -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 : $()
}