diff options
| author | Arnaud A. de Grandmaison <arnaud.degrandmaison@arm.com> | 2014-10-02 12:19:51 +0000 |
|---|---|---|
| committer | Arnaud A. de Grandmaison <arnaud.degrandmaison@arm.com> | 2014-10-02 12:19:51 +0000 |
| commit | 42d314d1ba7fd02da1784c2a2e26e7a91a6ef1b4 (patch) | |
| tree | 210dca4280865c7a7848760ce67e68e2559eb43e /clang/test | |
| parent | 4ae7f2e839957dbb1f7bc38f524adf6c6d4b416a (diff) | |
| download | bcm5719-llvm-42d314d1ba7fd02da1784c2a2e26e7a91a6ef1b4.tar.gz bcm5719-llvm-42d314d1ba7fd02da1784c2a2e26e7a91a6ef1b4.zip | |
Emit lifetime.start / lifetime.end markers for unnamed temporary objects.
This will give more information to the optimizers so that they can reuse stack slots
and reduce stack usage.
llvm-svn: 218865
Diffstat (limited to 'clang/test')
| -rw-r--r-- | clang/test/CodeGenCXX/unnamed-object-lifetime.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/clang/test/CodeGenCXX/unnamed-object-lifetime.cpp b/clang/test/CodeGenCXX/unnamed-object-lifetime.cpp new file mode 100644 index 00000000000..22a64bcd4d5 --- /dev/null +++ b/clang/test/CodeGenCXX/unnamed-object-lifetime.cpp @@ -0,0 +1,290 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s + +// Test lifetime marker generation for unnamed temporary objects. + +struct X { + X(); + ~X(); + char t[33]; // make the class big enough so that lifetime markers get inserted +}; + +extern void useX(const X &); + +// CHECK-LABEL: define void @_Z6simplev +// CHECK-EH-LABEL: define void @_Z6simplev +void simple() { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-NEXT: call void @_ZN1XC1Ev + // CHECK-NEXT: call void @_Z4useXRK1X + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-EH-NEXT: call void @_ZN1XC1Ev + // CHECK-EH: invoke void @_Z4useXRK1X + // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + useX(X()); +} + +// Same as above, but with a sub-scope +// CHECK-LABEL: define void @_Z6simpleb +// CHECK-EH-LABEL: define void @_Z6simpleb +void simple(bool b) { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK: br i1 %b + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-NEXT: call void @_ZN1XC1Ev + // CHECK-NEXT: call void @_Z4useXRK1X + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.X + // CHECK-EH: br i1 %b + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.X* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[PTR]]) + // CHECK-EH-NEXT: call void @_ZN1XC1Ev + // CHECK-EH: invoke void @_Z4useXRK1X + // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]]) + if (b) { + useX(X()); + } +} + +struct Y { + Y(){} + ~Y(){} + char t[34]; // make the class big enough so that lifetime markers get inserted +}; + +extern void useY(const Y &); + +// Check lifetime markers are inserted, despite Y's trivial constructor & destructor +// CHECK-LABEL: define void @_Z7trivialv +// CHECK-EH-LABEL: define void @_Z7trivialv +void trivial() { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-NEXT: call void @_Z4useYRK1Y + // CHECK-NEXT: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-EH-NEXT: invoke void @_Z4useYRK1Y + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + useY(Y()); +} + +// Same as above, but with a sub-scope +// CHECK-LABEL: define void @_Z7trivialb +// CHECK-EH-LABEL: define void @_Z7trivialb +void trivial(bool b) { + // CHECK: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK: br i1 %b + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-NEXT: call void @_Z4useYRK1Y + // CHECK-NEXT: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.Y + // CHECK-EH: br i1 %b + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.Y* [[ALLOCA]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[PTR]]) + // CHECK-EH-NEXT: invoke void @_Z4useYRK1Y + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]]) + if (b) { + useY(Y()); + } +} + +struct Z { + Z(); + ~Z(); + char t; +}; + +extern void useZ(const Z &); + +// Check lifetime markers are not inserted if the unnamed object is too small +// CHECK-LABEL: define void @_Z8tooSmallv +// CHECK-EH-LABEL: define void @_Z8tooSmallv +void tooSmall() { + // CHECK-NOT: call void @llvm.lifetime.start + // CHECK: call void @_Z4useZRK1Z + // CHECK-NOT: call void @llvm.lifetime.end + // CHECK: ret + // + // CHECK-EH-NOT: call void @llvm.lifetime.start + // CHECK-EH: invoke void @_Z4useZRK1Z + // CHECK-EH-NOT: call void @llvm.lifetime.end + // CHECK-EH: ret + useZ(Z()); +} + +// Check the lifetime are inserted at the right place in their respective scope +// CHECK-LABEL: define void @_Z6scopesv +// CHECK-EH-LABEL: define void @_Z6scopesv +void scopes() { + // CHECK: alloca %struct + // CHECK: alloca %struct + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[X:%.*]]) + // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[X]]) + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[Y:%.*]]) + // CHECK: call void @llvm.lifetime.end(i64 34, i8* [[Y]]) + // + // CHECK-EH: alloca %struct + // CHECK-EH: alloca %struct + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[X:%.*]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[X]]) + // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[Y:%.*]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[Y]]) + useX(X()); + useY(Y()); +} + +struct L { + L(int); + ~L(); + char t[33]; +}; + +// Check the lifetime-extended case, with a non trivial destructor +// and a top level scope +// CHECK-LABEL: define void @_Z16extendedLifetimev +// CHECK-EH-LABEL: define void @_Z16extendedLifetimev +void extendedLifetime() { + extern void useL(const L&); + + // CHECK: [[A:%.*]] = alloca %struct.L + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK: call void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK: call void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // + // CHECK-EH: [[A:%.*]] = alloca %struct.L + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-EH-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: invoke void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + const L &l = 2; + useL(l); +} + +// Check the lifetime-extended case, with a non trivial destructor in a +// sub-scope +// CHECK-LABEL: define void @_Z16extendedLifetimeb +// CHECK-EH-LABEL: define void @_Z16extendedLifetimeb +void extendedLifetime(bool b) { + extern void useL(const L&); + + // CHECK: [[A:%.*]] = alloca %struct.L + // CHECK: br i1 %b + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK: call void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK: call void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // + // CHECK-EH: [[A:%.*]] = alloca %struct.L + // CHECK-EH: br i1 %b + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2) + // CHECK-EH-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: invoke void @_Z4useLRK1L(%struct.L* dereferenceable(33) [[A]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + if (b) { + const L &l = 2; + useL(l); + } +} + +struct T { + T(); + T(int); + char t[33]; +}; + +// Check the lifetime-extended case, with a trivial destructor, +// in a sub-scope +// CHECK-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorb +// CHECK-EH-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorb +void extendedLifetimeWithTrivialDestructor(bool b) { + extern void useT(const T &); + + // CHECK: [[A:%.*]] = alloca %struct.T + // CHECK: br i1 %b + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 2) + // CHECK: call void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK: br label + // + // CHECK-EH: [[A:%.*]] = alloca %struct.T + // CHECK-EH: br i1 %b + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 2) + // CHECK-EH: invoke void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH-NEXT: resume + if (b) { + const T &t = 2; + useT(t); + } +} + +// Check the lifetime-extended case, with a trivial destructor and a top level +// scope +// CHECK-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorv +// CHECK-EH-LABEL: define void @_Z37extendedLifetimeWithTrivialDestructorv +void extendedLifetimeWithTrivialDestructor() { + extern void useT(const T &); + + // CHECK: [[A:%.*]] = alloca %struct.T + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 3) + // CHECK: call void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-NEXT: ret + // + // CHECK-EH: [[A:%.*]] = alloca %struct.T + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.T* [[A]], i32 0, i32 0, i32 0 + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]]) + // CHECK-EH: call void @_ZN1TC1Ei(%struct.T* [[A]], i32 3) + // CHECK-EH: invoke void @_Z4useTRK1T(%struct.T* dereferenceable(33) [[A]]) + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH-NEXT: ret + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]]) + // CHECK-EH-NEXT: resume + const T &t = 3; + useT(t); +} |

