| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py |
| // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s |
| // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -fcxx-exceptions -fexceptions -disable-llvm-passes -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH-03 %s |
| // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -fcxx-exceptions -fexceptions -disable-llvm-passes -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH-11 %s |
| |
| // Test code generation for the named return value optimization. |
| class X { |
| public: |
| X(); |
| X(const X&); |
| X(const volatile X &); |
| ~X(); |
| }; |
| |
| template<typename T> struct Y { |
| Y(); |
| static Y f() { |
| Y y; |
| return y; |
| } |
| }; |
| |
| void ConsumeX(X x); |
| extern X OuterX; |
| |
| // CHECK-LABEL: @_Z5test0v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4:[0-9]+]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test0v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z5test0v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6:[0-9]+]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test0() { // http://wg21.link/p2025r2#ex-2 |
| X x; |
| return x; // NRVO happens |
| } |
| |
| // CHECK-LABEL: @_Z5test1b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test1b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z5test1b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test1(bool B) { |
| X x; |
| if (B) |
| return (x); // NRVO happens |
| return x; // NRVO happens |
| } |
| |
| // CHECK-LABEL: @_Z5test2b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR4]] |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test2b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr 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: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] |
| // CHECK-EH-03: invoke.cont2: |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] |
| // CHECK-EH-03: lpad1: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD1]] |
| // CHECK-EH-03: invoke.cont3: |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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 @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: invoke.cont5: |
| // CHECK-EH-03-NEXT: br label [[EHCLEANUP]] |
| // CHECK-EH-03: ehcleanup: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[TERMINATE_LPAD]] |
| // CHECK-EH-03: invoke.cont7: |
| // CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL8:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL8]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP9]]) #[[ATTR6:[0-9]+]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test2b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr 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: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] |
| // CHECK-EH-11: invoke.cont2: |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] |
| // CHECK-EH-11: lpad1: |
| // CHECK-EH-11-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EHCLEANUP]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD1]] |
| // CHECK-EH-11: invoke.cont3: |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: ehcleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL5:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL5]] |
| // |
| X test2(bool B) { |
| X x; |
| X y; |
| if (B) |
| return y; // NRVO is impossible |
| return x; // NRVO is impossible |
| } |
| |
| // CHECK-LABEL: @_Z5test3b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: br label [[RETURN:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]] |
| // CHECK: nrvo.unused3: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR4]] |
| // CHECK: nrvo.skipdtor4: |
| // 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]] |
| // CHECK-EH-03: nrvo.unused3: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR4]] |
| // CHECK-EH-03: nrvo.skipdtor4: |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z5test3b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]] |
| // CHECK-EH-11: nrvo.unused3: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR4]] |
| // CHECK-EH-11: nrvo.skipdtor4: |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test3(bool B) { // http://wg21.link/p2025r2#ex-4 |
| if (B) { |
| X y; |
| return y; // NRVO happens |
| } |
| X x; |
| return x; // FIXME: NRVO could happen, but doesn't |
| } |
| |
| extern "C" void exit(int) throw(); |
| |
| // CHECK-LABEL: @_Z5test4b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-NEXT: ] |
| // CHECK: cleanup.cont: |
| // CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR4]] |
| // CHECK-NEXT: call void @llvm.trap() |
| // CHECK-NEXT: unreachable |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // CHECK: unreachable: |
| // CHECK-NEXT: unreachable |
| // |
| // CHECK-EH-03-LABEL: @_Z5test4b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-EH-03-NEXT: ] |
| // CHECK-EH-03: cleanup.cont: |
| // CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR7:[0-9]+]] |
| // CHECK-EH-03-NEXT: call void @llvm.trap() |
| // CHECK-EH-03-NEXT: unreachable |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: unreachable: |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test4b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-EH-11-NEXT: ] |
| // CHECK-EH-11: cleanup.cont: |
| // CHECK-EH-11-NEXT: call void @exit(i32 noundef 1) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: call void @llvm.trap() |
| // CHECK-EH-11-NEXT: unreachable |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: unreachable: |
| // CHECK-EH-11-NEXT: unreachable |
| // |
| X test4(bool B) { |
| { |
| X x; |
| if (B) |
| return x; // NRVO happens |
| } |
| exit(1); |
| } |
| |
| #ifdef __EXCEPTIONS |
| void may_throw(); |
| // CHECK-EH-03-LABEL: @_Z5test5v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_Z9may_throwv() |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont: |
| // CHECK-EH-03-NEXT: br label [[TRY_CONT:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr @_ZTI1X |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CATCH_DISPATCH:%.*]] |
| // CHECK-EH-03: catch.dispatch: |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTI1X) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP4]] |
| // CHECK-EH-03-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: catch: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = call ptr @__cxa_get_exception_ptr(ptr [[EXN]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[X]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP5]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: [[TMP7:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr 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 { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT6:%.*]] unwind label [[TERMINATE_LPAD]] |
| // CHECK-EH-03: invoke.cont5: |
| // CHECK-EH-03-NEXT: call void @__cxa_end_catch() |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: lpad4: |
| // CHECK-EH-03-NEXT: [[TMP11:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP12:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP12]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP13]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] |
| // CHECK-EH-03: invoke.cont6: |
| // CHECK-EH-03-NEXT: br label [[EHCLEANUP]] |
| // CHECK-EH-03: ehcleanup: |
| // 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: br label [[EH_RESUME]] |
| // CHECK-EH-03: try.cont: |
| // CHECK-EH-03-NEXT: call void @llvm.trap() |
| // CHECK-EH-03-NEXT: unreachable |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN8:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL9:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN8]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL10:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL9]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL10]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP14:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP15:%.*]] = extractvalue { ptr, i32 } [[TMP14]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP15]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test5v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: invoke void @_Z9may_throwv() |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont: |
| // CHECK-EH-11-NEXT: br label [[TRY_CONT:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: catch ptr @_ZTI1X |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CATCH_DISPATCH:%.*]] |
| // CHECK-EH-11: catch.dispatch: |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTI1X) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP4]] |
| // CHECK-EH-11-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: catch: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP5:%.*]] = call ptr @__cxa_get_exception_ptr(ptr [[EXN]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[X]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP5]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont1: |
| // CHECK-EH-11-NEXT: [[TMP7:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: call void @__cxa_end_catch() |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: lpad2: |
| // CHECK-EH-11-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // 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: br label [[EH_RESUME]] |
| // CHECK-EH-11: try.cont: |
| // CHECK-EH-11-NEXT: call void @llvm.trap() |
| // CHECK-EH-11-NEXT: unreachable |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN5:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL6:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN5]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL7:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL6]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL7]] |
| // CHECK-EH-11: terminate.lpad: |
| // CHECK-EH-11-NEXT: [[TMP11:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: catch ptr null |
| // CHECK-EH-11-NEXT: [[TMP12:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 0 |
| // CHECK-EH-11-NEXT: call void @__clang_call_terminate(ptr [[TMP12]]) #[[ATTR7:[0-9]+]] |
| // CHECK-EH-11-NEXT: unreachable |
| // |
| X test5() { // http://wg21.link/p2025r2#ex-14 |
| try { |
| may_throw(); |
| } catch (X x) { |
| return x; // FIXME: NRVO could happen, but doesn't |
| } |
| } |
| #endif |
| |
| // CHECK-LABEL: @_Z5test6v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR4]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test6v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP5]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test6v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]] |
| // |
| X test6() { |
| X a __attribute__((aligned(8))); |
| return a; // NRVO is impossible |
| } |
| |
| // CHECK-LABEL: @_Z5test7b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: br label [[RETURN:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test7b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z5test7b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test7(bool b) { |
| if (b) { |
| X x; |
| return x; // NRVO happens |
| } |
| return X(); |
| } |
| |
| // CHECK-LABEL: @_Z5test8b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: br label [[RETURN:%.*]] |
| // CHECK: if.else: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]] |
| // CHECK: nrvo.unused3: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR4]] |
| // CHECK: nrvo.skipdtor4: |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z5test8b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-03: if.else: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]] |
| // CHECK-EH-03: nrvo.unused3: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR4]] |
| // CHECK-EH-03: nrvo.skipdtor4: |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z5test8b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-11: if.else: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]] |
| // CHECK-EH-11: nrvo.unused3: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR4]] |
| // CHECK-EH-11: nrvo.skipdtor4: |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test8(bool b) { |
| if (b) { |
| X x; |
| return x; // NRVO happens |
| } else { |
| X y; |
| return y; // NRVO happens |
| } |
| } |
| |
| // CHECK-LABEL: @_Z5test9v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: call void @_ZN1YIiE1fEv(ptr sret([[STRUCT_Y]]) align 1 [[TMP]]) |
| // CHECK-NEXT: call void @llvm.trap() |
| // CHECK-NEXT: unreachable |
| // |
| // CHECK-EH-03-LABEL: @_Z5test9v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: call void @_ZN1YIiE1fEv(ptr sret([[STRUCT_Y]]) align 1 [[TMP]]) |
| // CHECK-EH-03-NEXT: call void @llvm.trap() |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z5test9v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1YIiE1fEv(ptr sret([[STRUCT_Y]]) align 1 [[TMP]]) |
| // CHECK-EH-11-NEXT: call void @llvm.trap() |
| // CHECK-EH-11-NEXT: unreachable |
| // |
| Y<int> test9() { |
| Y<int>::f(); |
| } |
| |
| // CHECK-LABEL: @_Z6test10b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.else: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test10b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: if.else: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: invoke.cont2: |
| // CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL3]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test10b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: if.else: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-11: invoke.cont1: |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] |
| // |
| X test10(bool b) { // http://wg21.link/p2025r2#ex-3 |
| X x; |
| if (b) |
| return x; // NRVO is impossible |
| else |
| return X(); |
| } |
| |
| // CHECK-LABEL: @_Z6test11b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test11b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont: |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: invoke.cont2: |
| // CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL3]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test11b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont: |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-11: invoke.cont1: |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] |
| // |
| X test11(bool b) { // http://wg21.link/p2025r2#ex-5 |
| X x; |
| if (b) |
| return X(); |
| return x; // NRVO is impossible |
| } |
| |
| // CHECK-LABEL: @_Z6test12b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: br label [[DO_BODY:%.*]] |
| // CHECK: do.body: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-NEXT: i32 2, label [[DO_END:%.*]] |
| // CHECK-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-NEXT: ] |
| // CHECK: do.end: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // CHECK: unreachable: |
| // CHECK-NEXT: unreachable |
| // |
| // CHECK-EH-03-LABEL: @_Z6test12b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: br label [[DO_BODY:%.*]] |
| // CHECK-EH-03: do.body: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-03-NEXT: i32 2, label [[DO_END:%.*]] |
| // CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-EH-03-NEXT: ] |
| // CHECK-EH-03: do.end: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: unreachable: |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test12b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: br label [[DO_BODY:%.*]] |
| // CHECK-EH-11: do.body: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-11-NEXT: i32 2, label [[DO_END:%.*]] |
| // CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-EH-11-NEXT: ] |
| // CHECK-EH-11: do.end: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: unreachable: |
| // CHECK-EH-11-NEXT: unreachable |
| // |
| X test12(bool b) { // http://wg21.link/p2025r2#ex-6 |
| do { |
| X x; |
| if (b) |
| break; |
| return x; // NRVO happens |
| } while (false); |
| return X(); |
| } |
| |
| // CHECK-LABEL: @_Z6test13b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: br label [[RETURN:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test13b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z6test13b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test13(bool b) { // http://wg21.link/p2025r2#ex-7 |
| if (b) |
| return X(); |
| X x; |
| return x; // FIXME: NRVO could happen, but doesn't |
| } |
| |
| // CHECK-LABEL: @_Z6test14b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test14b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-03: invoke.cont2: |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: invoke.cont3: |
| // CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL4:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL4]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test14b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-11: invoke.cont1: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] |
| // |
| X test14(bool b) { // http://wg21.link/p2025r2#ex-8 |
| X x; |
| if (b) |
| return x; |
| X y; |
| return y; // FIXME: NRVO could happen, but doesn't |
| } |
| |
| // CHECK-LABEL: @_Z6test15b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test15b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-03: invoke.cont2: |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: invoke.cont3: |
| // CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL4:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL4]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test15b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]] |
| // CHECK-EH-11: invoke.cont1: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] |
| // |
| X test15(bool b) { // http://wg21.link/p2025r2#ex-15 |
| X x; |
| if (b) |
| return (x); |
| X y; |
| return ((y)); // FIXME: NRVO could happen, but doesn't |
| } |
| |
| #ifdef CXX11 |
| // CHECK-EH-11-LABEL: @_Z6test16v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[AGG_TMP:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-EH-11-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON:%.*]], align 4 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 0 |
| // CHECK-EH-11-NEXT: store ptr [[X]], ptr [[TMP0]], align 4 |
| // CHECK-EH-11-NEXT: invoke void @"_ZZ6test16vENK3$_0clEv"(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP]], ptr noundef nonnull align 4 dereferenceable(4) [[REF_TMP]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont: |
| // CHECK-EH-11-NEXT: invoke void @_Z8ConsumeX1X(ptr noundef [[AGG_TMP]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] |
| // CHECK-EH-11: invoke.cont2: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] |
| // CHECK-EH-11: lpad1: |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP5]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP6]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EHCLEANUP]] |
| // CHECK-EH-11: ehcleanup: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL3]] |
| // |
| void test16() { // http://wg21.link/p2025r2#ex-9 |
| X x; |
| ConsumeX([&] { |
| X y(x); |
| return y; // NRVO happens |
| }()); |
| } |
| #endif |
| |
| // CHECK-LABEL: @_Z6test17i( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: br label [[IMPOSSIBLE:%.*]] |
| // CHECK: impossible: |
| // CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3 |
| // CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then1: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: br label [[RETURN:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: br label [[IF_END2]] |
| // CHECK: if.end2: |
| // CHECK-NEXT: br label [[WHILE_BODY:%.*]] |
| // CHECK: while.body: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0 |
| // CHECK-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]] |
| // CHECK: if.then4: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end5: |
| // CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1 |
| // CHECK-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]] |
| // CHECK: if.then7: |
| // CHECK-NEXT: store i32 4, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: if.end8: |
| // CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2 |
| // CHECK-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]] |
| // CHECK: if.then10: |
| // CHECK-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3:![0-9]+]] |
| // CHECK: if.end11: |
| // CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3 |
| // CHECK-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]] |
| // CHECK: if.then13: |
| // CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: if.end14: |
| // CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4 |
| // CHECK-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]] |
| // CHECK: if.then16: |
| // CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR4]] |
| // CHECK-NEXT: br label [[IF_END17]] |
| // CHECK: if.end17: |
| // CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5 |
| // CHECK-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]] |
| // CHECK: if.then19: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: if.end20: |
| // CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-NEXT: i32 1, label [[RETURN]] |
| // CHECK-NEXT: i32 4, label [[WHILE_END:%.*]] |
| // CHECK-NEXT: i32 3, label [[WHILE_BODY]] |
| // CHECK-NEXT: i32 2, label [[IMPOSSIBLE]] |
| // CHECK-NEXT: ] |
| // CHECK: cleanup.cont: |
| // CHECK-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3]] |
| // CHECK: while.end: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // CHECK: unreachable: |
| // CHECK-NEXT: unreachable |
| // |
| // CHECK-EH-03-LABEL: @_Z6test17i( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: br label [[IMPOSSIBLE:%.*]] |
| // CHECK-EH-03: impossible: |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3 |
| // CHECK-EH-03-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then1: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: br label [[IF_END2]] |
| // CHECK-EH-03: if.end2: |
| // CHECK-EH-03-NEXT: br label [[WHILE_BODY:%.*]] |
| // CHECK-EH-03: while.body: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]] |
| // CHECK-EH-03: if.then4: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: if.end5: |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1 |
| // CHECK-EH-03-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]] |
| // CHECK-EH-03: if.then7: |
| // CHECK-EH-03-NEXT: store i32 4, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: if.end8: |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2 |
| // CHECK-EH-03-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]] |
| // CHECK-EH-03: if.then10: |
| // CHECK-EH-03-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: if.end11: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3 |
| // CHECK-EH-03-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]] |
| // CHECK-EH-03: if.then13: |
| // CHECK-EH-03-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: if.end14: |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4 |
| // CHECK-EH-03-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]] |
| // CHECK-EH-03: if.then16: |
| // CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR7]] |
| // CHECK-EH-03-NEXT: br label [[IF_END17]] |
| // CHECK-EH-03: if.end17: |
| // CHECK-EH-03-NEXT: [[TMP7:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5 |
| // CHECK-EH-03-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]] |
| // CHECK-EH-03: if.then19: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: if.end20: |
| // CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-EH-03-NEXT: i32 1, label [[RETURN]] |
| // CHECK-EH-03-NEXT: i32 4, label [[WHILE_END:%.*]] |
| // CHECK-EH-03-NEXT: i32 3, label [[WHILE_BODY]] |
| // CHECK-EH-03-NEXT: i32 2, label [[IMPOSSIBLE]] |
| // CHECK-EH-03-NEXT: ] |
| // CHECK-EH-03: cleanup.cont: |
| // CHECK-EH-03-NEXT: br label [[WHILE_BODY]] |
| // CHECK-EH-03: while.end: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: unreachable: |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test17i( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: br label [[IMPOSSIBLE:%.*]] |
| // CHECK-EH-11: impossible: |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3 |
| // CHECK-EH-11-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then1: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: br label [[IF_END2]] |
| // CHECK-EH-11: if.end2: |
| // CHECK-EH-11-NEXT: br label [[WHILE_BODY:%.*]] |
| // CHECK-EH-11: while.body: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]] |
| // CHECK-EH-11: if.then4: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: if.end5: |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1 |
| // CHECK-EH-11-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]] |
| // CHECK-EH-11: if.then7: |
| // CHECK-EH-11-NEXT: store i32 4, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: if.end8: |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2 |
| // CHECK-EH-11-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]] |
| // CHECK-EH-11: if.then10: |
| // CHECK-EH-11-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3:![0-9]+]] |
| // CHECK-EH-11: if.end11: |
| // CHECK-EH-11-NEXT: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3 |
| // CHECK-EH-11-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]] |
| // CHECK-EH-11: if.then13: |
| // CHECK-EH-11-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: if.end14: |
| // CHECK-EH-11-NEXT: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4 |
| // CHECK-EH-11-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]] |
| // CHECK-EH-11: if.then16: |
| // CHECK-EH-11-NEXT: call void @exit(i32 noundef 1) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[IF_END17]] |
| // CHECK-EH-11: if.end17: |
| // CHECK-EH-11-NEXT: [[TMP7:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5 |
| // CHECK-EH-11-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]] |
| // CHECK-EH-11: if.then19: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: if.end20: |
| // CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-EH-11-NEXT: i32 1, label [[RETURN]] |
| // CHECK-EH-11-NEXT: i32 4, label [[WHILE_END:%.*]] |
| // CHECK-EH-11-NEXT: i32 3, label [[WHILE_BODY]] |
| // CHECK-EH-11-NEXT: i32 2, label [[IMPOSSIBLE]] |
| // CHECK-EH-11-NEXT: ] |
| // CHECK-EH-11: cleanup.cont: |
| // CHECK-EH-11-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3]] |
| // CHECK-EH-11: while.end: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: unreachable: |
| // CHECK-EH-11-NEXT: unreachable |
| // |
| X test17(int i) { // http://wg21.link/p2025r2#ex-10 |
| if (false) { |
| impossible: |
| if (i == 3) |
| return X(); |
| } |
| |
| while (true) { |
| X x; |
| if (i == 0) |
| return x; // NRVO happens |
| if (i == 1) |
| break; |
| if (i == 2) |
| continue; |
| if (i == 3) |
| goto impossible; |
| if (i == 4) |
| exit(1); |
| if (i == 5) |
| return x; // NRVO happens |
| } |
| return X(); |
| } |
| |
| // CHECK-LABEL: @_Z6test18i( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[NRVO11:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0 |
| // CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP]] |
| // CHECK: cleanup: |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-NEXT: ] |
| // CHECK: cleanup.cont: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP2]], 1 |
| // CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]] |
| // CHECK: if.then3: |
| // CHECK-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP5:%.*]] |
| // CHECK: if.end4: |
| // CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: br label [[CLEANUP5]] |
| // CHECK: cleanup5: |
| // CHECK-NEXT: [[NRVO_VAL6:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL6]], label [[NRVO_SKIPDTOR8:%.*]], label [[NRVO_UNUSED7:%.*]] |
| // CHECK: nrvo.unused7: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR8]] |
| // CHECK: nrvo.skipdtor8: |
| // CHECK-NEXT: [[CLEANUP_DEST9:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: switch i32 [[CLEANUP_DEST9]], label [[UNREACHABLE]] [ |
| // CHECK-NEXT: i32 0, label [[CLEANUP_CONT10:%.*]] |
| // CHECK-NEXT: i32 1, label [[RETURN]] |
| // CHECK-NEXT: ] |
| // CHECK: cleanup.cont10: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO11]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO11]], align 1 |
| // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-NEXT: [[NRVO_VAL13:%.*]] = load i1, ptr [[NRVO11]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL13]], label [[NRVO_SKIPDTOR15:%.*]], label [[NRVO_UNUSED14:%.*]] |
| // CHECK: nrvo.unused14: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR15]] |
| // CHECK: nrvo.skipdtor15: |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // CHECK: unreachable: |
| // CHECK-NEXT: unreachable |
| // |
| // CHECK-EH-03-LABEL: @_Z6test18i( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO11:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0 |
| // CHECK-EH-03-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-03: cleanup: |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-EH-03-NEXT: ] |
| // CHECK-EH-03: cleanup.cont: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-03-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP2]], 1 |
| // CHECK-EH-03-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]] |
| // CHECK-EH-03: if.then3: |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP5:%.*]] |
| // CHECK-EH-03: if.end4: |
| // CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: br label [[CLEANUP5]] |
| // CHECK-EH-03: cleanup5: |
| // CHECK-EH-03-NEXT: [[NRVO_VAL6:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL6]], label [[NRVO_SKIPDTOR8:%.*]], label [[NRVO_UNUSED7:%.*]] |
| // CHECK-EH-03: nrvo.unused7: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR8]] |
| // CHECK-EH-03: nrvo.skipdtor8: |
| // CHECK-EH-03-NEXT: [[CLEANUP_DEST9:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST9]], label [[UNREACHABLE]] [ |
| // CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT10:%.*]] |
| // CHECK-EH-03-NEXT: i32 1, label [[RETURN]] |
| // CHECK-EH-03-NEXT: ] |
| // CHECK-EH-03: cleanup.cont10: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO11]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO11]], align 1 |
| // CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL13:%.*]] = load i1, ptr [[NRVO11]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL13]], label [[NRVO_SKIPDTOR15:%.*]], label [[NRVO_UNUSED14:%.*]] |
| // CHECK-EH-03: nrvo.unused14: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR15]] |
| // CHECK-EH-03: nrvo.skipdtor15: |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: unreachable: |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test18i( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO1:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO11:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0 |
| // CHECK-EH-11-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP]] |
| // CHECK-EH-11: cleanup: |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [ |
| // CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT:%.*]] |
| // CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]] |
| // CHECK-EH-11-NEXT: ] |
| // CHECK-EH-11: cleanup.cont: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4 |
| // CHECK-EH-11-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]] |
| // CHECK-EH-11: if.then3: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP5:%.*]] |
| // CHECK-EH-11: if.end4: |
| // CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: br label [[CLEANUP5]] |
| // CHECK-EH-11: cleanup5: |
| // CHECK-EH-11-NEXT: [[NRVO_VAL6:%.*]] = load i1, ptr [[NRVO1]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL6]], label [[NRVO_SKIPDTOR8:%.*]], label [[NRVO_UNUSED7:%.*]] |
| // CHECK-EH-11: nrvo.unused7: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR8]] |
| // CHECK-EH-11: nrvo.skipdtor8: |
| // CHECK-EH-11-NEXT: [[CLEANUP_DEST9:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST9]], label [[UNREACHABLE]] [ |
| // CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT10:%.*]] |
| // CHECK-EH-11-NEXT: i32 1, label [[RETURN]] |
| // CHECK-EH-11-NEXT: ] |
| // CHECK-EH-11: cleanup.cont10: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO11]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO11]], align 1 |
| // CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL13:%.*]] = load i1, ptr [[NRVO11]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL13]], label [[NRVO_SKIPDTOR15:%.*]], label [[NRVO_UNUSED14:%.*]] |
| // CHECK-EH-11: nrvo.unused14: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR15]] |
| // CHECK-EH-11: nrvo.skipdtor15: |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: unreachable: |
| // CHECK-EH-11-NEXT: unreachable |
| // |
| X test18(int i) { // http://wg21.link/p2025r2#ex-11 |
| { |
| { |
| X x; |
| if (i == 0) |
| return x; // NRVO happens |
| } |
| X y; |
| if (i == 1) |
| return y; // FIXME: NRVO could happen, but doesn't |
| } |
| X z; |
| return z; // FIXME: NRVO could happen, but doesn't |
| } |
| |
| #ifdef CXX11 |
| // CHECK-EH-11-LABEL: @_Z6test19v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[L:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 4 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT]], ptr [[TMP1]], align 4 |
| // CHECK-EH-11-NEXT: invoke void @"_ZZ6test19vENK3$_0clEv"(ptr sret([[CLASS_X]]) align 1 [[L]], ptr noundef nonnull align 4 dereferenceable(4) [[REF_TMP]]) |
| // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] |
| // CHECK-EH-11: invoke.cont: |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[L]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]] |
| // |
| X test19() { // http://wg21.link/p2025r2#ex-12 |
| X x; |
| struct S { |
| X f() { return X(); } |
| }; |
| auto L = [&x]() { return X(); }(); |
| if constexpr (false) { |
| return X(); |
| } |
| return x; // NRVO happens |
| } |
| |
| template <bool B> |
| X test20() { // http://wg21.link/p2025r2#ex-18 |
| X x; |
| if constexpr (B) { |
| if (false) |
| return X(); |
| } |
| return x; // FIXME: NRVO could happen when B == false, but doesn't |
| } |
| |
| // CHECK-EH-11-LABEL: @_Z17test20instantiatev( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED1:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-EH-11-NEXT: call void @_Z6test20ILb1EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED]]) |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: call void @_Z6test20ILb0EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED1]]) |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // |
| void test20instantiate() { |
| test20<true>(); |
| test20<false>(); |
| } |
| #endif |
| |
| // CHECK-LABEL: @_Z6test21v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test21v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z6test21v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| const volatile X test21() { // http://wg21.link/p2025r2#ex-19 |
| X x; |
| return x; // NRVO happens |
| } |
| |
| // CHECK-LABEL: @_Z6test22v( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: call void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test22v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP5]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test22v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]] |
| // |
| X test22() { // http://wg21.link/p2025r2#ex-19 |
| volatile X x; |
| return x; // NRVO is impossible |
| } |
| |
| // CHECK-LABEL: @_Z6test23b( |
| // CHECK-NEXT: entry: |
| // CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK: if.then: |
| // CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK: nrvo.unused: |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK: nrvo.skipdtor: |
| // CHECK-NEXT: br label [[RETURN:%.*]] |
| // CHECK: if.end: |
| // CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-NEXT: call void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR4]] |
| // CHECK-NEXT: br label [[RETURN]] |
| // CHECK: return: |
| // CHECK-NEXT: ret void |
| // |
| // CHECK-EH-03-LABEL: @_Z6test23b( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-03: if.then: |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-03: if.end: |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: br label [[RETURN]] |
| // CHECK-EH-03: lpad: |
| // CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: cleanup |
| // CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] |
| // CHECK-EH-03: invoke.cont1: |
| // CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-03: return: |
| // CHECK-EH-03-NEXT: ret void |
| // CHECK-EH-03: eh.resume: |
| // CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL2]] |
| // CHECK-EH-03: terminate.lpad: |
| // CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-03-NEXT: catch ptr null |
| // CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0 |
| // CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]] |
| // CHECK-EH-03-NEXT: unreachable |
| // |
| // CHECK-EH-11-LABEL: @_Z6test23b( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 |
| // CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1 |
| // CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1 |
| // CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| // CHECK-EH-11: if.then: |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] |
| // CHECK-EH-11: if.end: |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) |
| // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[RETURN]] |
| // CHECK-EH-11: lpad: |
| // CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 } |
| // CHECK-EH-11-NEXT: cleanup |
| // CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0 |
| // CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1 |
| // CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] |
| // CHECK-EH-11: return: |
| // CHECK-EH-11-NEXT: ret void |
| // CHECK-EH-11: eh.resume: |
| // CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0 |
| // CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1 |
| // CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]] |
| // |
| X test23(bool b) { // http://wg21.link/p2025r2#ex-19 |
| if (b) { |
| const X x; |
| return x; // NRVO happens |
| } |
| volatile X y; |
| return y; // NRVO is impossible |
| } |
| |
| #ifdef __EXCEPTIONS |
| // CHECK-EH-03-LABEL: @_Z6test24v( |
| // CHECK-EH-03-NEXT: entry: |
| // CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-03: nrvo.unused: |
| // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-03: nrvo.skipdtor: |
| // CHECK-EH-03-NEXT: ret void |
| // |
| // CHECK-EH-11-LABEL: @_Z6test24v( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4 |
| // CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1 |
| // CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4 |
| // CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) |
| // CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1 |
| // CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] |
| // CHECK-EH-11: nrvo.unused: |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] |
| // CHECK-EH-11: nrvo.skipdtor: |
| // CHECK-EH-11-NEXT: ret void |
| // |
| X test24() { // http://wg21.link/p2025r2#ex-20 |
| X x; |
| if (&x == &OuterX) |
| throw 0; |
| return x; // NRVO happens |
| } |
| #endif |
| |
| #ifdef CXX11 |
| template <bool B> |
| X test25() { |
| X x; |
| if constexpr (B) { |
| return x; // FIXME: NRVO could happen when B == true, but doesn't |
| } else { |
| return X(); |
| } |
| } |
| |
| // CHECK-EH-11-LABEL: @_Z17test25instantiatev( |
| // CHECK-EH-11-NEXT: entry: |
| // CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[CLASS_X:%.*]], align 1 |
| // CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED1:%.*]] = alloca [[CLASS_X]], align 1 |
| // CHECK-EH-11-NEXT: call void @_Z6test25ILb1EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED]]) |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: call void @_Z6test25ILb0EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED1]]) |
| // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]]) #[[ATTR6]] |
| // CHECK-EH-11-NEXT: ret void |
| // |
| void test25instantiate() { |
| test25<true>(); |
| test25<false>(); |
| } |
| #endif |