llvm-project/clang/test/CodeGenCXX/stack-reuse.cpp
Eric Christopher fd39b1bb20 Revert "Revert "As a follow-up to my initial mail to llvm-dev here's a first pass at the O1 described there.""
This reapplies: 8ff85ed905a7306977d07a5cd67ab4d5a56fafb4

Original commit message:

As a follow-up to my initial mail to llvm-dev here's a first pass at the O1 described there.

This change doesn't include any change to move from selection dag to fast isel
and that will come with other numbers that should help inform that decision.
There also haven't been any real debuggability studies with this pipeline yet,
this is just the initial start done so that people could see it and we could start
tweaking after.

Test updates: Outside of the newpm tests most of the updates are coming from either
optimization passes not run anymore (and without a compelling argument at the moment)
that were largely used for canonicalization in clang.

Original post:

http://lists.llvm.org/pipermail/llvm-dev/2019-April/131494.html

Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65410

This reverts commit c9ddb02659e3ece7a0d9d6b4dac7ceea4ae46e6d.
2019-11-26 20:28:52 -08:00

147 lines
3.7 KiB
C++

// 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 %struct.Combiner* @_ZN8CombinerC1E7S_large(%struct.Combiner* nonnull [[T1]], [9 x i32] %s.coerce)
// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret [[T2]], %struct.Combiner* nonnull [[T1]])
// 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]]
return Combiner(s).f().a.a[0];
}
}