forked from OSchip/llvm-project
3152 lines
178 KiB
C++
3152 lines
178 KiB
C++
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
|
|
// RUN: %clang_cc1 -no-opaque-pointers -triple i386-unknown-unknown -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
|
|
// RUN: %clang_cc1 -no-opaque-pointers -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 -no-opaque-pointers -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 i8*, align 4
|
|
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: [[TMP3:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP3]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-EH-03-LABEL: @_Z5test2b(
|
|
// CHECK-EH-03-NEXT: entry:
|
|
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP3]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* 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, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]]
|
|
// CHECK-EH-03: lpad1:
|
|
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP8]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP9]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD1]]
|
|
// CHECK-EH-03: invoke.cont3:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD]]
|
|
// CHECK-EH-03: invoke.cont4:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* 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(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[TERMINATE_LPAD]]
|
|
// CHECK-EH-03: invoke.cont7:
|
|
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-03: eh.resume:
|
|
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL12:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL12]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP14:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP15:%.*]] = extractvalue { i8*, i32 } [[TMP14]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP15]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z5test2b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP3]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* 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, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]]
|
|
// CHECK-EH-11: lpad1:
|
|
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP8]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP9]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD1]]
|
|
// CHECK-EH-11: invoke.cont3:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: ehcleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL9:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL9]]
|
|
//
|
|
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 i8*, align 4
|
|
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// 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 i8*, 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: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL2]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z5test3b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL1]]
|
|
//
|
|
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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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)
|
|
// 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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, i32* [[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)
|
|
// 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK-EH-11: nrvo.skipdtor:
|
|
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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)
|
|
// 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 i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_Z9may_throwv()
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: br label [[TRY_CONT:%.*]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP1]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP2]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP1]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP3]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CATCH_DISPATCH:%.*]]
|
|
// CHECK-EH-03: catch.dispatch:
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*))
|
|
// CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP4]]
|
|
// CHECK-EH-03-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-03: catch:
|
|
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[EXN]])
|
|
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = bitcast i8* [[TMP6]] to %class.X*
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP7]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD2:%.*]]
|
|
// CHECK-EH-03: invoke.cont3:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD4:%.*]]
|
|
// CHECK-EH-03: lpad2:
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP10:%.*]] = extractvalue { i8*, i32 } [[TMP9]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP10]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP11:%.*]] = extractvalue { i8*, i32 } [[TMP9]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP11]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* 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: [[TMP13:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP14:%.*]] = extractvalue { i8*, i32 } [[TMP13]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP14]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP15:%.*]] = extractvalue { i8*, i32 } [[TMP13]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP15]], i32* [[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: [[EXN9:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL10:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN9]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL11:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL10]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL11]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP17:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP18:%.*]] = extractvalue { i8*, i32 } [[TMP17]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP18]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z5test5v(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: invoke void @_Z9may_throwv()
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: br label [[TRY_CONT:%.*]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP1]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP2]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP1]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP3]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CATCH_DISPATCH:%.*]]
|
|
// CHECK-EH-11: catch.dispatch:
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*))
|
|
// CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP4]]
|
|
// CHECK-EH-11-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: catch:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[EXN]])
|
|
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast i8* [[TMP6]] to %class.X*
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP7]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont1:
|
|
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD2:%.*]]
|
|
// CHECK-EH-11: invoke.cont3:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: call void @__cxa_end_catch()
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: lpad2:
|
|
// CHECK-EH-11-NEXT: [[TMP10:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP11:%.*]] = extractvalue { i8*, i32 } [[TMP10]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP11]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP12:%.*]] = extractvalue { i8*, i32 } [[TMP10]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP12]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL6:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN5]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL7:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL6]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL7]]
|
|
// CHECK-EH-11: terminate.lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP14:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: catch i8* null
|
|
// CHECK-EH-11-NEXT: [[TMP15:%.*]] = extractvalue { i8*, i32 } [[TMP14]], 0
|
|
// CHECK-EH-11-NEXT: call void @__clang_call_terminate(i8* [[TMP15]])
|
|
// 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
|
|
|
|
// rdar://problem/10430868
|
|
// CHECK-LABEL: @_Z5test6v(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, align 4
|
|
// CHECK-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-EH-03-LABEL: @_Z5test6v(
|
|
// CHECK-EH-03-NEXT: entry:
|
|
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
|
|
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-03-NEXT: ret void
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-03: eh.resume:
|
|
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL2]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP8]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z5test6v(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
|
|
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, 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 i8*, align 4
|
|
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK: if.else:
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO1]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO1]], align 1
|
|
// CHECK-NEXT: [[NRVO_VAL2:%.*]] = load i1, i1* [[NRVO1]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]]
|
|
// CHECK: nrvo.unused3:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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, i1* [[NRVO1]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO1]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL2:%.*]] = load i1, i1* [[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(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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, i1* [[NRVO1]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO1]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL2:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, align 4
|
|
// CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %struct.Y* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* 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 i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %struct.Y* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* 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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %struct.Y* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.else:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-EH-03-LABEL: @_Z6test10b(
|
|
// CHECK-EH-03-NEXT: entry:
|
|
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* 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(%class.X* 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, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL4:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL4]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z6test10b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: if.else:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* 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, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL3]]
|
|
//
|
|
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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-EH-03-LABEL: @_Z6test11b(
|
|
// CHECK-EH-03-NEXT: entry:
|
|
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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(%class.X* 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, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL4:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL4]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z6test11b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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(%class.X* 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, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
|
|
// CHECK-EH-11: invoke.cont1:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL3]]
|
|
//
|
|
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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: br label [[DO_BODY:%.*]]
|
|
// CHECK: do.body:
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i32 2, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: br label [[DO_BODY:%.*]]
|
|
// CHECK-EH-03: do.body:
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i32 2, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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, i32* [[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(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: br label [[DO_BODY:%.*]]
|
|
// CHECK-EH-11: do.body:
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i32 2, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK-EH-11: nrvo.skipdtor:
|
|
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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(%class.X* 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 i8*, align 4
|
|
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// 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 i8*, 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 i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL2]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z6test13b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL1]]
|
|
//
|
|
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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-EH-03-LABEL: @_Z6test14b(
|
|
// CHECK-EH-03-NEXT: entry:
|
|
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[EHCLEANUP7:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]]
|
|
// CHECK-EH-03: invoke.cont3:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD1]]
|
|
// CHECK-EH-03: lpad2:
|
|
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP8]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP9]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT6:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont4:
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: invoke.cont5:
|
|
// CHECK-EH-03-NEXT: br label [[EHCLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: ret void
|
|
// CHECK-EH-03: ehcleanup:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD]]
|
|
// CHECK-EH-03: invoke.cont6:
|
|
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-03: eh.resume:
|
|
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL11:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL11]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP17:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP18:%.*]] = extractvalue { i8*, i32 } [[TMP17]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP18]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z6test14b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP5:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]]
|
|
// CHECK-EH-11: invoke.cont1:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]]
|
|
// CHECK-EH-11: invoke.cont3:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: lpad2:
|
|
// CHECK-EH-11-NEXT: [[TMP11:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP12:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP12]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP13:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP13]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: ehcleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL8:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL8]]
|
|
//
|
|
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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-EH-03-LABEL: @_Z6test15b(
|
|
// CHECK-EH-03-NEXT: entry:
|
|
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[EHCLEANUP7:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]]
|
|
// CHECK-EH-03: invoke.cont3:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD1]]
|
|
// CHECK-EH-03: lpad2:
|
|
// CHECK-EH-03-NEXT: [[TMP10:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP11:%.*]] = extractvalue { i8*, i32 } [[TMP10]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP11]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP12:%.*]] = extractvalue { i8*, i32 } [[TMP10]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP12]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT6:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont4:
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: invoke.cont5:
|
|
// CHECK-EH-03-NEXT: br label [[EHCLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: ret void
|
|
// CHECK-EH-03: ehcleanup:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD]]
|
|
// CHECK-EH-03: invoke.cont6:
|
|
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-03: eh.resume:
|
|
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL11:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL11]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP17:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP18:%.*]] = extractvalue { i8*, i32 } [[TMP17]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP18]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z6test15b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP2]] 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_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP5:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]]
|
|
// CHECK-EH-11: invoke.cont1:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]]
|
|
// CHECK-EH-11: invoke.cont3:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: lpad2:
|
|
// CHECK-EH-11-NEXT: [[TMP11:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP12:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP12]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP13:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP13]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: ehcleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL8:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL8]]
|
|
//
|
|
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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_ANON]], %class.anon* [[REF_TMP]], i32 0, i32 0
|
|
// CHECK-EH-11-NEXT: store %class.X* [[X]], %class.X** [[TMP2]], align 4
|
|
// CHECK-EH-11-NEXT: invoke void @"_ZZ6test16vENK3$_0clEv"(%class.X* sret([[CLASS_X]]) align 1 [[AGG_TMP]], %class.anon* 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(%class.X* 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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]])
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP6]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP7]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]]
|
|
// CHECK-EH-11: lpad1:
|
|
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP9]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP10]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]])
|
|
// CHECK-EH-11-NEXT: br label [[EHCLEANUP]]
|
|
// CHECK-EH-11: ehcleanup:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL5:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL5]]
|
|
//
|
|
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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: store i32 [[I:%.*]], i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: br label [[IMPOSSIBLE:%.*]]
|
|
// CHECK: impossible:
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
|
|
// CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then1:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* 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, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0
|
|
// CHECK-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]]
|
|
// CHECK: if.then4:
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end5:
|
|
// CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1
|
|
// CHECK-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]]
|
|
// CHECK: if.then7:
|
|
// CHECK-NEXT: store i32 4, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: if.end8:
|
|
// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2
|
|
// CHECK-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]]
|
|
// CHECK: if.then10:
|
|
// CHECK-NEXT: store i32 3, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP10:![0-9]+]]
|
|
// CHECK: if.end11:
|
|
// CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3
|
|
// CHECK-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]]
|
|
// CHECK: if.then13:
|
|
// CHECK-NEXT: store i32 2, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: if.end14:
|
|
// CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4
|
|
// CHECK-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]]
|
|
// CHECK: if.then16:
|
|
// CHECK-NEXT: call void @exit(i32 noundef 1)
|
|
// CHECK-NEXT: br label [[IF_END17]]
|
|
// CHECK: if.end17:
|
|
// CHECK-NEXT: [[TMP7:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5
|
|
// CHECK-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]]
|
|
// CHECK: if.then19:
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: if.end20:
|
|
// CHECK-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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 [[LOOP10]]
|
|
// CHECK: while.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: store i32 [[I:%.*]], i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: br label [[IMPOSSIBLE:%.*]]
|
|
// CHECK-EH-03: impossible:
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then1:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: 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, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]]
|
|
// CHECK-EH-03: if.then4:
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: if.end5:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]]
|
|
// CHECK-EH-03: if.then7:
|
|
// CHECK-EH-03-NEXT: store i32 4, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: if.end8:
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]]
|
|
// CHECK-EH-03: if.then10:
|
|
// CHECK-EH-03-NEXT: store i32 3, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: if.end11:
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]]
|
|
// CHECK-EH-03: if.then13:
|
|
// CHECK-EH-03-NEXT: store i32 2, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: if.end14:
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]]
|
|
// CHECK-EH-03: if.then16:
|
|
// CHECK-EH-03-NEXT: call void @exit(i32 noundef 1)
|
|
// CHECK-EH-03-NEXT: br label [[IF_END17]]
|
|
// CHECK-EH-03: if.end17:
|
|
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]]
|
|
// CHECK-EH-03: if.then19:
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: if.end20:
|
|
// CHECK-EH-03-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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, i32* [[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(%class.X* 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: store i32 [[I:%.*]], i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: br label [[IMPOSSIBLE:%.*]]
|
|
// CHECK-EH-11: impossible:
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then1:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: 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, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]]
|
|
// CHECK-EH-11: if.then4:
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: if.end5:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]]
|
|
// CHECK-EH-11: if.then7:
|
|
// CHECK-EH-11-NEXT: store i32 4, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: if.end8:
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]]
|
|
// CHECK-EH-11: if.then10:
|
|
// CHECK-EH-11-NEXT: store i32 3, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP14:![0-9]+]]
|
|
// CHECK-EH-11: if.end11:
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]]
|
|
// CHECK-EH-11: if.then13:
|
|
// CHECK-EH-11-NEXT: store i32 2, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: if.end14:
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]]
|
|
// CHECK-EH-11: if.then16:
|
|
// CHECK-EH-11-NEXT: call void @exit(i32 noundef 1)
|
|
// CHECK-EH-11-NEXT: br label [[IF_END17]]
|
|
// CHECK-EH-11: if.end17:
|
|
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]]
|
|
// CHECK-EH-11: if.then19:
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: if.end20:
|
|
// CHECK-EH-11-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK-EH-11: nrvo.skipdtor:
|
|
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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 [[LOOP14]]
|
|
// CHECK-EH-11: while.end:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-11: 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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: store i32 [[I:%.*]], i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
|
|
// CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP]]
|
|
// CHECK: cleanup:
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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 @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP3]], 1
|
|
// CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
|
|
// CHECK: if.then2:
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP4:%.*]]
|
|
// CHECK: if.end3:
|
|
// CHECK-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: br label [[CLEANUP4]]
|
|
// CHECK: cleanup4:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: [[CLEANUP_DEST6:%.*]] = load i32, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: switch i32 [[CLEANUP_DEST6]], label [[UNREACHABLE]] [
|
|
// CHECK-NEXT: i32 0, label [[CLEANUP_CONT7:%.*]]
|
|
// CHECK-NEXT: i32 1, label [[RETURN]]
|
|
// CHECK-NEXT: ]
|
|
// CHECK: cleanup.cont6:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// 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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-03-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: store i32 [[I:%.*]], i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-03: if.end:
|
|
// CHECK-EH-03-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-03: cleanup:
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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, i32* [[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 @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-03-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
|
|
// CHECK-EH-03: if.then2:
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP4:%.*]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: if.end3:
|
|
// CHECK-EH-03-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: br label [[CLEANUP4]]
|
|
// CHECK-EH-03: cleanup4:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: [[CLEANUP_DEST7:%.*]] = load i32, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST7]], label [[UNREACHABLE]] [
|
|
// CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT8:%.*]]
|
|
// CHECK-EH-03-NEXT: i32 1, label [[RETURN]]
|
|
// CHECK-EH-03-NEXT: ]
|
|
// CHECK-EH-03: cleanup.cont6:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT10:%.*]] unwind label [[LPAD9:%.*]]
|
|
// CHECK-EH-03: invoke.cont9:
|
|
// CHECK-EH-03-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-EH-03-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-03: invoke.cont7:
|
|
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-03: lpad8:
|
|
// CHECK-EH-03-NEXT: [[TMP11:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP12:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP12]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP13:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP13]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT12:%.*]] unwind label [[TERMINATE_LPAD]]
|
|
// CHECK-EH-03: invoke.cont11:
|
|
// 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL14:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL14]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP15:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP16:%.*]] = extractvalue { i8*, i32 } [[TMP15]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP16]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
// 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 i8*, 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: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: store i32 [[I:%.*]], i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
|
|
// CHECK-EH-11: if.end:
|
|
// CHECK-EH-11-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
|
|
// CHECK-EH-11: cleanup:
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK-EH-11: nrvo.skipdtor:
|
|
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, i32* [[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 @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4
|
|
// CHECK-EH-11-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
|
|
// CHECK-EH-11: if.then2:
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP4:%.*]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: if.end3:
|
|
// CHECK-EH-11-NEXT: store i32 0, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: br label [[CLEANUP4]]
|
|
// CHECK-EH-11: cleanup4:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: [[CLEANUP_DEST6:%.*]] = load i32, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST6]], label [[UNREACHABLE]] [
|
|
// CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT7:%.*]]
|
|
// CHECK-EH-11-NEXT: i32 1, label [[RETURN]]
|
|
// CHECK-EH-11-NEXT: ]
|
|
// CHECK-EH-11: cleanup.cont6:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[LPAD8:%.*]]
|
|
// CHECK-EH-11: invoke.cont8:
|
|
// CHECK-EH-11-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// CHECK-EH-11-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-11: lpad7:
|
|
// CHECK-EH-11-NEXT: [[TMP11:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP12:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP12]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP13:%.*]] = extractvalue { i8*, i32 } [[TMP11]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP13]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]])
|
|
// 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL12:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL12]]
|
|
// 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 i8*, 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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], %class.anon.0* [[REF_TMP]], i32 0, i32 0
|
|
// CHECK-EH-11-NEXT: store %class.X* [[AGG_RESULT]], %class.X** [[TMP3]], align 4
|
|
// CHECK-EH-11-NEXT: invoke void @"_ZZ6test19vENK3$_1clEv"(%class.X* sret([[CLASS_X]]) align 1 [[L]], %class.anon.0* 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, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[L]])
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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: [[TMP6:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = extractvalue { i8*, i32 } [[TMP6]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP7]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP6]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP8]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: nrvo.unused:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, 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(%class.X* sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED]])
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]])
|
|
// CHECK-EH-11-NEXT: call void @_Z6test20ILb0EE1Xv(%class.X* sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED1]])
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
//
|
|
void test20instantiate() {
|
|
test20<true>();
|
|
test20<false>();
|
|
}
|
|
#endif
|
|
|
|
// CHECK-LABEL: @_Z6test21v(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, align 4
|
|
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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 i8*, align 4
|
|
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
// CHECK-EH-03-LABEL: @_Z6test22v(
|
|
// CHECK-EH-03-NEXT: entry:
|
|
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: ret void
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont1:
|
|
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-03: eh.resume:
|
|
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL2]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP8]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z6test22v(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
|
|
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP4]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP5]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
|
|
// CHECK-EH-11: eh.resume:
|
|
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, 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 i8*, 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: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK: if.then:
|
|
// CHECK-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[NRVO]], align 1
|
|
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
|
|
// CHECK: nrvo.unused:
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
|
|
// CHECK: nrvo.skipdtor:
|
|
// CHECK-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK: if.end:
|
|
// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: call void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// 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 i8*, 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 i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-03: if.then:
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-03: invoke.cont:
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-03-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-03: lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: cleanup
|
|
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-03-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL2]]
|
|
// CHECK-EH-03: terminate.lpad:
|
|
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-03-NEXT: catch i8* null
|
|
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0
|
|
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]])
|
|
// CHECK-EH-03-NEXT: unreachable
|
|
//
|
|
// CHECK-EH-11-LABEL: @_Z6test23b(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca i8*, 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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
|
|
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1
|
|
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-EH-11: if.then:
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// CHECK-EH-11-NEXT: br label [[RETURN]]
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 }
|
|
// CHECK-EH-11-NEXT: cleanup
|
|
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP5]], i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 1
|
|
// CHECK-EH-11-NEXT: store i32 [[TMP6]], i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
|
|
// 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 i8*, i8** [[EXN_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, i32* [[EHSELECTOR_SLOT]], align 4
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0
|
|
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { i8*, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
|
|
// CHECK-EH-11-NEXT: resume { i8*, 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 i8*, align 4
|
|
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-03-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-03-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-03-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* 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 i8*, align 4
|
|
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
|
|
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8*
|
|
// CHECK-EH-11-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4
|
|
// CHECK-EH-11-NEXT: store i1 false, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// CHECK-EH-11-NEXT: store i1 true, i1* [[NRVO]], align 1
|
|
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, i1* [[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(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
|
|
// 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: define linkonce_odr void @_Z6test25ILb1EE1Xv(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11: [[X:%.*]] = alloca %class.X,
|
|
// CHECK-EH-11: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) %{{.*}}, %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: to label %{{.*}} unwind label %{{.*}}
|
|
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: landingpad { i8*, i32 }
|
|
// CHECK-EH-11: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label %{{.*}}
|
|
|
|
// CHECK-EH-11: resume { i8*, i32 } %
|
|
|
|
// CHECK-EH-11-LABEL: define linkonce_odr void @_Z6test25ILb0EE1Xv(
|
|
// CHECK-EH-11-NEXT: entry:
|
|
// CHECK-EH-11: [[X:%.*]] = alloca %class.X,
|
|
// CHECK-EH-11: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) %{{.*}})
|
|
// CHECK-EH-11-NEXT: to label %{{.*}} unwind label %{{.*}}
|
|
|
|
// CHECK-EH-11: invoke.cont:
|
|
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: ret void
|
|
|
|
// CHECK-EH-11: lpad:
|
|
// CHECK-EH-11-NEXT: landingpad { i8*, i32 }
|
|
// CHECK-EH-11: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
|
|
// CHECK-EH-11-NEXT: br label %{{.*}}
|
|
|
|
// CHECK-EH-11: resume { i8*, i32 } %
|
|
|
|
void test25instantiate() {
|
|
test25<true>();
|
|
test25<false>();
|
|
}
|
|
#endif
|