| // RUN: %target-sil-opt -enable-sil-verify-all %s -mem2reg | %FileCheck %s |
| |
| import Builtin |
| import Swift |
| |
| ////////////////// |
| // Declarations // |
| ////////////////// |
| |
| class Klass {} |
| |
| struct SmallCodesizeStruct { |
| var cls1 : Klass |
| var cls2 : Klass |
| } |
| |
| struct LargeCodesizeStruct { |
| var s1: SmallCodesizeStruct |
| var s2: SmallCodesizeStruct |
| var s3: SmallCodesizeStruct |
| var s4: SmallCodesizeStruct |
| var s5: SmallCodesizeStruct |
| } |
| |
| /////////// |
| // Tests // |
| /////////// |
| |
| // CHECK-LABEL: sil [ossa] @store_only_allocas : |
| // CHECK-NOT: alloc_stack |
| // CHECK-LABEL: } // end sil function 'store_only_allocas' |
| // simple.foo0 (c : Swift.Int64) -> () |
| sil [ossa] @store_only_allocas : $@convention(thin) (Int64) -> () { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $Int64, var, name "c" |
| store %0 to [trivial] %1 : $*Int64 |
| // function_ref Swift.print (val : Swift.Int64) -> () |
| %3 = function_ref @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> () |
| %4 = apply %3(%0) : $@convention(thin) (Int64) -> () |
| dealloc_stack %1 : $*Int64 |
| %6 = tuple () |
| return %6 : $() |
| } |
| |
| // Swift.print (val : Swift.Int64) -> () |
| sil [ossa] @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> () |
| |
| // CHECK-LABEL: sil [ossa] @multiple_store_vals : |
| // CHECK-NOT: alloc_stack |
| // CHECK-LABEL: } // end sil function 'multiple_store_vals' |
| // simple.foo1 (c : Swift.Int64) -> Swift.Int64 |
| sil [ossa] @multiple_store_vals : $@convention(thin) (Int64) -> Int64 { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $Int64, var, name "c" |
| store %0 to [trivial] %1 : $*Int64 |
| %3 = alloc_stack $Int64, var, name "x" |
| %4 = integer_literal $Builtin.Int64, 2 |
| %5 = struct $Int64 (%4 : $Builtin.Int64) |
| store %5 to [trivial] %3 : $*Int64 |
| %7 = integer_literal $Builtin.Int64, 5 |
| %8 = integer_literal $Builtin.Int1, 0 |
| %9 = struct $Int64 (%7 : $Builtin.Int64) |
| cond_fail %8 : $Builtin.Int1 |
| store %9 to [trivial] %3 : $*Int64 |
| store %9 to [trivial] %3 : $*Int64 |
| dealloc_stack %3 : $*Int64 |
| dealloc_stack %1 : $*Int64 |
| return %9 : $Int64 |
| } |
| |
| // CHECK-LABEL: sil [ossa] @multiple_store_vals2 : |
| // CHECK-NOT: alloc_stack |
| // CHECK-LABEL: } // end sil function 'multiple_store_vals2' |
| // simple.foo2 (c : Swift.Int64) -> Swift.Int64 |
| sil [ossa] @multiple_store_vals2 : $@convention(thin) (Int64) -> Int64 { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $Int64, var, name "c" |
| store %0 to [trivial] %1 : $*Int64 |
| %3 = alloc_box $<τ_0_0> { var τ_0_0 } <Int64>, var, name "x" |
| %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Int64>, 0 |
| %4 = integer_literal $Builtin.Int64, 2 |
| %5 = struct $Int64 (%4 : $Builtin.Int64) |
| store %5 to [trivial] %3a : $*Int64 |
| %8 = struct_extract %0 : $Int64, #Int64._value |
| %9 = builtin "cmp_sgt_Int64"(%8 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1 |
| cond_br %9, bb1, bb2 |
| |
| bb1: |
| destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64> |
| br bb3(%5 : $Int64) |
| |
| bb2: |
| %13 = integer_literal $Builtin.Int64, 5 |
| %14 = struct $Int64 (%13 : $Builtin.Int64) |
| cond_fail %9 : $Builtin.Int1 |
| destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64> |
| br bb3(%14 : $Int64) |
| |
| bb3(%18 : $Int64): |
| dealloc_stack %1 : $*Int64 |
| return %18 : $Int64 |
| } |
| |
| // CHECK-LABEL: sil [ossa] @with_loads : |
| // CHECK: bb3([[RET:%[0-9]+]] : $Int64): |
| // CHECK-LABEL: } // end sil function 'with_loads' |
| // simple.foo2 (c : Swift.Int64) -> Swift.Int64 |
| sil [ossa] @with_loads : $@convention(thin) (Int64) -> Int64 { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $Int64, var, name "c" |
| store %0 to [trivial] %1 : $*Int64 |
| %3 = alloc_box $<τ_0_0> { var τ_0_0 } <Int64>, var, name "x" |
| %3a = project_box %3 : $<τ_0_0> { var τ_0_0 } <Int64>, 0 |
| %4 = integer_literal $Builtin.Int64, 2 |
| %5 = struct $Int64 (%4 : $Builtin.Int64) |
| store %5 to [trivial] %3a : $*Int64 |
| %8 = struct_extract %0 : $Int64, #Int64._value |
| %9 = builtin "cmp_sgt_Int64"(%8 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1 |
| cond_br %9, bb1, bb2 |
| |
| bb1: |
| destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64> |
| br bb3(%5 : $Int64) |
| |
| bb2: |
| %13 = integer_literal $Builtin.Int64, 5 |
| %14 = struct $Int64 (%13 : $Builtin.Int64) |
| cond_fail %9 : $Builtin.Int1 |
| destroy_value %3 : $<τ_0_0> { var τ_0_0 } <Int64> |
| br bb3(%14 : $Int64) |
| |
| bb3(%18 : $Int64): |
| dealloc_stack %1 : $*Int64 |
| %20 = load [trivial] %1 : $*Int64 |
| return %18 : $Int64 |
| } |
| |
| // CHECK-LABEL: sil [ossa] @basic_block_with_loads_and_stores : |
| // CHECK-NOT: alloc_stack |
| // CHECK-LABEL: } // end sil function 'basic_block_with_loads_and_stores' |
| // test.foo3 (c : Swift.Int64) -> () |
| sil [ossa] @basic_block_with_loads_and_stores : $@convention(thin) (Int64) -> () { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $Int64, var, name "c" |
| store %0 to [trivial] %1 : $*Int64 |
| %3 = alloc_stack $Int64, var, name "x" |
| %4 = integer_literal $Builtin.Int64, 3 |
| %5 = struct $Int64 (%4 : $Builtin.Int64) |
| store %5 to [trivial] %3 : $*Int64 |
| %7 = integer_literal $Builtin.Int64, 3 |
| %9 = struct_extract %0 : $Int64, #Int64._value |
| %10 = builtin "cmp_sgt_Int64"(%9 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1 |
| |
| %12 = integer_literal $Builtin.Int64, 2 |
| %13 = struct $Int64 (%12 : $Builtin.Int64) |
| store %13 to [trivial] %3 : $*Int64 |
| |
| // function_ref Swift.print (val : Swift.Int64) -> () |
| %16 = function_ref @_Ts5printFT3valSi_T_ : $@convention(thin) (Int64) -> () |
| %17 = load [trivial] %3 : $*Int64 |
| %18 = apply %16(%17) : $@convention(thin) (Int64) -> () |
| dealloc_stack %3 : $*Int64 |
| dealloc_stack %1 : $*Int64 |
| %21 = tuple () |
| return %21 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @load_uninitialized_empty : |
| // CHECK-NOT: load |
| // CHECK-LABEL: } // end sil function 'load_uninitialized_empty' |
| sil [ossa] @load_uninitialized_empty : $@convention(thin) (@inout ()) -> () { |
| bb0(%0 : $*()): |
| %1 = alloc_stack $() |
| %2 = load [trivial] %1 : $*() |
| store %2 to [trivial] %0 : $*() |
| dealloc_stack %1 : $*() |
| %3 = tuple () |
| return %3 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @mem2reg_debug_value_addr : |
| // CHECK-NOT: alloc_stack |
| // CHECK-NOT: debug_value_addr |
| // CHECK: debug_value %0 |
| // CHECK-LABEL: } // end sil function 'mem2reg_debug_value_addr' |
| sil [ossa] @mem2reg_debug_value_addr : $@convention(thin) (Int) -> Int { |
| bb0(%0 : $Int): |
| %1 = alloc_stack $Int |
| store %0 to [trivial] %1 : $*Int |
| debug_value_addr %1 : $*Int |
| %2 = load [trivial] %1 : $*Int |
| dealloc_stack %1 : $*Int |
| return %2 : $Int |
| } |
| |
| // CHECK-LABEL: sil [ossa] @mem2reg_struct_addr : |
| // CHECK-NOT: alloc_stack |
| // CHECK: struct_extract |
| // CHECK-LABEL: } // end sil function 'mem2reg_struct_addr' |
| sil [ossa] @mem2reg_struct_addr : $@convention(thin) (Int64) -> Builtin.Int64 { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $Int64 |
| store %0 to [trivial] %1 : $*Int64 |
| %2 = struct_element_addr %1 : $*Int64, #Int64._value |
| %3 = load [trivial] %2 : $*Builtin.Int64 |
| dealloc_stack %1 : $*Int64 |
| return %3 : $Builtin.Int64 |
| } |
| |
| // CHECK-LABEL: sil [ossa] @mem2reg_tuple_addr : |
| // CHECK-NOT: alloc_stack |
| // CHECK: tuple_extract {{.*}}, 0 |
| // CHECK-LABEL: } // end sil function 'mem2reg_tuple_addr' |
| sil [ossa] @mem2reg_tuple_addr : $@convention(thin) (Int64) -> Int64 { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $(Int64, Int64) |
| %2 = tuple (%0 : $Int64, %0 : $Int64) |
| store %2 to [trivial] %1 : $*(Int64, Int64) |
| %4 = tuple_element_addr %1 : $*(Int64, Int64), 0 |
| %5 = load [trivial] %4 : $*Int64 |
| dealloc_stack %1 : $*(Int64, Int64) |
| return %5 : $Int64 |
| } |
| |
| // CHECK-LABEL: sil [ossa] @struct_extract_if_then_else : |
| // CHECK-NOT: alloc_stack |
| sil [ossa] @struct_extract_if_then_else : $@convention(thin) (Int64) -> Int64 { |
| bb0(%0 : $Int64): |
| %1 = alloc_stack $Int64 |
| store %0 to [trivial] %1 : $*Int64 |
| %3 = integer_literal $Builtin.Int64, 2 |
| %4 = struct_extract %0 : $Int64, #Int64._value |
| %5 = builtin "cmp_sgt_Int64"(%4 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1 |
| %6 = struct_element_addr %1 : $*Int64, #Int64._value |
| cond_br %5, bb1, bb2 |
| |
| // CHECK: bb1: |
| // CHECK: struct_extract %0 |
| bb1: |
| %8 = load [trivial] %6 : $*Builtin.Int64 |
| %9 = integer_literal $Builtin.Int64, 1 |
| %10 = integer_literal $Builtin.Int1, 0 |
| %11 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %9 : $Builtin.Int64, %10 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) |
| %12 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 0 |
| br bb3(%12 : $Builtin.Int64) |
| |
| // CHECK: bb2: |
| // CHECK: struct_extract %0 |
| bb2: |
| %14 = load [trivial] %6 : $*Builtin.Int64 |
| %15 = integer_literal $Builtin.Int64, 2 |
| %16 = integer_literal $Builtin.Int1, 0 |
| %17 = builtin "sadd_with_overflow_Int64"(%14 : $Builtin.Int64, %15 : $Builtin.Int64, %16 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) |
| %18 = tuple_extract %17 : $(Builtin.Int64, Builtin.Int1), 0 |
| br bb3(%18 : $Builtin.Int64) |
| |
| // CHECK-NOT: dealloc_stack |
| bb3(%20 : $Builtin.Int64): |
| dealloc_stack %1 : $*Int64 |
| %22 = struct $Int64 (%20 : $Builtin.Int64) |
| return %22 : $Int64 |
| } |
| // CHECK-LABEL: } // end sil function 'struct_extract_if_then_else' |
| |
| sil [ossa] @first : $@convention(thin) () -> Int |
| sil [ossa] @second : $@convention(thin) () -> Int |
| |
| // CHECK: sil [ossa] @promote_function_refs : |
| sil [ossa] @promote_function_refs : $@convention(thin) (Bool) -> Int { |
| // CHECK: bb0 |
| bb0(%0 : $Bool): |
| // CHECK-NOT: [[STACK:%.*]] = alloc_stack |
| %1 = alloc_stack $@callee_owned () -> Int |
| debug_value %0 : $Bool |
| %3 = struct_extract %0 : $Bool, #Bool._value |
| cond_br %3, bb1, bb2 |
| |
| // CHECK: bb1 |
| bb1: |
| // CHECK: [[FIRSTREF:%.*]] = function_ref @first |
| %5 = function_ref @first : $@convention(thin) () -> Int |
| // CHECK: [[FIRSTTHICK:%.*]] = thin_to_thick_function [[FIRSTREF]] |
| %6 = thin_to_thick_function %5 : $@convention(thin) () -> Int to $@callee_owned () -> Int |
| // CHECK-NOT: store |
| store %6 to [init] %1 : $*@callee_owned () -> Int |
| // CHECK: br bb3([[FIRSTTHICK]] : $@callee_owned () -> Int |
| br bb3 |
| |
| // CHECK: bb2 |
| bb2: |
| // CHECK: [[SECONDREF:%.*]] = function_ref @second |
| %9 = function_ref @second : $@convention(thin) () -> Int |
| // CHECK: [[SECONDTHICK:%.*]] = thin_to_thick_function [[SECONDREF]] |
| %10 = thin_to_thick_function %9 : $@convention(thin) () -> Int to $@callee_owned () -> Int |
| // CHECK-NOT: store |
| store %10 to [init] %1 : $*@callee_owned () -> Int |
| // CHECK: br bb3([[SECONDTHICK]] : $@callee_owned () -> Int) |
| br bb3 |
| |
| // CHECK: bb3([[ARG:%.*]] : @owned $@callee_owned () -> Int): |
| bb3: |
| // CHECK-NOT: load [[STACK]] |
| %13 = load [copy] %1 : $*@callee_owned () -> Int |
| // CHECK: [[COPY:%.*]] = copy_value [[ARG]] |
| // CHECK: [[RESULT:%.*]] = apply [[COPY]] |
| %15 = apply %13() : $@callee_owned () -> Int |
| br bb4 |
| |
| // NOTE: This block and the branch above exist to ensure that we |
| // test what happens when %1 hasn't already been loaded in this |
| // block. |
| // CHECK: bb4 |
| bb4: |
| // CHECK-NOT: destroy_addr [[STACK]] |
| // CHECK: destroy_value [[ARG]] |
| destroy_addr %1 : $*@callee_owned () -> Int |
| // CHECK-NOT: dealloc_stack [[STACK]] |
| dealloc_stack %1 : $*@callee_owned () -> Int |
| return %15 : $Int |
| } |
| // CHECK-LABEL: } // end sil function 'promote_function_refs' |
| |
| // Test cases where the only use is a debug_value_addr |
| // CHECK-LABEL: sil [ossa] @no_real_uses : |
| sil [ossa] @no_real_uses : $@convention(thin) () -> () { |
| // CHECK: bb0 |
| bb0: |
| // CHECK-NOT: alloc_stack |
| %0 = alloc_stack $Builtin.Int32 |
| // CHECK-NOT: debug_value_addr |
| debug_value_addr %0 : $*Builtin.Int32, let, name "x", argno 1 |
| // CHECK-NOT: dealloc_stack |
| dealloc_stack %0 : $*Builtin.Int32 |
| %1 = tuple () |
| return %1 : $() |
| } |
| // CHECK-LABEL: } // end sil function 'no_real_uses' |
| |
| // CHECK-LABEL: sil [ossa] @keep_release : |
| // CHECK: destroy_value %0 |
| // CHECK-LABEL: } // end sil function 'keep_release' |
| sil [ossa] @keep_release : $@convention(thin) (@owned AnyObject) -> () { |
| bb0(%0 : @owned $AnyObject): |
| %1 = alloc_stack $AnyObject |
| store %0 to [init] %1 : $*AnyObject |
| destroy_addr %1 : $*AnyObject |
| dealloc_stack %1 : $*AnyObject |
| %7 = tuple () |
| return %7 : $() |
| } |
| |
| // Test cases where there are dead address instructions. |
| // CHECK-LABEL: sil [ossa] @dead_use : |
| // CHECK-NOT: alloc_stack |
| // CHECK-LABEL: } // end sil function 'dead_use' |
| sil [ossa] @dead_use : $@convention(thin) () -> () { |
| %0 = alloc_stack $Int64 |
| %1 = struct_element_addr %0 : $*Int64, #Int64._value |
| dealloc_stack %0 : $*Int64 |
| %2 = alloc_stack $(Int64, Int64) |
| %3 = tuple_element_addr %2 : $*(Int64, Int64), 0 |
| dealloc_stack %2 : $*(Int64, Int64) |
| %4 = tuple () |
| return %4 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_crash_on_dead_arg_use : |
| // CHECK: bb0{{.*}}: |
| // CHECK: tuple () |
| // CHECK-LABEL: } // end sil function 'dont_crash_on_dead_arg_use' |
| sil [ossa] @dont_crash_on_dead_arg_use : $@convention(thin) (@inout Int64) -> () { |
| bb0(%0 : $*Int64): |
| %2 = alloc_stack $Int64 |
| %1 = struct_element_addr %0 : $*Int64, #Int64._value |
| %3 = struct_element_addr %2 : $*Int64, #Int64._value |
| dealloc_stack %2 : $*Int64 |
| %4 = tuple () |
| return %4 : $() |
| } |
| |
| // Make sure that we do expand destroy_addr appropriately for code-size |
| // trade-offs. |
| // CHECK-LABEL: sil [ossa] @large_struct_test : |
| // CHECK: bb0([[ARG0:%.*]] : @owned $LargeCodesizeStruct): |
| // CHECK: destroy_value [[ARG0]] |
| // CHECK: } // end sil function 'large_struct_test' |
| sil [ossa] @large_struct_test : $@convention(thin) (@owned LargeCodesizeStruct) -> () { |
| bb0(%0 : @owned $LargeCodesizeStruct): |
| %1 = alloc_stack $LargeCodesizeStruct |
| store %0 to [init] %1 : $*LargeCodesizeStruct |
| destroy_addr %1 : $*LargeCodesizeStruct |
| dealloc_stack %1 : $*LargeCodesizeStruct |
| %7 = tuple () |
| return %7 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @small_struct_test : |
| // CHECK: bb0([[ARG0:%.*]] : @owned $SmallCodesizeStruct): |
| // CHECK: ([[ELEM1:%[0-9]+]], [[ELEM2:%[0-9]+]]) = destructure_struct [[ARG0]] |
| // CHECK: destroy_value [[ELEM1]] |
| // CHECK: destroy_value [[ELEM2]] |
| // CHECK: } // end sil function 'small_struct_test' |
| sil [ossa] @small_struct_test : $@convention(thin) (@owned SmallCodesizeStruct) -> () { |
| bb0(%0 : @owned $SmallCodesizeStruct): |
| %1 = alloc_stack $SmallCodesizeStruct |
| store %0 to [init] %1 : $*SmallCodesizeStruct |
| destroy_addr %1 : $*SmallCodesizeStruct |
| dealloc_stack %1 : $*SmallCodesizeStruct |
| %7 = tuple () |
| return %7 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @small_struct_multi_test : |
| // CHECK-NOT: alloc_stack |
| // CHECK: [[COPY:%.*]] = copy_value %0 |
| // CHECK-NEXT: destructure_struct %0 |
| // CHECK-NEXT: destroy_value |
| // CHECK-NEXT: destroy_value |
| // CHECK-NEXT: begin_borrow [[COPY]] |
| // CHECK-NEXT: debug_value |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: destroy_value [[COPY]] |
| // CHECK: bb2: |
| // CHECK-NEXT: destructure_struct %0 |
| // CHECK-NEXT: destroy_value |
| // CHECK-NEXT: destroy_value |
| // CHECK-LABEL: } // end sil function 'small_struct_multi_test' |
| sil [ossa] @small_struct_multi_test : $@convention(thin) (@owned SmallCodesizeStruct) -> () { |
| bb0(%0 : @owned $SmallCodesizeStruct): |
| %1 = alloc_stack $SmallCodesizeStruct |
| store %0 to [init] %1 : $*SmallCodesizeStruct |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %3 = load [copy] %1 : $*SmallCodesizeStruct |
| destroy_addr %1 : $*SmallCodesizeStruct |
| dealloc_stack %1 : $*SmallCodesizeStruct |
| %4 = begin_borrow %3 : $SmallCodesizeStruct |
| debug_value %4 : $SmallCodesizeStruct |
| end_borrow %4 : $SmallCodesizeStruct |
| destroy_value %3 : $SmallCodesizeStruct |
| br bb3 |
| |
| bb2: |
| destroy_addr %1 : $*SmallCodesizeStruct |
| dealloc_stack %1 : $*SmallCodesizeStruct |
| br bb3 |
| |
| bb3: |
| %7 = tuple () |
| return %7 : $() |
| } |
| |
| |
| // CHECK-LABEL: sil [ossa] @dead_address_projections : |
| // CHECK-NOT: alloc_stack |
| // CHECK: } // end sil function 'dead_address_projections' |
| sil [ossa] @dead_address_projections : $@convention(thin) (((), ())) -> ((), ()) { |
| bb0(%0 : $((), ())): |
| %1 = alloc_stack $((), ()) |
| %200 = tuple_element_addr %1 : $*((), ()), 0 |
| %300 = tuple_element_addr %1 : $*((), ()), 1 |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| store %0 to [trivial] %1 : $*((), ()) |
| %16 = load [trivial] %1 : $*((), ()) |
| dealloc_stack %1 : $*((), ()) |
| br bb3(%16 : $((), ())) |
| |
| bb2: |
| dealloc_stack %1 : $*((), ()) |
| br bb3(%0 : $((), ())) |
| |
| bb3(%20 : $((), ())): |
| return %20 : $((), ()) |
| } |
| |
| // CHECK-LABEL: sil [ossa] @load_tuple_of_void : |
| // CHECK-NOT: alloc_stack |
| // CHECK: return undef : $((), ()) |
| // CHECK: } // end sil function 'load_tuple_of_void' |
| sil [ossa] @load_tuple_of_void : $@convention(thin) () -> ((), ()) { |
| bb0: |
| %1 = alloc_stack $((), ()) |
| %16 = load [trivial] %1 : $*((), ()) |
| dealloc_stack %1 : $*((), ()) |
| return %16 : $((), ()) |
| } |