2016-03-14 05:05:23 +08:00
|
|
|
// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf %s -o - -emit-llvm -O1 | FileCheck %s
|
2015-06-08 18:23:49 +08:00
|
|
|
|
|
|
|
// Stack should be reused when possible, no need to allocate two separate slots
|
|
|
|
// if they have disjoint lifetime.
|
|
|
|
|
|
|
|
// Sizes of objects are related to previously existed threshold of 32. In case
|
|
|
|
// of S_large stack size is rounded to 40 bytes.
|
|
|
|
|
|
|
|
// 32B
|
|
|
|
struct S_small {
|
|
|
|
int a[8];
|
|
|
|
};
|
|
|
|
|
|
|
|
// 36B
|
|
|
|
struct S_large {
|
|
|
|
int a[9];
|
|
|
|
};
|
|
|
|
|
|
|
|
// Helper class for lifetime scope absence testing
|
|
|
|
struct Combiner {
|
|
|
|
S_large a, b;
|
|
|
|
|
|
|
|
Combiner(S_large);
|
2016-03-14 05:05:23 +08:00
|
|
|
Combiner f();
|
2015-06-08 18:23:49 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
extern S_small foo_small();
|
|
|
|
extern S_large foo_large();
|
|
|
|
extern void bar_small(S_small*);
|
|
|
|
extern void bar_large(S_large*);
|
|
|
|
|
|
|
|
// Prevent mangling of function names.
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
void small_rvoed_unnamed_temporary_object() {
|
|
|
|
// CHECK-LABEL: define void @small_rvoed_unnamed_temporary_object
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_smallv
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_smallv
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
|
|
|
|
foo_small();
|
|
|
|
foo_small();
|
|
|
|
}
|
|
|
|
|
|
|
|
void large_rvoed_unnamed_temporary_object() {
|
|
|
|
// CHECK-LABEL: define void @large_rvoed_unnamed_temporary_object
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_largev
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_largev
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
|
|
|
|
foo_large();
|
|
|
|
foo_large();
|
|
|
|
}
|
|
|
|
|
|
|
|
void small_rvoed_named_temporary_object() {
|
|
|
|
// CHECK-LABEL: define void @small_rvoed_named_temporary_object
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_smallv
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_smallv
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
|
|
|
|
{
|
|
|
|
S_small s = foo_small();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
S_small s = foo_small();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void large_rvoed_named_temporary_object() {
|
|
|
|
// CHECK-LABEL: define void @large_rvoed_named_temporary_object
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_largev
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9foo_largev
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
|
|
|
|
{
|
|
|
|
S_large s = foo_large();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
S_large s = foo_large();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void small_auto_object() {
|
|
|
|
// CHECK-LABEL: define void @small_auto_object
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9bar_smallP7S_small
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9bar_smallP7S_small
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
|
|
|
|
{
|
|
|
|
S_small s;
|
|
|
|
bar_small(&s);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
S_small s;
|
|
|
|
bar_small(&s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void large_auto_object() {
|
|
|
|
// CHECK-LABEL: define void @large_auto_object
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9bar_largeP7S_large
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
// CHECK: call void @llvm.lifetime.start
|
|
|
|
// CHECK: call void @_Z9bar_largeP7S_large
|
|
|
|
// CHECK: call void @llvm.lifetime.end
|
|
|
|
|
|
|
|
{
|
|
|
|
S_large s;
|
|
|
|
bar_large(&s);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
S_large s;
|
|
|
|
bar_large(&s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int large_combiner_test(S_large s) {
|
|
|
|
// CHECK-LABEL: define i32 @large_combiner_test
|
2015-06-08 19:06:59 +08:00
|
|
|
// CHECK: [[T2:%.*]] = alloca %struct.Combiner
|
2016-12-05 15:49:14 +08:00
|
|
|
// CHECK: [[T1:%.*]] = alloca %struct.Combiner
|
2018-10-15 23:43:00 +08:00
|
|
|
// CHECK: [[T3:%.*]] = call %struct.Combiner* @_ZN8CombinerC1E7S_large(%struct.Combiner* nonnull [[T1]], [9 x i32] %s.coerce)
|
2015-06-17 04:24:06 +08:00
|
|
|
// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret [[T2]], %struct.Combiner* nonnull [[T1]])
|
2015-06-08 19:06:59 +08:00
|
|
|
// CHECK: [[T4:%.*]] = getelementptr inbounds %struct.Combiner, %struct.Combiner* [[T2]], i32 0, i32 0, i32 0, i32 0
|
|
|
|
// CHECK: [[T5:%.*]] = load i32, i32* [[T4]]
|
|
|
|
// CHECK: ret i32 [[T5]]
|
2015-06-08 18:23:49 +08:00
|
|
|
|
|
|
|
return Combiner(s).f().a.a[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|