2012-10-24 20:22:56 +08:00
|
|
|
// 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
|
2010-05-15 14:46:45 +08:00
|
|
|
|
|
|
|
// Test code generation for the named return value optimization.
|
|
|
|
class X {
|
|
|
|
public:
|
|
|
|
X();
|
|
|
|
X(const X&);
|
|
|
|
~X();
|
|
|
|
};
|
|
|
|
|
2014-05-03 08:41:18 +08:00
|
|
|
template<typename T> struct Y {
|
|
|
|
Y();
|
|
|
|
static Y f() {
|
|
|
|
Y y;
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-08-15 14:47:53 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test0v
|
|
|
|
// CHECK-EH-LABEL: define void @_Z5test0v
|
2010-05-15 14:46:45 +08:00
|
|
|
X test0() {
|
|
|
|
X x;
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK: call {{.*}} @_ZN1XC1Ev
|
2010-07-06 09:34:17 +08:00
|
|
|
// CHECK-NEXT: ret void
|
|
|
|
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: call {{.*}} @_ZN1XC1Ev
|
2010-07-06 09:34:17 +08:00
|
|
|
// CHECK-EH-NEXT: ret void
|
2010-05-15 14:46:45 +08:00
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2013-08-15 14:47:53 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test1b(
|
|
|
|
// CHECK-EH-LABEL: define void @_Z5test1b(
|
2010-05-15 14:46:45 +08:00
|
|
|
X test1(bool B) {
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK: tail call {{.*}} @_ZN1XC1Ev
|
2010-07-06 09:34:17 +08:00
|
|
|
// CHECK-NEXT: ret void
|
2010-05-15 14:46:45 +08:00
|
|
|
X x;
|
|
|
|
if (B)
|
|
|
|
return (x);
|
|
|
|
return x;
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: tail call {{.*}} @_ZN1XC1Ev
|
2010-07-06 09:34:17 +08:00
|
|
|
// CHECK-EH-NEXT: ret void
|
2010-05-15 14:46:45 +08:00
|
|
|
}
|
|
|
|
|
2013-08-15 14:47:53 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test2b
|
|
|
|
// CHECK-EH-LABEL: define void @_Z5test2b
|
2015-06-18 04:53:19 +08:00
|
|
|
// CHECK-EH-SAME: personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
|
2010-05-15 14:46:45 +08:00
|
|
|
X test2(bool B) {
|
2010-07-06 09:34:17 +08:00
|
|
|
// No NRVO.
|
|
|
|
|
2010-05-15 14:46:45 +08:00
|
|
|
X x;
|
|
|
|
X y;
|
|
|
|
if (B)
|
|
|
|
return y;
|
|
|
|
return x;
|
2010-07-06 09:34:17 +08:00
|
|
|
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK: call {{.*}} @_ZN1XC1Ev
|
2015-04-23 05:38:15 +08:00
|
|
|
// CHECK-NEXT: {{.*}} getelementptr inbounds %class.X, %class.X* %y, i32 0, i32 0
|
|
|
|
// CHECK-NEXT: call void @llvm.lifetime.start
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-NEXT: call {{.*}} @_ZN1XC1Ev
|
|
|
|
// CHECK: call {{.*}} @_ZN1XC1ERKS_
|
|
|
|
// CHECK: call {{.*}} @_ZN1XC1ERKS_
|
|
|
|
// CHECK: call {{.*}} @_ZN1XD1Ev
|
2015-04-23 05:38:15 +08:00
|
|
|
// CHECK-NEXT: call void @llvm.lifetime.end
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK: call {{.*}} @_ZN1XD1Ev
|
2015-04-23 05:38:15 +08:00
|
|
|
// CHECK-NEXT: call void @llvm.lifetime.end
|
2010-05-15 14:46:45 +08:00
|
|
|
// CHECK: ret void
|
2010-07-06 09:34:17 +08:00
|
|
|
|
|
|
|
// The block ordering in the -fexceptions IR is unfortunate.
|
|
|
|
|
2015-04-23 05:38:15 +08:00
|
|
|
// CHECK-EH: call void @llvm.lifetime.start
|
|
|
|
// CHECK-EH-NEXT: call {{.*}} @_ZN1XC1Ev
|
|
|
|
// CHECK-EH: call void @llvm.lifetime.start
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH-NEXT: invoke {{.*}} @_ZN1XC1Ev
|
2010-07-14 04:32:21 +08:00
|
|
|
// -> %invoke.cont, %lpad
|
2010-07-06 09:34:17 +08:00
|
|
|
|
2010-07-14 04:32:21 +08:00
|
|
|
// %invoke.cont:
|
2010-07-06 09:34:17 +08:00
|
|
|
// CHECK-EH: br i1
|
|
|
|
// -> %if.then, %if.end
|
|
|
|
|
|
|
|
// %if.then: returning 'x'
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
|
2010-07-14 04:32:21 +08:00
|
|
|
// -> %cleanup, %lpad1
|
2010-07-06 09:34:17 +08:00
|
|
|
|
|
|
|
// %lpad: landing pad for ctor of 'y', dtor of 'y'
|
2015-06-18 04:53:19 +08:00
|
|
|
// CHECK-EH: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 }
|
2011-09-20 04:31:14 +08:00
|
|
|
// CHECK-EH-NEXT: cleanup
|
|
|
|
// CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 0
|
|
|
|
// CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 1
|
2010-07-06 09:34:17 +08:00
|
|
|
// CHECK-EH-NEXT: br label
|
|
|
|
// -> %eh.cleanup
|
|
|
|
|
2010-07-14 04:32:21 +08:00
|
|
|
// %lpad1: landing pad for return copy ctors, EH cleanup for 'y'
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
|
2010-07-06 09:34:17 +08:00
|
|
|
// -> %eh.cleanup, %terminate.lpad
|
|
|
|
|
|
|
|
// %if.end: returning 'y'
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
|
2010-07-14 04:32:21 +08:00
|
|
|
// -> %cleanup, %lpad1
|
2010-07-06 09:34:17 +08:00
|
|
|
|
|
|
|
// %cleanup: normal cleanup for 'y'
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
|
2010-07-14 04:32:21 +08:00
|
|
|
// -> %invoke.cont11, %lpad
|
|
|
|
|
|
|
|
// %invoke.cont11: normal cleanup for 'x'
|
2015-04-23 05:38:15 +08:00
|
|
|
// CHECK-EH: call void @llvm.lifetime.end
|
|
|
|
// CHECK-EH-NEXT: call {{.*}} @_ZN1XD1Ev
|
|
|
|
// CHECK-EH-NEXT: call void @llvm.lifetime.end
|
2010-07-14 04:32:21 +08:00
|
|
|
// CHECK-EH-NEXT: ret void
|
2010-07-06 09:34:17 +08:00
|
|
|
|
|
|
|
// %eh.cleanup: EH cleanup for 'x'
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: invoke {{.*}} @_ZN1XD1Ev
|
2010-07-14 04:32:21 +08:00
|
|
|
// -> %invoke.cont17, %terminate.lpad
|
|
|
|
|
|
|
|
// %invoke.cont17: rethrow block for %eh.cleanup.
|
|
|
|
// This really should be elsewhere in the function.
|
2011-09-20 04:31:14 +08:00
|
|
|
// CHECK-EH: resume { i8*, i32 }
|
2010-07-06 09:34:17 +08:00
|
|
|
|
|
|
|
// %terminate.lpad: terminate landing pad.
|
2015-06-18 04:53:19 +08:00
|
|
|
// CHECK-EH: [[T0:%.*]] = landingpad { i8*, i32 }
|
2011-09-20 04:31:14 +08:00
|
|
|
// CHECK-EH-NEXT: catch i8* null
|
2013-02-12 11:51:46 +08:00
|
|
|
// CHECK-EH-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
|
2013-02-22 17:10:20 +08:00
|
|
|
// CHECK-EH-NEXT: call void @__clang_call_terminate(i8* [[T1]]) [[NR_NUW:#[0-9]+]]
|
2010-07-06 09:34:17 +08:00
|
|
|
// CHECK-EH-NEXT: unreachable
|
|
|
|
|
2010-05-15 14:46:45 +08:00
|
|
|
}
|
|
|
|
|
2014-05-03 08:41:18 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test3b
|
2010-05-15 14:46:45 +08:00
|
|
|
X test3(bool B) {
|
2014-05-06 09:09:50 +08:00
|
|
|
// CHECK: tail call {{.*}} @_ZN1XC1Ev
|
2014-05-03 08:41:18 +08:00
|
|
|
// CHECK-NOT: call {{.*}} @_ZN1XC1ERKS_
|
|
|
|
// CHECK: call {{.*}} @_ZN1XC1Ev
|
|
|
|
// CHECK: call {{.*}} @_ZN1XC1ERKS_
|
|
|
|
if (B) {
|
2010-05-15 14:46:45 +08:00
|
|
|
X y;
|
|
|
|
return y;
|
|
|
|
}
|
2014-05-03 08:41:18 +08:00
|
|
|
// FIXME: we should NRVO this variable too.
|
2010-05-15 14:46:45 +08:00
|
|
|
X x;
|
|
|
|
return x;
|
|
|
|
}
|
2010-05-17 23:52:46 +08:00
|
|
|
|
|
|
|
extern "C" void exit(int) throw();
|
|
|
|
|
2013-08-15 14:47:53 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test4b
|
2010-05-17 23:52:46 +08:00
|
|
|
X test4(bool B) {
|
|
|
|
{
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK: tail call {{.*}} @_ZN1XC1Ev
|
2010-05-17 23:52:46 +08:00
|
|
|
X x;
|
|
|
|
// CHECK: br i1
|
|
|
|
if (B)
|
|
|
|
return x;
|
|
|
|
}
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK: tail call {{.*}} @_ZN1XD1Ev
|
2010-05-17 23:52:46 +08:00
|
|
|
// CHECK: tail call void @exit(i32 1)
|
|
|
|
exit(1);
|
|
|
|
}
|
2011-01-22 02:05:27 +08:00
|
|
|
|
2011-02-20 03:23:03 +08:00
|
|
|
#ifdef __EXCEPTIONS
|
2013-08-15 14:47:53 +08:00
|
|
|
// CHECK-EH-LABEL: define void @_Z5test5
|
2011-01-22 02:05:27 +08:00
|
|
|
void may_throw();
|
|
|
|
X test5() {
|
|
|
|
try {
|
|
|
|
may_throw();
|
|
|
|
} catch (X x) {
|
2011-06-15 05:20:53 +08:00
|
|
|
// CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_
|
2011-01-22 02:05:27 +08:00
|
|
|
// CHECK-EH: call void @__cxa_end_catch()
|
|
|
|
// CHECK-EH: ret void
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
2011-02-20 03:23:03 +08:00
|
|
|
#endif
|
2011-11-11 11:57:31 +08:00
|
|
|
|
|
|
|
// rdar://problem/10430868
|
2013-08-15 14:47:53 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test6v
|
2011-11-11 11:57:31 +08:00
|
|
|
X test6() {
|
|
|
|
X a __attribute__((aligned(8)));
|
|
|
|
return a;
|
|
|
|
// CHECK: [[A:%.*]] = alloca [[X:%.*]], align 8
|
2015-04-23 05:38:15 +08:00
|
|
|
// CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds %class.X, %class.X* [[A]], i32 0, i32 0
|
|
|
|
// CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* [[PTR]])
|
2015-06-17 04:24:06 +08:00
|
|
|
// CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* nonnull [[A]])
|
|
|
|
// CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{%.*}}, [[X]]* nonnull dereferenceable({{[0-9]+}}) [[A]])
|
|
|
|
// CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* nonnull [[A]])
|
2015-04-23 05:38:15 +08:00
|
|
|
// CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* [[PTR]])
|
2011-11-11 11:57:31 +08:00
|
|
|
// CHECK-NEXT: ret void
|
|
|
|
}
|
2013-02-22 17:10:20 +08:00
|
|
|
|
2014-05-03 09:19:39 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test7b
|
2014-05-03 08:41:18 +08:00
|
|
|
X test7(bool b) {
|
2014-05-03 09:19:39 +08:00
|
|
|
// CHECK: tail call {{.*}} @_ZN1XC1Ev
|
|
|
|
// CHECK-NEXT: ret
|
2014-05-03 08:41:18 +08:00
|
|
|
if (b) {
|
|
|
|
X x;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
return X();
|
|
|
|
}
|
|
|
|
|
2014-05-03 09:19:39 +08:00
|
|
|
// CHECK-LABEL: define void @_Z5test8b
|
2014-05-03 08:41:18 +08:00
|
|
|
X test8(bool b) {
|
2014-05-03 09:19:39 +08:00
|
|
|
// CHECK: tail call {{.*}} @_ZN1XC1Ev
|
|
|
|
// CHECK-NEXT: ret
|
2014-05-03 08:41:18 +08:00
|
|
|
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: tail call {{.*}} @_ZN1YIiEC1Ev
|
|
|
|
|
2013-02-22 17:10:20 +08:00
|
|
|
// CHECK-EH: attributes [[NR_NUW]] = { noreturn nounwind }
|