| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py |
| // 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: @_Z5test0v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-LABEL: @_Z5test0v( |
| // CHECK-EH-NEXT: entry: |
| // CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-NEXT: ret void |
| // |
| X test0() { |
| X x; |
| |
| return x; |
| } |
| |
| // CHECK-LABEL: @_Z5test1b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-LABEL: @_Z5test1b( |
| // CHECK-EH-NEXT: entry: |
| // CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-NEXT: ret void |
| // |
| X test1(bool B) { |
| X x; |
| if (B) |
| return (x); |
| return x; |
| } |
| |
| // CHECK-LABEL: @_Z5test2b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] |
| // CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] |
| // CHECK-NEXT: [[Y_X:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[X]] |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y_X]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test2b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7:[0-9]+]] |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[X]] |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP2]]) |
| // CHECK-EH-03-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD1:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] |
| // CHECK-EH-03: lpad1: |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: to label [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-03: invoke.cont4: |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: ehcleanup: |
| // CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD]] ], [ [[TMP4]], [[LPAD1]] ] |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[TERMINATE_LPAD]] |
| // CHECK-EH-03: invoke.cont9: |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: catch i8* null |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8:[0-9]+]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test2b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7:[0-9]+]] |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[X]] |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP2]]) |
| // CHECK-EH-11-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD1:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] |
| // CHECK-EH-11: lpad1: |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: br label [[EHCLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: ehcleanup: |
| // CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD1]] ], [ [[TMP3]], [[LPAD]] ] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] |
| // |
| X test2(bool B) { |
| // No NRVO. |
| |
| X x; |
| X y; |
| if (B) |
| return y; |
| return x; |
| } |
| |
| // CHECK-LABEL: @_Z5test3b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] |
| // CHECK-NEXT: br label [[RETURN:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test3b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: catch i8* null |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test3b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test3(bool B) { |
| 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: @_Z5test4b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] |
| // CHECK-NEXT: br i1 [[B:%.*]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR5]] |
| // CHECK-NEXT: unreachable |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test4b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: unreachable |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z5test4b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @exit(i32 noundef 1) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: unreachable |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test4(bool B) { |
| { |
| X x; |
| if (B) |
| return x; |
| } |
| exit(1); |
| } |
| |
| #ifdef __EXCEPTIONS |
| void may_throw(); |
| // CHECK-EH-03-LABEL: @_Z5test5v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: invoke void @_Z9may_throwv() |
| // CHECK-EH-03-NEXT: to label [[TRY_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0 |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 1 |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[TMP2]], [[TMP3]] |
| // CHECK-EH-03-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: catch: |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast i8* [[TMP5]] to %class.X* |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP6]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: [[TMP7:%.*]] = call i8* @__cxa_begin_catch(i8* [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD2:%.*]] |
| // CHECK-EH-03: invoke.cont3: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD4:%.*]] |
| // CHECK-EH-03: lpad2: |
| // CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[EHCLEANUP:%.*]] unwind label [[TERMINATE_LPAD]] |
| // CHECK-EH-03: invoke.cont5: |
| // CHECK-EH-03-NEXT: call void @__cxa_end_catch() |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: lpad4: |
| // CHECK-EH-03-NEXT: [[TMP9:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: br label [[EHCLEANUP]] |
| // CHECK-EH-03: ehcleanup: |
| // CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP9]], [[LPAD4]] ], [ [[TMP8]], [[LPAD2]] ] |
| // CHECK-EH-03-NEXT: invoke void @__cxa_end_catch() |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[TERMINATE_LPAD]] |
| // CHECK-EH-03: invoke.cont7: |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: br label [[EH_RESUME]] |
| // CHECK-EH-03: try.cont: |
| // CHECK-EH-03-NEXT: unreachable |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[LPAD_VAL11_MERGED:%.*]] = phi { i8*, i32 } [ [[DOTPN]], [[INVOKE_CONT7]] ], [ [[TMP0]], [[LPAD]] ] |
| // CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL11_MERGED]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP10:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: catch i8* null |
| // CHECK-EH-03-NEXT: [[TMP11:%.*]] = extractvalue { i8*, i32 } [[TMP10]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP11]]) #[[ATTR8]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test5v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: invoke void @_Z9may_throwv() |
| // CHECK-EH-11-NEXT: to label [[TRY_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-11-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0 |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 1 |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[TMP2]], [[TMP3]] |
| // CHECK-EH-11-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: catch: |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: [[TMP5:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast i8* [[TMP5]] to %class.X* |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP6]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont1: |
| // CHECK-EH-11-NEXT: [[TMP7:%.*]] = call i8* @__cxa_begin_catch(i8* [[TMP1]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD2:%.*]] |
| // CHECK-EH-11: invoke.cont3: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @__cxa_end_catch() |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: lpad2: |
| // CHECK-EH-11-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: invoke void @__cxa_end_catch() |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[TERMINATE_LPAD]] |
| // CHECK-EH-11: invoke.cont4: |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME]] |
| // CHECK-EH-11: try.cont: |
| // CHECK-EH-11-NEXT: unreachable |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[LPAD_VAL7_MERGED:%.*]] = phi { i8*, i32 } [ [[TMP8]], [[INVOKE_CONT4]] ], [ [[TMP0]], [[LPAD]] ] |
| // CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL7_MERGED]] |
| // CHECK-EH-11: terminate.lpad: |
| // CHECK-EH-11-NEXT: [[TMP9:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-11-NEXT: catch i8* null |
| // CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { i8*, i32 } [[TMP9]], 0 |
| // CHECK-EH-11-NEXT: call void @__clang_call_terminate(i8* [[TMP10]]) #[[ATTR8:[0-9]+]] |
| // CHECK-EH-11-NEXT: unreachable |
| // |
| X test5() { |
| try { |
| may_throw(); |
| } catch (X x) { |
| return x; |
| } |
| } |
| #endif |
| |
| // rdar://problem/10430868 |
| // CHECK-LABEL: @_Z5test6v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8 |
| // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], i32 0, i32 0 |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test6v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8 |
| // CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], i32 0, i32 0 |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-03-NEXT: catch i8* null |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test6v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8 |
| // CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], i32 0, i32 0 |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] |
| // CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] |
| // |
| X test6() { |
| X a __attribute__((aligned(8))); |
| return a; |
| } |
| |
| // CHECK-LABEL: @_Z5test7b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-LABEL: @_Z5test7b( |
| // CHECK-EH-NEXT: entry: |
| // CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-NEXT: ret void |
| // |
| X test7(bool b) { |
| if (b) { |
| X x; |
| return x; |
| } |
| return X(); |
| } |
| |
| // CHECK-LABEL: @_Z5test8b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-LABEL: @_Z5test8b( |
| // CHECK-EH-NEXT: entry: |
| // CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) |
| // CHECK-EH-NEXT: ret void |
| // |
| X test8(bool b) { |
| if (b) { |
| X x; |
| return x; |
| } else { |
| X y; |
| return y; |
| } |
| } |
| |
| // CHECK-LABEL: @_Z5test9v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1 |
| // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_Y]], %struct.Y* [[TMP]], i32 0, i32 0 |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] |
| // CHECK-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* nonnull sret([[STRUCT_Y]]) align 1 [[TMP]]) |
| // CHECK-NEXT: unreachable |
| // |
| // CHECK-EH-LABEL: @_Z5test9v( |
| // CHECK-EH-NEXT: entry: |
| // CHECK-EH-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1 |
| // CHECK-EH-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_Y]], %struct.Y* [[TMP]], i32 0, i32 0 |
| // CHECK-EH-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7:[0-9]+]] |
| // CHECK-EH-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* nonnull sret([[STRUCT_Y]]) align 1 [[TMP]]) |
| // CHECK-EH-NEXT: unreachable |
| // |
| Y<int> test9() { |
| Y<int>::f(); |
| } |