Files
clang-p2996/clang/test/CodeGenCXX/nrvo.cpp
Arthur Eubanks cb5a10199b [test] Remove tests pinned to the legacy PM
Now that the legacy PM is deprecated for the optimization pipeline, we
can start deleting legacy PM tests.

For tests that test both PMs, merge the RUN lines.
Delete tests specific to the legacy PM.
2021-10-18 16:40:46 -07:00

222 lines
5.9 KiB
C++

// 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 -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
// Test code generation for the named return value optimization.
class X {
public:
X();
X(const X&);
~X();
};
template<typename T> struct Y {
Y();
static Y f() {
Y y;
return y;
}
};
// CHECK-LABEL: define{{.*}} void @_Z5test0v
// CHECK-EH-LABEL: define{{.*}} void @_Z5test0v
X test0() {
X x;
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: ret void
// CHECK-EH: call {{.*}} @_ZN1XC1Ev
// CHECK-EH-NEXT: ret void
return x;
}
// CHECK-LABEL: define{{.*}} void @_Z5test1b(
// CHECK-EH-LABEL: define{{.*}} void @_Z5test1b(
X test1(bool B) {
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: ret void
X x;
if (B)
return (x);
return x;
// CHECK-EH: call {{.*}} @_ZN1XC1Ev
// CHECK-EH-NEXT: ret void
}
// CHECK-LABEL: define{{.*}} void @_Z5test2b
// CHECK-EH-LABEL: define{{.*}} void @_Z5test2b
// CHECK-EH-SAME: personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
X test2(bool B) {
// No NRVO.
X x;
X y;
if (B)
return y;
return x;
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: {{.*}} getelementptr inbounds %class.X, %class.X* %y, i32 0, i32 0
// CHECK-NEXT: call void @llvm.lifetime.start
// CHECK-NEXT: call {{.*}} @_ZN1XC1Ev
// CHECK: call {{.*}} @_ZN1XC1ERKS_
// CHECK: call {{.*}} @_ZN1XD1Ev
// CHECK-NEXT: call void @llvm.lifetime.end
// CHECK: call {{.*}} @_ZN1XD1Ev
// CHECK-NEXT: call void @llvm.lifetime.end
// CHECK: ret void
// The block ordering in the -fexceptions IR is unfortunate.
// CHECK-EH: call void @llvm.lifetime.start
// CHECK-EH-NEXT: call {{.*}} @_ZN1XC1Ev
// CHECK-EH: call void @llvm.lifetime.start
// CHECK-EH-NEXT: invoke {{.*}} @_ZN1XC1Ev
// -> %invoke.cont, %lpad
// %invoke.cont:
// CHECK-EH: br i1
// -> %if.then, %if.end
// %if.then: returning 'x'
// CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
// -> %cleanup, %lpad1
// %lpad: landing pad for ctor of 'y', dtor of 'y'
// CHECK-EH: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-NEXT: cleanup
// CHECK-EH-NEXT: br label
// -> %eh.cleanup
// %lpad1: landing pad for return copy ctors, EH cleanup for 'y'
// CHECK-EH-03: invoke {{.*}} @_ZN1XD1Ev
// -> %eh.cleanup, %terminate.lpad
// CHECK-EH-11: call {{.*}} @_ZN1XD1Ev
// %if.end: returning 'y'
// CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
// -> %cleanup, %lpad1
// %cleanup: normal cleanup for 'y'
// CHECK-EH-03: invoke {{.*}} @_ZN1XD1Ev
// -> %invoke.cont11, %lpad
// CHECK-EH-11: call {{.*}} @_ZN1XD1Ev
// %invoke.cont11: normal cleanup for 'x'
// CHECK-EH: call void @llvm.lifetime.end
// CHECK-EH-NEXT: call {{.*}} @_ZN1XD1Ev
// CHECK-EH-NEXT: call void @llvm.lifetime.end
// CHECK-EH-NEXT: ret void
// %eh.cleanup: EH cleanup for 'x'
// CHECK-EH-03: invoke {{.*}} @_ZN1XD1Ev
// -> %invoke.cont17, %terminate.lpad
// CHECK-EH-11: call {{.*}} @_ZN1XD1Ev
// %invoke.cont17: rethrow block for %eh.cleanup.
// This really should be elsewhere in the function.
// CHECK-EH: resume { i8*, i32 }
// %terminate.lpad: terminate landing pad.
// CHECK-EH-03: [[T0:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-03-NEXT: catch i8* null
// CHECK-EH-03-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[T1]]) [[NR_NUW:#[0-9]+]]
// CHECK-EH-03-NEXT: unreachable
}
// CHECK-LABEL: define{{.*}} void @_Z5test3b
X test3(bool B) {
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NOT: call {{.*}} @_ZN1XC1ERKS_
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK: call {{.*}} @_ZN1XC1ERKS_
if (B) {
X y;
return y;
}
// FIXME: we should NRVO this variable too.
X x;
return x;
}
extern "C" void exit(int) throw();
// CHECK-LABEL: define{{.*}} void @_Z5test4b
X test4(bool B) {
{
// CHECK: call {{.*}} @_ZN1XC1Ev
X x;
// CHECK: br i1
if (B)
return x;
}
// CHECK: call {{.*}} @_ZN1XD1Ev
// CHECK: call void @exit(i32 1)
exit(1);
}
#ifdef __EXCEPTIONS
// CHECK-EH-LABEL: define{{.*}} void @_Z5test5
void may_throw();
X test5() {
try {
may_throw();
} catch (X x) {
// CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
// CHECK-EH: call void @__cxa_end_catch()
// CHECK-EH: ret void
return x;
}
}
#endif
// rdar://problem/10430868
// CHECK-LABEL: define{{.*}} void @_Z5test6v
X test6() {
X a __attribute__((aligned(8)));
return a;
// CHECK: [[A:%.*]] = alloca [[X:%.*]], align 8
// CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds %class.X, %class.X* [[A]], i32 0, i32 0
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[PTR]])
// CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* {{[^,]*}} [[A]])
// CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{[^,]*}} {{%.*}}, [[X]]* nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[A]])
// CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* {{[^,]*}} [[A]])
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[PTR]])
// CHECK-NEXT: ret void
}
// CHECK-LABEL: define{{.*}} void @_Z5test7b
X test7(bool b) {
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: ret
if (b) {
X x;
return x;
}
return X();
}
// CHECK-LABEL: define{{.*}} void @_Z5test8b
X test8(bool b) {
// CHECK: call {{.*}} @_ZN1XC1Ev
// CHECK-NEXT: ret
if (b) {
X x;
return x;
} else {
X y;
return y;
}
}
Y<int> test9() {
Y<int>::f();
}
// CHECK-LABEL: define linkonce_odr void @_ZN1YIiE1fEv
// CHECK: call {{.*}} @_ZN1YIiEC1Ev
// CHECK-EH-03: attributes [[NR_NUW]] = { noreturn nounwind }