Files
swift-mirror/test/SILOptimizer/simplify_struct.sil
Erik Eckstein 95ad832102 SimplifyStruct: split destructure_struct of copies
```
  %3 = struct $S(%1, %2)  // owned
  ...
  %4 = copy_value %3
  (%5, %6) = destructure_struct %5
```
->
```
  ...
  %5 = copy_value %1
  %6 = copy_value %2
```
2026-03-10 07:56:51 +01:00

240 lines
6.3 KiB
Plaintext

// RUN: %target-sil-opt %s -simplification -simplify-instruction=struct | %FileCheck %s
import Swift
import Builtin
struct S {
let a: String
let b: Int
}
struct Outer {
let s: S
}
// CHECK-LABEL: sil [ossa] @simple_delay_struct :
// CHECK: bb0
// CHECK-NEXT: [[B:%.*]] = begin_borrow %0
// CHECK-NEXT: fix_lifetime [[B]]
// CHECK-NEXT: fix_lifetime %1
// CHECK-NEXT: end_borrow [[B]]
// CHECK-NEXT: [[S:%.*]] = struct $S (%0, %1)
// CHECK-NEXT: destroy_value [[S]]
// CHECK: } // end sil function 'simple_delay_struct'
sil [ossa] @simple_delay_struct : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
debug_value %2, name "x"
%3 = begin_borrow %2
debug_value %3, name "x"
%4 = struct_extract %3, #S.a
%5 = struct_extract %3, #S.b
fix_lifetime %4
fix_lifetime %5
end_borrow %3
destroy_value %2
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @destructure_of_copy :
// CHECK: bb0(%0 : @owned $String, %1 : $Int):
// CHECK-NEXT: br bb1
// CHECK: bb1:
// CHECK-NEXT: [[C:%.*]] = copy_value %0
// CHECK-NEXT: fix_lifetime %1
// CHECK-NEXT: destroy_value [[C]]
// CHECK: bb3:
// CHECK-NEXT: [[S:%.*]] = struct $S (%0, %1)
// CHECK-NEXT: destroy_value [[S]]
// CHECK: } // end sil function 'destructure_of_copy'
sil [ossa] @destructure_of_copy : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
br bb1
bb1:
%4 = copy_value %2
debug_value %4, name "x"
(%6, %7) = destructure_struct %4
fix_lifetime %7
destroy_value %6
cond_br undef, bb2, bb3
bb2:
br bb1
bb3:
destroy_value %2
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @test_nested :
// CHECK: bb0
// CHECK-NEXT: [[B:%.*]] = begin_borrow %0
// CHECK-NEXT: fix_lifetime [[B]]
// CHECK-NEXT: fix_lifetime %1
// CHECK-NEXT: end_borrow [[B]]
// CHECK-NEXT: [[S:%.*]] = struct $S (%0, %1)
// CHECK-NEXT: [[OUTER:%.*]] = struct $Outer ([[S]])
// CHECK-NEXT: destroy_value [[OUTER]]
// CHECK: } // end sil function 'test_nested'
sil [ossa] @test_nested : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
%3 = struct $Outer (%2)
%4 = begin_borrow %3
%5 = struct_extract %4, #Outer.s
%6 = struct_extract %5, #S.a
%7 = struct_extract %5, #S.b
fix_lifetime %6
fix_lifetime %7
end_borrow %4
destroy_value %3
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @multi_lifetime_ends :
// CHECK: bb0
// CHECK-NEXT: [[B:%.*]] = begin_borrow %0
// CHECK-NEXT: fix_lifetime [[B]]
// CHECK-NEXT: fix_lifetime %1
// CHECK-NEXT: end_borrow [[B]]
// CHECK: bb1:
// CHECK-NEXT: [[S1:%.*]] = struct $S (%0, %1)
// CHECK-NEXT: destroy_value [[S1]]
// CHECK: bb2:
// CHECK-NEXT: [[S2:%.*]] = struct $S (%0, %1)
// CHECK-NEXT: destroy_value [[S2]]
// CHECK: } // end sil function 'multi_lifetime_ends'
sil [ossa] @multi_lifetime_ends : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
%3 = begin_borrow %2
%4 = struct_extract %3, #S.a
%5 = struct_extract %3, #S.b
fix_lifetime %4
fix_lifetime %5
end_borrow %3
cond_br undef, bb1, bb2
bb1:
destroy_value %2
br bb3
bb2:
destroy_value %2
br bb3
bb3:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @multi_borrows :
// CHECK: bb1:
// CHECK-NEXT: [[B:%.*]] = begin_borrow %0
// CHECK-NEXT: fix_lifetime [[B]]
// CHECK-NEXT: end_borrow [[B]]
// CHECK: bb2:
// CHECK-NEXT: fix_lifetime %1
// CHECK: bb3:
// CHECK-NEXT: [[S:%.*]] = struct $S (%0, %1)
// CHECK-NEXT: destroy_value [[S]]
// CHECK: } // end sil function 'multi_borrows'
sil [ossa] @multi_borrows : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
cond_br undef, bb1, bb2
bb1:
%3 = begin_borrow %2
%4 = struct_extract %3, #S.a
fix_lifetime %4
end_borrow %3
br bb3
bb2:
%7 = begin_borrow %2
%8 = struct_extract %7, #S.b
fix_lifetime %8
end_borrow %7
br bb3
bb3:
destroy_value %2
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @unknown_struct_use :
// CHECK: struct_extract
// CHECK: struct_extract
// CHECK: } // end sil function 'unknown_struct_use'
sil [ossa] @unknown_struct_use : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
fix_lifetime %2
%3 = begin_borrow %2
%4 = struct_extract %3, #S.a
%5 = struct_extract %3, #S.b
fix_lifetime %4
fix_lifetime %5
end_borrow %3
destroy_value %2
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @unknown_borrow_use :
// CHECK: struct_extract
// CHECK: struct_extract
// CHECK: } // end sil function 'unknown_borrow_use'
sil [ossa] @unknown_borrow_use : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
%3 = begin_borrow %2
fix_lifetime %3
%4 = struct_extract %3, #S.a
%5 = struct_extract %3, #S.b
fix_lifetime %4
fix_lifetime %5
end_borrow %3
destroy_value %2
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @no_borrows :
// CHECK: %2 = struct
// CHECK: destroy_value %2
// CHECK: } // end sil function 'no_borrows'
sil [ossa] @no_borrows : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
destroy_value %2
%r = tuple ()
return %r : $()
}
// TODO: remove this test once we require complete OSSA lifetimes
// CHECK-LABEL: sil [ossa] @incomplete_lifetimes :
// CHECK: bb0
// CHECK-NEXT: [[B:%.*]] = begin_borrow %0
// CHECK-NEXT: fix_lifetime [[B]]
// CHECK-NEXT: fix_lifetime %1
// CHECK-NEXT: end_borrow
// CHECK-NEXT: struct
// CHECK-NEXT: destroy_value [dead_end]
// CHECK-NEXT: unreachable
// CHECK: } // end sil function 'incomplete_lifetimes'
sil [ossa] @incomplete_lifetimes : $@convention(thin) (@owned String, Int) -> () {
bb0(%0 : @owned $String, %1 : $Int):
%2 = struct $S (%0, %1)
%3 = begin_borrow %2
%4 = struct_extract %3, #S.a
%5 = struct_extract %3, #S.b
fix_lifetime %4
fix_lifetime %5
end_borrow %3
destroy_value [dead_end] %2
unreachable
}