Set the writable and dead_on_unwind attributes for sret arguments. These indicate that the argument points to writable memory (and it's legal to introduce spurious writes to it on entry to the function) and that the argument memory will not be used if the call unwinds. This enables additional MemCpyOpt/DSE/LICM optimizations.
2948 lines
163 KiB
C++
2948 lines
163 KiB
C++
// 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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: br label [[EHCLEANUP:%.*]]
|
|
// CHECK-EH-03: lpad1:
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0
|
|
// CHECK-EH-03-NEXT: store ptr [[TMP5]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP6]], 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: [[TMP7:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: catch ptr null
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP7]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP8]]) #[[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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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) [[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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: catch ptr @_ZTI1X
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
|
|
// CHECK-EH-03-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTI1X) #[[ATTR7]]
|
|
// CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP3]]
|
|
// 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: [[TMP4:%.*]] = 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) [[TMP4]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = 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: [[TMP6:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 0
|
|
// CHECK-EH-03-NEXT: store ptr [[TMP7]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP8]], 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: [[TMP9:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP9]], 0
|
|
// CHECK-EH-03-NEXT: store ptr [[TMP10]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP11:%.*]] = extractvalue { ptr, i32 } [[TMP9]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP11]], 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: [[TMP12:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: catch ptr null
|
|
// CHECK-EH-03-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP12]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP13]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-11-NEXT: catch ptr @_ZTI1X
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
|
|
// CHECK-EH-11-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTI1X) #[[ATTR6]]
|
|
// CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP3]]
|
|
// 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: [[TMP4:%.*]] = 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) [[TMP4]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont1:
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = 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: [[TMP6:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 0
|
|
// CHECK-EH-11-NEXT: store ptr [[TMP7]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP8]], 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: [[TMP9:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-11-NEXT: catch ptr null
|
|
// CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP9]], 0
|
|
// CHECK-EH-11-NEXT: call void @__clang_call_terminate(ptr [[TMP10]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
|
|
// CHECK-EH-03-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: catch ptr null
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP4]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
|
|
// CHECK-EH-11-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP2]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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 dead_on_unwind writable 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 dead_on_unwind writable 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 dead_on_unwind writable 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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_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: [[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: @_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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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: 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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_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: [[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: @_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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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: 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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_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: [[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: @_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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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: 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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_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: [[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: @_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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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: 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 dead_on_unwind writable 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP2]], 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: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP3]], 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: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP4]], 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: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP5]], 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: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP6]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP2]], 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: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP3]], 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: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP4]], 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: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP5]], 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: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP6]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP2]], 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: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP3]], 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: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP4]], 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: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP5]], 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: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP6]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
|
|
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT]], ptr [[TMP0]], align 4
|
|
// CHECK-EH-11-NEXT: invoke void @"_ZZ6test19vENK3$_0clEv"(ptr dead_on_unwind writable 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: [[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) [[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 dead_on_unwind writable 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 dead_on_unwind writable 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: [[TMP0:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
|
|
// CHECK-EH-03-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-03-NEXT: catch ptr null
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP4]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
|
|
// CHECK-EH-11-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP2]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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) [[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: [[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: @_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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] 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: [[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) [[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 dead_on_unwind writable 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 dead_on_unwind writable 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
|