mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
For now I am trying out /not/ expanding when ownership is enabled. I still fixed the problems in it though. I also put in a force expand everything pass to make sure that in ossa we can still successfully go down this code path if we want to. The reason why I think this is the right thing to do is that the original reason why lower aggregate instrs was written was to help the low level arc optimizer (which only runs on non-ossa code). To the high level arc optimizer this is just noise and will keep the IR simpler. Another thing to note is that I updated the code so it should work in both ossa and non-ossa. In order to not perturb the code too much, I had to add a small optimization to TypeLowering where when ownership is disabled, we do not reform aggregates when copying. Instead, we just return the passed in value. This makes the pass the same when optimizing in both modes.
128 lines
4.3 KiB
Plaintext
128 lines
4.3 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all %s -lower-aggregate-instrs | %FileCheck %s
|
|
|
|
// This file makes sure that given the current code-size metric we properly
|
|
// expand operations for small structs and not for large structs in a consistent
|
|
// way for all operations we expand.
|
|
|
|
sil_stage canonical
|
|
|
|
import Swift
|
|
import Builtin
|
|
|
|
class C1 {
|
|
var data : Builtin.Int64
|
|
init()
|
|
}
|
|
|
|
class C2 {
|
|
var data : Builtin.FPIEEE32
|
|
init()
|
|
}
|
|
|
|
class C3 {
|
|
var data : Builtin.FPIEEE64
|
|
init()
|
|
}
|
|
|
|
struct S2 {
|
|
var cls1 : C1
|
|
var cls2 : C2
|
|
var trivial : Builtin.FPIEEE32
|
|
}
|
|
|
|
struct S {
|
|
var trivial : Builtin.Int64
|
|
var cls : C3
|
|
var inner_struct : S2
|
|
}
|
|
|
|
enum E {
|
|
case NoElement
|
|
case TrivialElement(Builtin.Int64)
|
|
case ReferenceElement(C1)
|
|
case StructNonTrivialElt(S)
|
|
case TupleNonTrivialElt((Builtin.Int64, S, C3))
|
|
}
|
|
|
|
// This struct is larger than our current code-size limit (> 6 leaf nodes).
|
|
struct LargeStruct {
|
|
var trivial1 : Builtin.Int64
|
|
var cls : S
|
|
var trivial2 : Builtin.Int64
|
|
var trivial3 : Builtin.Int64
|
|
}
|
|
|
|
///////////
|
|
// Tests //
|
|
///////////
|
|
|
|
// This test makes sure that we /do not/ expand retain_value, release_value and
|
|
// promote copy_addr/destroy_value to non-expanded retain_value, release_value.
|
|
// CHECK-LABEL: sil @large_struct_test : $@convention(thin) (@owned LargeStruct, @in LargeStruct) -> () {
|
|
// CHECK: bb0([[ARG0:%.*]] : $LargeStruct, [[ARG1:%.*]] : $*LargeStruct):
|
|
// CHECK: retain_value [[ARG0]]
|
|
// CHECK: release_value [[ARG0]]
|
|
// CHECK: [[ALLOC_STACK:%.*]] = alloc_stack $LargeStruct
|
|
// CHECK: [[LOADED_ARG1:%.*]] = load [[ARG1]]
|
|
// CHECK: retain_value [[LOADED_ARG1]]
|
|
// CHECK: [[LOADED_OLD_VAL:%.*]] = load [[ALLOC_STACK]]
|
|
// CHECK: release_value [[LOADED_OLD_VAL]]
|
|
// CHECK: store [[LOADED_ARG1]] to [[ALLOC_STACK]]
|
|
// CHECK: [[LOADED_ARG1:%.*]] = load [[ARG1]]
|
|
// CHECK: release_value [[LOADED_ARG1]]
|
|
// CHECK: dealloc_stack [[ALLOC_STACK]]
|
|
// CHECK: } // end sil function 'large_struct_test'
|
|
sil @large_struct_test : $@convention(thin) (@owned LargeStruct, @in LargeStruct) -> () {
|
|
bb0(%0 : $LargeStruct, %1 : $*LargeStruct):
|
|
retain_value %0 : $LargeStruct
|
|
release_value %0 : $LargeStruct
|
|
%2 = alloc_stack $LargeStruct
|
|
copy_addr %1 to %2 : $*LargeStruct
|
|
destroy_addr %1 : $*LargeStruct
|
|
dealloc_stack %2 : $*LargeStruct
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @small_struct_test : $@convention(thin) (@owned S2, @in S2) -> () {
|
|
// CHECK: bb0([[ARG0:%.*]] : $S2, [[ARG1:%.*]] : $*S2):
|
|
// CHECK: [[ARG0cls1:%.*]] = struct_extract [[ARG0]] : $S2, #S2.cls1
|
|
// CHECK: strong_retain [[ARG0cls1]] : $C1
|
|
// CHECK: [[ARG0cls2:%.*]] = struct_extract [[ARG0]] : $S2, #S2.cls2
|
|
// CHECK: strong_retain [[ARG0cls2]] : $C2
|
|
// CHECK: [[ARG0cls1:%.*]] = struct_extract [[ARG0]] : $S2, #S2.cls1
|
|
// CHECK: strong_release [[ARG0cls1]] : $C1
|
|
// CHECK: [[ARG0cls2:%.*]] = struct_extract [[ARG0]] : $S2, #S2.cls2
|
|
// CHECK: strong_release [[ARG0cls2]] : $C2
|
|
//
|
|
// CHECK: [[ALLOC_STACK:%.*]] = alloc_stack $S2
|
|
// CHECK: [[LOADED_ARG1:%.*]] = load [[ARG1]]
|
|
// CHECK: [[LOADED_ARG1cls1:%.*]] = struct_extract [[LOADED_ARG1]] : $S2, #S2.cls1
|
|
// CHECK: strong_retain [[LOADED_ARG1cls1]] : $C1
|
|
// CHECK: [[LOADED_ARG1cls2:%.*]] = struct_extract [[LOADED_ARG1]] : $S2, #S2.cls2
|
|
// CHECK: strong_retain [[LOADED_ARG1cls2]] : $C2
|
|
|
|
// CHECK: [[LOADED_OLDVALUE:%.*]] = load [[ALLOC_STACK]]
|
|
// CHECK: [[LOADED_OLDVALUEcls1:%.*]] = struct_extract [[LOADED_OLDVALUE]] : $S2, #S2.cls1
|
|
// CHECK: strong_release [[LOADED_OLDVALUEcls1]] : $C1
|
|
// CHECK: [[LOADED_OLDVALUEcls2:%.*]] = struct_extract [[LOADED_OLDVALUE]] : $S2, #S2.cls2
|
|
// CHECK: strong_release [[LOADED_OLDVALUEcls2]] : $C2
|
|
//
|
|
// CHECK: [[LOADED_ARG1:%.*]] = load [[ARG1]]
|
|
// CHECK: [[LOADED_ARG1cls1:%.*]] = struct_extract [[LOADED_ARG1]] : $S2, #S2.cls1
|
|
// CHECK: strong_release [[LOADED_ARG1cls1]] : $C1
|
|
// CHECK: [[LOADED_ARG1cls2:%.*]] = struct_extract [[LOADED_ARG1]] : $S2, #S2.cls2
|
|
// CHECK: strong_release [[LOADED_ARG1cls2]] : $C2
|
|
// CHECK: } // end sil function 'small_struct_test'
|
|
sil @small_struct_test : $@convention(thin) (@owned S2, @in S2) -> () {
|
|
bb0(%0 : $S2, %1 : $*S2):
|
|
retain_value %0 : $S2
|
|
release_value %0 : $S2
|
|
%2 = alloc_stack $S2
|
|
copy_addr %1 to %2 : $*S2
|
|
destroy_addr %1 : $*S2
|
|
dealloc_stack %2 : $*S2
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|