mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This is done by splitting the `begin_borrow` of the whole struct into individual borrows of the fields (for trivial fields no borrow is needed). And then sinking the `struct` to it's consuming use(s). ``` %3 = struct $S(%nonTrivialField, %trivialField) // owned ... %4 = begin_borrow %3 %5 = struct_extract %4, #S.nonTrivialField %6 = struct_extract %4, #S.trivialField use %5, %6 end_borrow %4 ... end_of_lifetime %3 ``` -> ``` ... %5 = begin_borrow %nonTrivialField use %5, %trivialField end_borrow %5 ... %3 = struct $S(%nonTrivialField, %trivialField) end_of_lifetime %3 ``` This optimization is important for Array code where the Array buffer is constantly wrapped into structs and then extracted again to access the buffer.
202 lines
5.4 KiB
Plaintext
202 lines
5.4 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] @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: 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
|
|
unreachable
|
|
}
|
|
|