// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf %s -o - -emit-llvm -O2 | FileCheck %s
// 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);
Combiner f();
};
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
// CHECK: [[T2:%.*]] = alloca %struct.Combiner
// CHECK: [[T1:%.*]] = alloca %struct.Combiner
// CHECK: [[T3:%.*]] = call noundef ptr @_ZN8CombinerC1E7S_large(ptr {{[^,]*}} [[T1]], [9 x i32] %s.coerce)
// CHECK: call void @_ZN8Combiner1fEv(ptr dead_on_unwind nonnull writable sret(%struct.Combiner) align 4 [[T2]], ptr {{[^,]*}} [[T1]])
// CHECK: [[T5:%.*]] = load i32, ptr [[T2]]
// CHECK: ret i32 [[T5]]
return Combiner(s).f().a.a[0];
}
}