blob: 8930a7f112a65353c02bed729b86cc706c8fff59 [file] [log] [blame]
// RUN: %target-sil-opt -for-each-loop-unroll -enable-sil-verify-all %s 2>&1 | %FileCheck %s
// SIL tests for the ForEachLoopUnroll mandatory optimization pass that unrolls
// Sequence.forEach calls over array literals.
import Swift
import Builtin
sil [_semantics "array.uninitialized_intrinsic"] @_allocateUninitializedArray : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
sil [_semantics "sequence.forEach"] @forEach : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error
sil @forEachBody : $@convention(thin) (@in_guaranteed Builtin.Int64) -> @error Error
sil hidden [ossa] @forEachLoopUnrollTest : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 2
%1 = function_ref @_allocateUninitializedArray : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
%2 = apply %1<Builtin.Int64>(%0) : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
(%3, %4) = destructure_tuple %2 : $(Array<Builtin.Int64>, Builtin.RawPointer)
%5 = pointer_to_address %4 : $Builtin.RawPointer to [strict] $*Builtin.Int64
%6 = integer_literal $Builtin.Int64, 15
store %6 to [trivial] %5 : $*Builtin.Int64
%12 = integer_literal $Builtin.Word, 1
%13 = index_addr %5 : $*Builtin.Int64, %12 : $Builtin.Word
%14 = integer_literal $Builtin.Int64, 27
store %14 to [trivial] %13 : $*Builtin.Int64
%21 = begin_borrow %3 : $Array<Builtin.Int64>
%22 = alloc_stack $Array<Builtin.Int64>
%23 = store_borrow %21 to %22 : $*Array<Builtin.Int64>
%24 = function_ref @forEachBody : $@convention(thin) (@in_guaranteed Builtin.Int64) -> @error Error
%25 = convert_function %24 : $@convention(thin) (@in_guaranteed Builtin.Int64) -> @error Error to $@convention(thin) @noescape (@in_guaranteed Builtin.Int64) -> @error Error
%26 = thin_to_thick_function %25 : $@convention(thin) @noescape (@in_guaranteed Builtin.Int64) -> @error Error to $@noescape @callee_guaranteed (@in_guaranteed Builtin.Int64) -> @error Error
// A stub for Sequence.forEach(_:)
%30 = function_ref @forEach : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error
try_apply %30<[Builtin.Int64]>(%26, %22) : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error, normal bb1, error bb2
bb1(%32 : $()):
dealloc_stack %22 : $*Array<Builtin.Int64>
end_borrow %21 : $Array<Builtin.Int64>
destroy_value %3 : $Array<Builtin.Int64>
%37 = tuple ()
return %37 : $()
bb2(%39 : @owned $Error):
unreachable
}
// CHECK-LABEL: forEachLoopUnrollTest
// CHECK: [[LIT1:%[0-9]+]] = integer_literal $Builtin.Int64, 15
// CHECK: [[LIT2:%[0-9]+]] = integer_literal $Builtin.Int64, 27
// CHECK: [[BODYCLOSURE:%[0-9]+]] = thin_to_thick_function
// CHECK-NOT: forEach
// CHECK: [[STACK:%[0-9]+]] = alloc_stack $Builtin.Int64
// CHECK: store [[LIT1]] to [trivial] [[STACK]]
// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed Builtin.Int64) -> @error Error, normal [[NORMAL:bb[0-9]+]], error [[ERROR:bb[0-9]+]]
// CHECK: [[ERROR]]([[ERRPARAM:%[0-9]+]] : @owned $Error):
// CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM]] : $Error)
// CHECK: [[NORMAL]](%{{.*}} : $()):
// CHECK: store [[LIT2]] to [trivial] [[STACK]] : $*Builtin.Int64
// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed Builtin.Int64) -> @error Error, normal [[NORMAL2:bb[0-9]+]], error [[ERROR2:bb[0-9]+]]
// CHECK: [[ERROR2]]([[ERRPARAM2:%[0-9]+]] : @owned $Error):
// CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM2]] : $Error)
// CHECK: [[NORMAL2]](%{{.*}} : $()):
// CHECK: dealloc_stack [[STACK]]
// Note that the temporary alloc_stack of the array created for the forEach call
// will be cleaned up when the forEach call is removed.
// CHECK: destroy_value
// CHECK: [[ERROR3]]([[ERRPARAM3:%[0-9]+]] : @owned $Error):
// CHECK: dealloc_stack [[STACK]]
// CHECK: unreachable
sil @forEachBody2 : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <Int>) -> @error Error
sil hidden [ossa] @nonTrivialForEachLoopUnrollTest : $@convention(thin) (@owned @callee_guaranteed @substituted <A> () -> @out A for <Int>, @owned @callee_guaranteed @substituted <A> () -> @out A for <Int>) -> () {
bb0(%0: @owned $@callee_guaranteed @substituted <A> () -> @out A for <Int>, %1: @owned $@callee_guaranteed @substituted <A> () -> @out A for <Int>):
%2 = integer_literal $Builtin.Word, 2
%3 = function_ref @_allocateUninitializedArray : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
%4 = apply %3<() -> Int>(%2) : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
(%5, %6) = destructure_tuple %4 : $(Array<()->Int>, Builtin.RawPointer)
%7 = pointer_to_address %6 : $Builtin.RawPointer to [strict] $*@callee_guaranteed @substituted <A> () -> @out A for <Int>
store %0 to [init] %7 : $*@callee_guaranteed @substituted <A> () -> @out A for <Int>
%12 = integer_literal $Builtin.Word, 1
%13 = index_addr %7 : $*@callee_guaranteed @substituted <A> () -> @out A for <Int>, %12 : $Builtin.Word
store %1 to [init] %13 : $*@callee_guaranteed @substituted <A> () -> @out A for <Int>
%21 = begin_borrow %5 : $Array<()->Int>
%22 = alloc_stack $Array<()->Int>
%23 = store_borrow %21 to %22 : $*Array<()->Int>
%24 = function_ref @forEachBody2 : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <Int>) -> @error Error
%25 = convert_function %24 : $@convention(thin) (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <Int>) -> @error Error to $@convention(thin) @noescape (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <Int>) -> @error Error
%26 = thin_to_thick_function %25 : $@convention(thin) @noescape (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <Int>) -> @error Error to $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <Int>) -> @error Error
// A stub for Sequence.forEach(_:)
%30 = function_ref @forEach : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error
try_apply %30<[() -> Int]>(%26, %22) : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error, normal bb1, error bb2
bb1(%32 : $()):
dealloc_stack %22 : $*Array<() -> Int>
end_borrow %21 : $Array<() -> Int>
destroy_value %5 : $Array<() -> Int>
%37 = tuple ()
return %37 : $()
bb2(%39 : @owned $Error):
unreachable
}
// CHECK-LABEL: nonTrivialForEachLoopUnrollTest
// CHECK: [[ELEM1:%[0-9]+]] = copy_value %0
// CHECK-NEXT: store %0 to [init] %{{.*}} : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
// CHECK: [[ELEM2:%[0-9]+]] = copy_value %1
// CHECK-NEXT: store %1 to [init] %{{.*}} : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
// CHECK: [[BODYCLOSURE:%[0-9]+]] = thin_to_thick_function
// CHECK-NOT: forEach
// CHECK: [[STACK:%[0-9]+]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
// CHECK: [[ELEM1BORROW:%[0-9]+]] = begin_borrow [[ELEM1]]
// CHECK: store_borrow [[ELEM1BORROW]] to [[STACK]]
// CHECK: end_borrow [[ELEM1BORROW]]
// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>) -> @error Error, normal [[NORMAL:bb[0-9]+]], error [[ERROR:bb[0-9]+]]
// CHECK: [[ERROR]]([[ERRPARAM:%[0-9]+]] : @owned $Error):
// CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM]] : $Error)
// CHECK: [[NORMAL]](%{{.*}} : $()):
// CHECK: [[ELEM2BORROW:%[0-9]+]] = begin_borrow [[ELEM2]]
// CHECK: store_borrow [[ELEM2BORROW]] to [[STACK]]
// CHECK: end_borrow [[ELEM2BORROW]]
// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>) -> @error Error, normal [[NORMAL2:bb[0-9]+]], error [[ERROR2:bb[0-9]+]]
// CHECK: [[ERROR2]]([[ERRPARAM2:%[0-9]+]] : @owned $Error):
// CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM2]] : $Error)
// CHECK: [[NORMAL2]](%{{.*}} : $()):
// CHECK: dealloc_stack [[STACK]]
// Note that the temporary alloc_stack of the array created for the forEach call
// will be cleaned up when the forEach call is removed.
// CHECK: destroy_value
// CHECK: [[ERROR3]]([[ERRPARAM3:%[0-9]+]] : @owned $Error):
// CHECK: dealloc_stack [[STACK]]
// CHECK: unreachable
sil hidden [ossa] @checkIndirectFixLifetimeUsesAreIgnored : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Word, 2
%1 = function_ref @_allocateUninitializedArray : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
%2 = apply %1<Builtin.Int64>(%0) : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
(%3, %4) = destructure_tuple %2 : $(Array<Builtin.Int64>, Builtin.RawPointer)
%5 = pointer_to_address %4 : $Builtin.RawPointer to [strict] $*Builtin.Int64
%6 = integer_literal $Builtin.Int64, 15
store %6 to [trivial] %5 : $*Builtin.Int64
%12 = integer_literal $Builtin.Word, 1
%13 = index_addr %5 : $*Builtin.Int64, %12 : $Builtin.Word
%14 = integer_literal $Builtin.Int64, 27
store %14 to [trivial] %13 : $*Builtin.Int64
%21 = begin_borrow %3 : $Array<Builtin.Int64>
%22 = alloc_stack $Array<Builtin.Int64>
%23 = store_borrow %21 to %22 : $*Array<Builtin.Int64>
%24 = function_ref @forEachBody : $@convention(thin) (@in_guaranteed Builtin.Int64) -> @error Error
%25 = convert_function %24 : $@convention(thin) (@in_guaranteed Builtin.Int64) -> @error Error to $@convention(thin) @noescape (@in_guaranteed Builtin.Int64) -> @error Error
%26 = thin_to_thick_function %25 : $@convention(thin) @noescape (@in_guaranteed Builtin.Int64) -> @error Error to $@noescape @callee_guaranteed (@in_guaranteed Builtin.Int64) -> @error Error
// A stub for Sequence.forEach(_:)
%30 = function_ref @forEach : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error
try_apply %30<[Builtin.Int64]>(%26, %22) : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error, normal bb1, error bb2
bb1(%32 : $()):
// An indirect fixLifetime use
dealloc_stack %22 : $*Array<Builtin.Int64>
%33 = alloc_stack $Array<Builtin.Int64>
%34 = store_borrow %21 to %33 : $*Array<Builtin.Int64>
fix_lifetime %33 : $*Array<Builtin.Int64>
dealloc_stack %33 : $*Array<Builtin.Int64>
end_borrow %21 : $Array<Builtin.Int64>
destroy_value %3 : $Array<Builtin.Int64>
%37 = tuple ()
return %37 : $()
bb2(%39 : @owned $Error):
unreachable
}
// CHECK-LABEL: @checkIndirectFixLifetimeUsesAreIgnored
// CHECK-NOT: function_ref @forEach : $@convention(method) <τ_0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error
// CHECK: end sil function 'checkIndirectFixLifetimeUsesAreIgnored'
sil hidden [ossa] @testUnrollOfArrayWithPhiArguments : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Int64, 57
br bb1(%0 : $Builtin.Int64)
bb1(%arg : $Builtin.Int64):
%10 = integer_literal $Builtin.Word, 1
%11 = function_ref @_allocateUninitializedArray : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
%12 = apply %11<Builtin.Int64>(%10) : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
(%13, %14) = destructure_tuple %12 : $(Array<Builtin.Int64>, Builtin.RawPointer)
%15 = pointer_to_address %14 : $Builtin.RawPointer to [strict] $*Builtin.Int64
store %arg to [trivial] %15 : $*Builtin.Int64
br bb2(%arg : $Builtin.Int64)
bb2(%arg2 : $Builtin.Int64):
%21 = begin_borrow %13 : $Array<Builtin.Int64>
%22 = alloc_stack $Array<Builtin.Int64>
%23 = store_borrow %21 to %22 : $*Array<Builtin.Int64>
%24 = function_ref @forEachBody : $@convention(thin) (@in_guaranteed Builtin.Int64) -> @error Error
%25 = convert_function %24 : $@convention(thin) (@in_guaranteed Builtin.Int64) -> @error Error to $@convention(thin) @noescape (@in_guaranteed Builtin.Int64) -> @error Error
%26 = thin_to_thick_function %25 : $@convention(thin) @noescape (@in_guaranteed Builtin.Int64) -> @error Error to $@noescape @callee_guaranteed (@in_guaranteed Builtin.Int64) -> @error Error
// A stub for Sequence.forEach(_:)
%30 = function_ref @forEach : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error
try_apply %30<[Builtin.Int64]>(%26, %22) : $@convention(method) _0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error, normal bb3, error bb4
bb3(%32 : $()):
dealloc_stack %22 : $*Array<Builtin.Int64>
end_borrow %21 : $Array<Builtin.Int64>
destroy_value %13 : $Array<Builtin.Int64>
%37 = tuple ()
return %37 : $()
bb4(%39 : @owned $Error):
unreachable
}
// CHECK-LABEL: @testUnrollOfArrayWithPhiArguments
// CHECK-NOT: function_ref @forEach : $@convention(method) <τ_0_0 where τ_0_0 : Sequence> (@noescape @callee_guaranteed (@in_guaranteed τ_0_0.Element) -> @error Error, @in_guaranteed τ_0_0) -> @error Error
// CHECK: end sil function 'testUnrollOfArrayWithPhiArguments'