From b6dab4ebac595c61ed00c8559307a15fd3b9d077 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 28 Mar 2022 11:14:44 -0700 Subject: [PATCH] Pass -disable-llvm-passes to avoid running llvm passes Differential Revision: https://reviews.llvm.org/D122425 --- clang/test/CodeGenCXX/nrvo.cpp | 3001 ++++++++++++++++++++++++-------- 1 file changed, 2311 insertions(+), 690 deletions(-) diff --git a/clang/test/CodeGenCXX/nrvo.cpp b/clang/test/CodeGenCXX/nrvo.cpp index 542d6d98b0a6..c1f5196e8d8c 100644 --- a/clang/test/CodeGenCXX/nrvo.cpp +++ b/clang/test/CodeGenCXX/nrvo.cpp @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py -// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s -// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -disable-llvm-passes -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -disable-llvm-passes -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH-03 %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -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 { @@ -25,13 +25,54 @@ extern X OuterX; // CHECK-LABEL: @_Z5test0v( // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]] +// CHECK-NEXT: [[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]]) #[[ATTR4:[0-9]+]] +// CHECK-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK: nrvo.skipdtor: // CHECK-NEXT: ret void // -// CHECK-EH-LABEL: @_Z5test0v( -// CHECK-EH-NEXT: entry: -// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-NEXT: ret void +// 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]]) #[[ATTR7:[0-9]+]] +// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK-EH-11: nrvo.skipdtor: +// CHECK-EH-11-NEXT: ret void // X test0() { // http://wg21.link/p2025r2#ex-2 X x; @@ -40,13 +81,99 @@ X test0() { // http://wg21.link/p2025r2#ex-2 // CHECK-LABEL: @_Z5test1b( // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// 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, !tbaa [[TBAA3:![0-9]+]] +// 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, !tbaa [[TBAA3]], !range [[RNG7:![0-9]+]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK: nrvo.skipdtor: // CHECK-NEXT: ret void // -// CHECK-EH-LABEL: @_Z5test1b( -// CHECK-EH-NEXT: entry: -// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-NEXT: ret void +// 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, !tbaa [[TBAA3:![0-9]+]] +// 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, !tbaa [[TBAA3]], !range [[RNG7:![0-9]+]] +// 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, !tbaa [[TBAA3:![0-9]+]] +// 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, !tbaa [[TBAA3]], !range [[RNG7:![0-9]+]] +// 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]]) #[[ATTR7]] +// 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; @@ -57,105 +184,202 @@ X test1(bool B) { // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: [[Y_X:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[X]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y_X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-NEXT: [[TMP3:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP4:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP4]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP5:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP5]]) #[[ATTR4]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7:[0-9]+]] +// CHECK-EH-03-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6:[0-9]+]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] // CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-03: invoke.cont: -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[X]] -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP2]]) -// CHECK-EH-03-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD1:%.*]] +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] -// CHECK-EH-03: lpad1: // CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: [[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 [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] +// 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 @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP10:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP10]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP11:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP11]]) #[[ATTR6]] // 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: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD]] ], [ [[TMP4]], [[LPAD1]] ] -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP12:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP12]]) #[[ATTR6]] // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[TERMINATE_LPAD]] // CHECK-EH-03: invoke.cont9: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN]] +// CHECK-EH-03-NEXT: [[TMP13:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP13]]) #[[ATTR6]] +// 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: [[TMP5:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP14:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8:[0-9]+]] +// CHECK-EH-03-NEXT: [[TMP15:%.*]] = extractvalue { i8*, i32 } [[TMP14]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP15]]) #[[ATTR7:[0-9]+]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7:[0-9]+]] +// CHECK-EH-11-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] // CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-11: invoke.cont: -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[X]] -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP2]]) -// CHECK-EH-11-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD1:%.*]] +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] -// CHECK-EH-11: lpad1: // CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } // CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: [[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]]) #[[ATTR7]] // 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP10:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP10]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP11:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP11]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // CHECK-EH-11: ehcleanup: -// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD1]] ], [ [[TMP3]], [[LPAD]] ] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP12:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP12]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] +// CHECK-EH-11-NEXT: [[TMP13:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP13]]) #[[ATTR7]] +// 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; @@ -167,81 +391,161 @@ X test2(bool B) { // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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:%.*]]) #[[ATTR5]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK: nrvo.skipdtor: // CHECK-NEXT: br label [[RETURN:%.*]] // CHECK: if.end: -// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR4]] // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-03: invoke.cont: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[RETURN]] // CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR6]] +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]]) #[[ATTR7]] // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: 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]]) #[[ATTR7]] +// 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-11: invoke.cont: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[RETURN]] // CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] +// 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) { @@ -256,36 +560,129 @@ extern "C" void exit(int) throw(); // CHECK-LABEL: @_Z5test4b( // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] -// CHECK-NEXT: br i1 [[B:%.*]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK-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, !tbaa [[TBAA3]] +// 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, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR5]] -// CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] +// 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) #[[ATTR4]] // 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK-EH-03-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, !tbaa [[TBAA3]] +// 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, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: call void @exit(i32 noundef 1) #[[ATTR7]] +// 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) #[[ATTR6]] // 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK-EH-11-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, !tbaa [[TBAA3]] +// 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, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR7]] +// 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) #[[ATTR7]] // 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) { { @@ -300,111 +697,160 @@ X test4(bool B) { 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 [[TRY_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: invoke.cont: +// CHECK-EH-03-NEXT: br label [[TRY_CONT:%.*]] // CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*) -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0 -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 1 -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)) #[[ATTR7]] -// CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[TMP2]], [[TMP3]] +// CHECK-EH-03-NEXT: [[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*)) #[[ATTR6]] +// 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: [[TMP4:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: [[TMP5:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[TMP1]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast i8* [[TMP5]] to %class.X* -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP6]]) +// CHECK-EH-03-NEXT: [[TMP5:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP5]]) #[[ATTR6]] +// 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]]) #[[ATTR6]] +// 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: [[TMP7:%.*]] = call i8* @__cxa_begin_catch(i8* [[TMP1]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]]) #[[ATTR6]] +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD2:%.*]] // CHECK-EH-03: invoke.cont3: // CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD4:%.*]] // CHECK-EH-03: lpad2: -// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: to label [[EHCLEANUP:%.*]] unwind label [[TERMINATE_LPAD]] -// CHECK-EH-03: invoke.cont5: -// CHECK-EH-03-NEXT: call void @__cxa_end_catch() -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: ret void -// CHECK-EH-03: lpad4: // CHECK-EH-03-NEXT: [[TMP9:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: [[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: [[TMP12:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP12]]) #[[ATTR6]] +// 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: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP9]], [[LPAD4]] ], [ [[TMP8]], [[LPAD2]] ] // CHECK-EH-03-NEXT: invoke void @__cxa_end_catch() // CHECK-EH-03-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[TERMINATE_LPAD]] // CHECK-EH-03: invoke.cont7: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP16:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP16]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[EH_RESUME]] // CHECK-EH-03: try.cont: // CHECK-EH-03-NEXT: unreachable // CHECK-EH-03: eh.resume: -// CHECK-EH-03-NEXT: [[LPAD_VAL11_MERGED:%.*]] = phi { i8*, i32 } [ [[DOTPN]], [[INVOKE_CONT7]] ], [ [[TMP0]], [[LPAD]] ] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL11_MERGED]] +// CHECK-EH-03-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: [[TMP10:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP17:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP11:%.*]] = extractvalue { i8*, i32 } [[TMP10]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP11]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP18:%.*]] = extractvalue { i8*, i32 } [[TMP17]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP18]]) #[[ATTR7]] // 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 [[TRY_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: invoke.cont: +// CHECK-EH-11-NEXT: br label [[TRY_CONT:%.*]] // CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } // CHECK-EH-11-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*) -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0 -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 1 -// CHECK-EH-11-NEXT: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)) #[[ATTR7]] -// CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[TMP2]], [[TMP3]] +// CHECK-EH-11-NEXT: [[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*)) #[[ATTR7]] +// 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: [[TMP4:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: [[TMP5:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[TMP1]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast i8* [[TMP5]] to %class.X* -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP6]]) +// CHECK-EH-11-NEXT: [[TMP5:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP5]]) #[[ATTR7]] +// 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]]) #[[ATTR7]] +// 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: [[TMP7:%.*]] = call i8* @__cxa_begin_catch(i8* [[TMP1]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: [[TMP8:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-11-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD2:%.*]] // CHECK-EH-11: invoke.cont3: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @__cxa_end_catch() -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP9:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP9]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // CHECK-EH-11: lpad2: -// CHECK-EH-11-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] // CHECK-EH-11-NEXT: invoke void @__cxa_end_catch() // CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[TERMINATE_LPAD]] // CHECK-EH-11: invoke.cont4: -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP13:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP13]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[EH_RESUME]] // CHECK-EH-11: try.cont: // CHECK-EH-11-NEXT: unreachable // CHECK-EH-11: eh.resume: -// CHECK-EH-11-NEXT: [[LPAD_VAL7_MERGED:%.*]] = phi { i8*, i32 } [ [[TMP8]], [[INVOKE_CONT4]] ], [ [[TMP0]], [[LPAD]] ] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL7_MERGED]] +// CHECK-EH-11-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: [[TMP9:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: [[TMP14:%.*]] = landingpad { i8*, i32 } // CHECK-EH-11-NEXT: catch i8* null -// CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { i8*, i32 } [[TMP9]], 0 -// CHECK-EH-11-NEXT: call void @__clang_call_terminate(i8* [[TMP10]]) #[[ATTR8:[0-9]+]] +// CHECK-EH-11-NEXT: [[TMP15:%.*]] = extractvalue { i8*, i32 } [[TMP14]], 0 +// CHECK-EH-11-NEXT: call void @__clang_call_terminate(i8* [[TMP15]]) #[[ATTR8:[0-9]+]] // CHECK-EH-11-NEXT: unreachable // X test5() { // http://wg21.link/p2025r2#ex-14 @@ -419,60 +865,98 @@ X test5() { // http://wg21.link/p2025r2#ex-14 // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8* +// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[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: [[TMP1:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6]] // 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: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-03: invoke.cont: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] // CHECK-EH-03-NEXT: ret void // CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR6]] +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP8]]) #[[ATTR7]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[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: [[TMP1:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-11: invoke.cont: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[A]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR7]] +// 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))); @@ -481,13 +965,90 @@ X test6() { // CHECK-LABEL: @_Z5test7b( // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR4]] +// 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-LABEL: @_Z5test7b( -// CHECK-EH-NEXT: entry: -// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-NEXT: ret void +// 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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR7]] +// 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) { @@ -499,13 +1060,117 @@ X test7(bool b) { // CHECK-LABEL: @_Z5test8b( // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: br label [[NRVO_SKIPDTOR4]] +// CHECK: nrvo.skipdtor4: +// CHECK-NEXT: br label [[RETURN]] +// CHECK: return: // CHECK-NEXT: ret void // -// CHECK-EH-LABEL: @_Z5test8b( -// CHECK-EH-NEXT: entry: -// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-NEXT: ret void +// 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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR7]] +// 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]]) #[[ATTR7]] +// 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) { @@ -519,19 +1184,42 @@ X test8(bool b) { // 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:%.*]] = getelementptr inbounds [[STRUCT_Y]], %struct.Y* [[TMP]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* nonnull sret([[STRUCT_Y]]) align 1 [[TMP]]) +// CHECK-NEXT: [[TMP0:%.*]] = bitcast %struct.Y* [[AGG_RESULT:%.*]] to i8* +// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %struct.Y* [[TMP]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* sret([[STRUCT_Y]]) align 1 [[TMP]]) +// CHECK-NEXT: [[TMP2:%.*]] = bitcast %struct.Y* [[TMP]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] // CHECK-NEXT: unreachable // -// CHECK-EH-LABEL: @_Z5test9v( -// CHECK-EH-NEXT: entry: -// CHECK-EH-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1 -// CHECK-EH-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_Y]], %struct.Y* [[TMP]], i32 0, i32 0 -// CHECK-EH-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7:[0-9]+]] -// CHECK-EH-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* nonnull sret([[STRUCT_Y]]) align 1 [[TMP]]) -// CHECK-EH-NEXT: unreachable +// 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: [[TMP1:%.*]] = bitcast %struct.Y* [[TMP]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6]] +// CHECK-EH-03-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* sret([[STRUCT_Y]]) align 1 [[TMP]]) +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = bitcast %struct.Y* [[TMP]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] +// 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: [[TMP1:%.*]] = bitcast %struct.Y* [[TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* sret([[STRUCT_Y]]) align 1 [[TMP]]) +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %struct.Y* [[TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: unreachable // Y test9() { Y::f(); @@ -539,77 +1227,147 @@ Y test9() { // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// 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]]) #[[ATTR5]] +// 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]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR4]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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 [[CLEANUP]] unwind label [[LPAD]] +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR6]] // CHECK-EH-03-NEXT: ret void // CHECK-EH-03: invoke.cont2: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR6]] +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]]) #[[ATTR7]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR7]] +// 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 [[CLEANUP]] unwind label [[LPAD]] +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] // 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; @@ -621,77 +1379,147 @@ X test10(bool b) { // http://wg21.link/p2025r2#ex-3 // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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:%.*]]) #[[ATTR5]] +// 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]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// 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]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR4]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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 [[CLEANUP]] unwind label [[LPAD]] +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR6]] // CHECK-EH-03-NEXT: ret void // CHECK-EH-03: invoke.cont2: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR6]] +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]]) #[[ATTR7]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR7]] +// 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 [[CLEANUP]] unwind label [[LPAD]] +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] // 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; @@ -702,36 +1530,135 @@ X test11(bool b) { // http://wg21.link/p2025r2#ex-5 // CHECK-LABEL: @_Z6test12b( // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] -// CHECK-NEXT: br i1 [[B:%.*]], label [[NRVO_UNUSED:%.*]], label [[RETURN:%.*]] +// 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, !tbaa [[TBAA3]] +// 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, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[NRVO_UNUSED:%.*]], label [[RETURN:%.*]] +// 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, !tbaa [[TBAA3]] +// 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, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[NRVO_UNUSED:%.*]], label [[RETURN:%.*]] +// 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, !tbaa [[TBAA3]] +// 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, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR7]] +// 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 { @@ -745,81 +1672,134 @@ X test12(bool b) { // http://wg21.link/p2025r2#ex-6 // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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:%.*]]) #[[ATTR5]] +// 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR4]] // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) // CHECK-EH-03-NEXT: br label [[RETURN:%.*]] // CHECK-EH-03: if.end: -// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-03: invoke.cont: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[RETURN]] // CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR6]] +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]]) #[[ATTR7]] // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) // CHECK-EH-11-NEXT: br label [[RETURN:%.*]] // CHECK-EH-11: if.end: -// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] // CHECK-EH-11: invoke.cont: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[RETURN]] // CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] +// 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) @@ -830,137 +1810,222 @@ X test13(bool b) { // http://wg21.link/p2025r2#ex-7 // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4 // CHECK-NEXT: br label [[CLEANUP:%.*]] // CHECK: if.end: -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP4:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP4]]) #[[ATTR4]] // CHECK-NEXT: br label [[CLEANUP]] // CHECK: cleanup: -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP5:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP5]]) #[[ATTR4]] // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR6]] // 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.cont2: // 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.cont4: +// 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: lpad1: -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// 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: br label [[EHCLEANUP:%.*]] // CHECK-EH-03: lpad3: -// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// 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 [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT6:%.*]] unwind label [[TERMINATE_LPAD:%.*]] // CHECK-EH-03: invoke.cont5: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP13:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP13]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[CLEANUP]] +// CHECK-EH-03: invoke.cont6: +// CHECK-EH-03-NEXT: br label [[EHCLEANUP]] // CHECK-EH-03: ehcleanup: -// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD1]] ], [ [[TMP4]], [[LPAD3]] ] -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP14:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP14]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[EHCLEANUP7]] // CHECK-EH-03: cleanup: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP15:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP15]]) #[[ATTR6]] // CHECK-EH-03-NEXT: ret void // CHECK-EH-03: ehcleanup7: -// CHECK-EH-03-NEXT: [[DOTPN13:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[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.cont8: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN13]] +// CHECK-EH-03-NEXT: [[TMP16:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP16]]) #[[ATTR6]] +// 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: [[TMP5:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP17:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP18:%.*]] = extractvalue { i8*, i32 } [[TMP17]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP18]]) #[[ATTR7]] // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR7]] // 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.cont2: // 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.cont4: +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[CLEANUP]] // CHECK-EH-11: lpad1: -// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// 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: br label [[EHCLEANUP:%.*]] // CHECK-EH-11: lpad3: -// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[EHCLEANUP]] // CHECK-EH-11: ehcleanup: -// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD3]] ], [ [[TMP3]], [[LPAD1]] ] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP14:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP14]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[EHCLEANUP5]] // CHECK-EH-11: cleanup: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP15:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP15]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // CHECK-EH-11: ehcleanup5: -// CHECK-EH-11-NEXT: [[DOTPN10:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN10]] +// CHECK-EH-11-NEXT: [[TMP16:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP16]]) #[[ATTR7]] +// 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; @@ -972,137 +2037,222 @@ X test14(bool b) { // http://wg21.link/p2025r2#ex-8 // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-NEXT: store i32 1, i32* [[CLEANUP_DEST_SLOT]], align 4 // CHECK-NEXT: br label [[CLEANUP:%.*]] // CHECK: if.end: -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP4:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP4]]) #[[ATTR4]] // CHECK-NEXT: br label [[CLEANUP]] // CHECK: cleanup: -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP5:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP5]]) #[[ATTR4]] // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR6]] // 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.cont2: // 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.cont4: +// 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: lpad1: -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// 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: br label [[EHCLEANUP:%.*]] // CHECK-EH-03: lpad3: -// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// 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 [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT6:%.*]] unwind label [[TERMINATE_LPAD:%.*]] // CHECK-EH-03: invoke.cont5: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP13:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP13]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[CLEANUP]] +// CHECK-EH-03: invoke.cont6: +// CHECK-EH-03-NEXT: br label [[EHCLEANUP]] // CHECK-EH-03: ehcleanup: -// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD1]] ], [ [[TMP4]], [[LPAD3]] ] -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP14:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP14]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[EHCLEANUP7]] // CHECK-EH-03: cleanup: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP15:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP15]]) #[[ATTR6]] // CHECK-EH-03-NEXT: ret void // CHECK-EH-03: ehcleanup7: -// CHECK-EH-03-NEXT: [[DOTPN13:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[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.cont8: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN13]] +// CHECK-EH-03-NEXT: [[TMP16:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP16]]) #[[ATTR6]] +// 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: [[TMP5:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP17:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP18:%.*]] = extractvalue { i8*, i32 } [[TMP17]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP18]]) #[[ATTR7]] // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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 [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR7]] // 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.cont2: // 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.cont4: +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[CLEANUP]] // CHECK-EH-11: lpad1: -// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// 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: br label [[EHCLEANUP:%.*]] // CHECK-EH-11: lpad3: -// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[EHCLEANUP]] // CHECK-EH-11: ehcleanup: -// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD3]] ], [ [[TMP3]], [[LPAD1]] ] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP14:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP14]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[EHCLEANUP5]] // CHECK-EH-11: cleanup: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP15:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP15]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // CHECK-EH-11: ehcleanup5: -// CHECK-EH-11-NEXT: [[DOTPN10:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN10]] +// CHECK-EH-11-NEXT: [[TMP16:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP16]]) #[[ATTR7]] +// 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; @@ -1117,33 +2267,59 @@ X test15(bool b) { // http://wg21.link/p2025r2#ex-15 // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[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: [[TMP0:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP0]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = bitcast %class.anon* [[REF_TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[TMP1]]) #[[ATTR7]] +// 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, !tbaa [[TBAA8:![0-9]+]] +// 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 nonnull [[AGG_TMP]]) +// 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]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = bitcast %class.anon* [[REF_TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP3]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP4:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP4]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[EHCLEANUP]] // CHECK-EH-11: ehcleanup: -// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP2]], [[LPAD1]] ], [ [[TMP1]], [[LPAD]] ] +// CHECK-EH-11-NEXT: [[TMP11:%.*]] = bitcast %class.anon* [[REF_TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP11]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] +// CHECK-EH-11-NEXT: [[TMP12:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP12]]) #[[ATTR7]] +// 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; @@ -1156,50 +2332,95 @@ void test16() { // http://wg21.link/p2025r2#ex-9 // CHECK-LABEL: @_Z6test17i( // CHECK-NEXT: entry: -// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 3 -// CHECK-NEXT: br label [[WHILE_BODY:%.*]] +// 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, !tbaa [[TBAA8:![0-9]+]] +// CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]] +// CHECK: if.then: +// CHECK-NEXT: br label [[IMPOSSIBLE:%.*]] // CHECK: impossible: -// CHECK-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[WHILE_BODY_BACKEDGE:%.*]] -// CHECK: while.body.backedge: -// CHECK-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3:![0-9]+]] +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA8]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] -// CHECK-NEXT: switch i32 [[I]], label [[IF_END20:%.*]] [ -// CHECK-NEXT: i32 0, label [[CLEANUP:%.*]] -// CHECK-NEXT: i32 1, label [[IF_THEN7:%.*]] -// CHECK-NEXT: i32 2, label [[IF_THEN10:%.*]] -// CHECK-NEXT: i32 3, label [[IF_THEN13:%.*]] -// CHECK-NEXT: i32 4, label [[IF_THEN16:%.*]] -// CHECK-NEXT: i32 5, label [[CLEANUP]] -// CHECK-NEXT: ] +// 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, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2 +// CHECK-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]] // CHECK: if.then10: -// CHECK-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3]] +// 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, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// 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) #[[ATTR5]] -// CHECK-NEXT: br label [[IF_END20]] +// CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR4]] +// CHECK-NEXT: br label [[IF_END17]] +// CHECK: if.end17: +// CHECK-NEXT: [[TMP7:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA8]] +// 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_0:%.*]] = phi i1 [ false, [[IF_THEN7]] ], [ false, [[IF_THEN10]] ], [ false, [[IF_THEN13]] ], [ false, [[IF_END20]] ], [ true, [[WHILE_BODY]] ], [ true, [[WHILE_BODY]] ] -// CHECK-NEXT: [[CLEANUP_DEST_SLOT_0:%.*]] = phi i32 [ 4, [[IF_THEN7]] ], [ 3, [[IF_THEN10]] ], [ 2, [[IF_THEN13]] ], [ 0, [[IF_END20]] ], [ 1, [[WHILE_BODY]] ], [ 1, [[WHILE_BODY]] ] -// CHECK-NEXT: br i1 [[NRVO_0]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] +// 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]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] // CHECK-NEXT: br label [[NRVO_SKIPDTOR]] // CHECK: nrvo.skipdtor: -// CHECK-NEXT: switch i32 [[CLEANUP_DEST_SLOT_0]], label [[UNREACHABLE:%.*]] [ -// CHECK-NEXT: i32 0, label [[WHILE_BODY_BACKEDGE]] -// CHECK-NEXT: i32 1, label [[RETURN:%.*]] -// CHECK-NEXT: i32 4, label [[RETURN_SINK_SPLIT]] -// CHECK-NEXT: i32 3, label [[WHILE_BODY_BACKEDGE]] -// CHECK-NEXT: i32 2, label [[IMPOSSIBLE:%.*]] +// 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: return.sink.split: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// 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 @@ -1208,49 +2429,94 @@ void test16() { // http://wg21.link/p2025r2#ex-9 // // CHECK-EH-03-LABEL: @_Z6test17i( // CHECK-EH-03-NEXT: entry: -// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 3 -// CHECK-EH-03-NEXT: br label [[WHILE_BODY:%.*]] +// 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, !tbaa [[TBAA8:![0-9]+]] +// 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: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[WHILE_BODY_BACKEDGE:%.*]] -// CHECK-EH-03: while.body.backedge: -// CHECK-EH-03-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3:![0-9]+]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA8]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-03-NEXT: switch i32 [[I]], label [[IF_END20:%.*]] [ -// CHECK-EH-03-NEXT: i32 0, label [[CLEANUP:%.*]] -// CHECK-EH-03-NEXT: i32 1, label [[IF_THEN7:%.*]] -// CHECK-EH-03-NEXT: i32 2, label [[IF_THEN10:%.*]] -// CHECK-EH-03-NEXT: i32 3, label [[IF_THEN13:%.*]] -// CHECK-EH-03-NEXT: i32 4, label [[IF_THEN16:%.*]] -// CHECK-EH-03-NEXT: i32 5, label [[CLEANUP]] -// CHECK-EH-03-NEXT: ] +// 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, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// 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: br label [[CLEANUP]], !llvm.loop [[LOOP3]] +// CHECK-EH-03-NEXT: store i32 3, i32* [[CLEANUP_DEST_SLOT]], align 4 +// CHECK-EH-03-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP10:![0-9]+]] +// CHECK-EH-03: if.end11: +// CHECK-EH-03-NEXT: [[TMP5:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// CHECK-EH-03-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4 +// CHECK-EH-03-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]] // CHECK-EH-03: if.then16: -// CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[IF_END20]] +// CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR6]] +// 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, !tbaa [[TBAA8]] +// 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_0:%.*]] = phi i1 [ false, [[IF_THEN7]] ], [ false, [[IF_THEN10]] ], [ false, [[IF_THEN13]] ], [ false, [[IF_END20]] ], [ true, [[WHILE_BODY]] ], [ true, [[WHILE_BODY]] ] -// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT_0:%.*]] = phi i32 [ 4, [[IF_THEN7]] ], [ 3, [[IF_THEN10]] ], [ 2, [[IF_THEN13]] ], [ 0, [[IF_END20]] ], [ 1, [[WHILE_BODY]] ], [ 1, [[WHILE_BODY]] ] -// CHECK-EH-03-NEXT: br i1 [[NRVO_0]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] +// 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: switch i32 [[CLEANUP_DEST_SLOT_0]], label [[UNREACHABLE:%.*]] [ -// CHECK-EH-03-NEXT: i32 0, label [[WHILE_BODY_BACKEDGE]] -// CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]] -// CHECK-EH-03-NEXT: i32 4, label [[RETURN_SINK_SPLIT]] -// CHECK-EH-03-NEXT: i32 3, label [[WHILE_BODY_BACKEDGE]] -// CHECK-EH-03-NEXT: i32 2, label [[IMPOSSIBLE:%.*]] +// 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: return.sink.split: +// CHECK-EH-03: cleanup.cont: +// CHECK-EH-03-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP10]] +// 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: @@ -1260,49 +2526,94 @@ void test16() { // http://wg21.link/p2025r2#ex-9 // // CHECK-EH-11-LABEL: @_Z6test17i( // CHECK-EH-11-NEXT: entry: -// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 3 -// CHECK-EH-11-NEXT: br label [[WHILE_BODY:%.*]] +// 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, !tbaa [[TBAA12:![0-9]+]] +// 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: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[WHILE_BODY_BACKEDGE:%.*]] -// CHECK-EH-11: while.body.backedge: -// CHECK-EH-11-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3:![0-9]+]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA12]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-11-NEXT: switch i32 [[I]], label [[IF_END20:%.*]] [ -// CHECK-EH-11-NEXT: i32 0, label [[CLEANUP:%.*]] -// CHECK-EH-11-NEXT: i32 1, label [[IF_THEN7:%.*]] -// CHECK-EH-11-NEXT: i32 2, label [[IF_THEN10:%.*]] -// CHECK-EH-11-NEXT: i32 3, label [[IF_THEN13:%.*]] -// CHECK-EH-11-NEXT: i32 4, label [[IF_THEN16:%.*]] -// CHECK-EH-11-NEXT: i32 5, label [[CLEANUP]] -// CHECK-EH-11-NEXT: ] +// 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, !tbaa [[TBAA12]] +// 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, !tbaa [[TBAA12]] +// 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, !tbaa [[TBAA12]] +// 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: br label [[CLEANUP]], !llvm.loop [[LOOP3]] +// 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, !tbaa [[TBAA12]] +// 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, !tbaa [[TBAA12]] +// 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) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[IF_END20]] +// 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, !tbaa [[TBAA12]] +// 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_0:%.*]] = phi i1 [ false, [[IF_THEN7]] ], [ false, [[IF_THEN10]] ], [ false, [[IF_THEN13]] ], [ false, [[IF_END20]] ], [ true, [[WHILE_BODY]] ], [ true, [[WHILE_BODY]] ] -// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT_0:%.*]] = phi i32 [ 4, [[IF_THEN7]] ], [ 3, [[IF_THEN10]] ], [ 2, [[IF_THEN13]] ], [ 0, [[IF_END20]] ], [ 1, [[WHILE_BODY]] ], [ 1, [[WHILE_BODY]] ] -// CHECK-EH-11-NEXT: br i1 [[NRVO_0]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] +// 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]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] // CHECK-EH-11: nrvo.skipdtor: -// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST_SLOT_0]], label [[UNREACHABLE:%.*]] [ -// CHECK-EH-11-NEXT: i32 0, label [[WHILE_BODY_BACKEDGE]] -// CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]] -// CHECK-EH-11-NEXT: i32 4, label [[RETURN_SINK_SPLIT]] -// CHECK-EH-11-NEXT: i32 3, label [[WHILE_BODY_BACKEDGE]] -// CHECK-EH-11-NEXT: i32 2, label [[IMPOSSIBLE:%.*]] +// 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: return.sink.split: +// 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: @@ -1337,151 +2648,300 @@ X test17(int i) { // http://wg21.link/p2025r2#ex-10 // 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] -// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 -// CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// 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, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// 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]]) #[[ATTR5]] -// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 -// CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT7_CRITEDGE:%.*]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]] +// 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: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA8]] +// 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]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: br label [[RETURN]] -// CHECK: cleanup.cont7.critedge: -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP4:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP4]]) #[[ATTR4]] +// 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.cont7: +// CHECK-NEXT: [[TMP5:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP5]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR4]] // 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 -// CHECK-EH-03-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// 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, !tbaa [[TBAA8]] +// 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, !tbaa [[TBAA8]] +// 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// 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: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 -// CHECK-EH-03-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT8_CRITEDGE:%.*]] +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA8]] +// 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 [[CLEANUP4:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br i1 [[CMP1]], label [[RETURN]], label [[CLEANUP_CONT8:%.*]] -// CHECK-EH-03: cleanup.cont8.critedge: -// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[CLEANUP_CONT8]] +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR6]] +// 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.cont8: -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP8]]) #[[ATTR6]] // 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.cont10: +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP9:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP9]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[RETURN]] // CHECK-EH-03: invoke.cont5: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP10:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP10]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] // CHECK-EH-03: lpad9: -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// 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.cont12: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP14:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP14]]) #[[ATTR6]] // 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: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[INVOKE_CONT12]] ], [ [[TMP1]], [[INVOKE_CONT5]] ] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN]] +// 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: [[TMP4:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP15:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP5]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP16:%.*]] = extractvalue { i8*, i32 } [[TMP15]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP16]]) #[[ATTR7]] +// 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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 -// CHECK-EH-11-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// 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, !tbaa [[TBAA12]] +// 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, !tbaa [[TBAA12]] +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// 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: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-11-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 -// CHECK-EH-11-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT7_CRITEDGE:%.*]] +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = load i32, i32* [[I_ADDR]], align 4, !tbaa [[TBAA12]] +// 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 [[CLEANUP4:%.*]] unwind label [[LPAD:%.*]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] // 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br i1 [[CMP1]], label [[RETURN]], label [[CLEANUP_CONT7:%.*]] -// CHECK-EH-11: cleanup.cont7.critedge: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[CLEANUP_CONT7]] +// CHECK-EH-11-NEXT: [[TMP8:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP8]]) #[[ATTR7]] +// 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.cont7: -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP9:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP9]]) #[[ATTR7]] // 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.cont9: +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP10:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP10]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[RETURN]] // CHECK-EH-11: lpad8: -// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP14:%.*]] = bitcast %class.X* [[Z]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP14]]) #[[ATTR7]] // 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: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD8]] ], [ [[TMP1]], [[LPAD]] ] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] +// 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 { @@ -1501,22 +2961,57 @@ X test18(int i) { // http://wg21.link/p2025r2#ex-11 #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: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[L]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[L]]) +// 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: [[TMP1:%.*]] = bitcast %class.X* [[L]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %class.anon.0* [[REF_TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[TMP2]]) #[[ATTR7]] +// 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, !tbaa [[TBAA8]] +// 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: [[TMP4:%.*]] = bitcast %class.anon.0* [[REF_TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP4]]) #[[ATTR7]] +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11-NEXT: [[TMP5:%.*]] = bitcast %class.X* [[L]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP5]]) #[[ATTR7]] +// 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: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: [[TMP6:%.*]] = landingpad { i8*, i32 } // CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// 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: [[TMP9:%.*]] = bitcast %class.anon.0* [[REF_TMP]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP9]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP10:%.*]] = bitcast %class.X* [[L]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP10]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// 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]]) #[[ATTR7]] +// 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; @@ -1542,42 +3037,11 @@ X test20() { // http://wg21.link/p2025r2#ex-18 // CHECK-EH-11-LABEL: @_Z17test20instantiatev( // CHECK-EH-11-NEXT: entry: -// CHECK-EH-11-NEXT: [[X_I2:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-11-NEXT: [[X_I:%.*]] = alloca [[CLASS_X]], align 1 -// CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[CLASS_X]], align 1 +// 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X_I]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !6 -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]), !noalias !6 -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) -// CHECK-EH-11-NEXT: to label [[_Z6TEST20ILB1EE1XV_EXIT:%.*]] unwind label [[LPAD_I:%.*]] -// CHECK-EH-11: common.resume: -// CHECK-EH-11-NEXT: [[COMMON_RESUME_OP:%.*]] = phi { i8*, i32 } [ [[TMP1:%.*]], [[LPAD_I]] ], [ [[TMP3:%.*]], [[LPAD_I3:%.*]] ] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[COMMON_RESUME_OP]] -// CHECK-EH-11: lpad.i: -// CHECK-EH-11-NEXT: [[TMP1]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !6 -// CHECK-EH-11-NEXT: br label [[COMMON_RESUME:%.*]] -// CHECK-EH-11: _Z6test20ILb1EE1Xv.exit: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !6 +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X_I2]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !9 -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]), !noalias !9 -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) -// CHECK-EH-11-NEXT: to label [[_Z6TEST20ILB0EE1XV_EXIT:%.*]] unwind label [[LPAD_I3]] -// CHECK-EH-11: lpad.i3: -// CHECK-EH-11-NEXT: [[TMP3]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !9 -// CHECK-EH-11-NEXT: br label [[COMMON_RESUME]] -// CHECK-EH-11: _Z6test20ILb0EE1Xv.exit: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !9 +// 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]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // @@ -1589,13 +3053,54 @@ void test20instantiate() { // CHECK-LABEL: @_Z6test21v( // CHECK-NEXT: entry: -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK: nrvo.skipdtor: // CHECK-NEXT: ret void // -// CHECK-EH-LABEL: @_Z6test21v( -// CHECK-EH-NEXT: entry: -// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-NEXT: ret void +// 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]]) #[[ATTR7]] +// 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; @@ -1604,60 +3109,98 @@ const volatile X test21() { // http://wg21.link/p2025r2#ex-19 // 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:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast %class.X* [[AGG_RESULT:%.*]] to i8* +// CHECK-NEXT: store i8* [[TMP0]], i8** [[RESULT_PTR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[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: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR6]] // 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: 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] // CHECK-EH-03-NEXT: ret void // CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR6]] +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { i8*, i32 } [[TMP7]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP8]]) #[[ATTR7]] // 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[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: [[TMP1:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP1]]) #[[ATTR7]] // 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: 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void // CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast %class.X* [[X]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP6]]) #[[ATTR7]] +// 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; @@ -1666,81 +3209,161 @@ X test22() { // http://wg21.link/p2025r2#ex-19 // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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:%.*]]) #[[ATTR5]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK: nrvo.skipdtor: // CHECK-NEXT: br label [[RETURN:%.*]] // CHECK: if.end: -// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR4]] +// 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]]) #[[ATTR4]] +// CHECK-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR4]] // CHECK-NEXT: br label [[RETURN]] // CHECK: return: // CHECK-NEXT: ret void // // CHECK-EH-03-LABEL: @_Z6test23b( // CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR6]] // 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR6]] // CHECK-EH-03-NEXT: br label [[RETURN]] // CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR6]] +// 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: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { i8*, i32 } [[TMP8]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP9]]) #[[ATTR7]] // 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: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// 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, !tbaa [[TBAA3]] +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, i8* [[B_ADDR]], align 1, !tbaa [[TBAA3]], !range [[RNG7]] +// 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: 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]]) #[[ATTR7]] +// 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* [[TMP2]]) #[[ATTR7]] // 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP3]]) #[[ATTR7]] // CHECK-EH-11-NEXT: br label [[RETURN]] // CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// 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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11-NEXT: [[TMP7:%.*]] = bitcast %class.X* [[Y]] to i8* +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* [[TMP7]]) #[[ATTR7]] +// 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) { @@ -1752,10 +3375,39 @@ X test23(bool b) { // http://wg21.link/p2025r2#ex-19 } #ifdef __EXCEPTIONS -// CHECK-EH-LABEL: @_Z6test24v( -// CHECK-EH-NEXT: entry: -// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-NEXT: ret void +// 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]]) #[[ATTR7]] +// 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; @@ -1778,42 +3430,11 @@ X test25() { // CHECK-EH-11-LABEL: @_Z17test25instantiatev( // CHECK-EH-11-NEXT: entry: -// CHECK-EH-11-NEXT: [[X_I2:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-11-NEXT: [[X_I:%.*]] = alloca [[CLASS_X]], align 1 -// CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[CLASS_X]], align 1 +// 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: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X_I]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !12 -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]), !noalias !12 -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) -// CHECK-EH-11-NEXT: to label [[_Z6TEST25ILB1EE1XV_EXIT:%.*]] unwind label [[LPAD_I:%.*]] -// CHECK-EH-11: common.resume: -// CHECK-EH-11-NEXT: [[COMMON_RESUME_OP:%.*]] = phi { i8*, i32 } [ [[TMP1:%.*]], [[LPAD_I]] ], [ [[TMP3:%.*]], [[LPAD_I3:%.*]] ] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[COMMON_RESUME_OP]] -// CHECK-EH-11: lpad.i: -// CHECK-EH-11-NEXT: [[TMP1]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !12 -// CHECK-EH-11-NEXT: br label [[COMMON_RESUME:%.*]] -// CHECK-EH-11: _Z6test25ILb1EE1Xv.exit: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !12 +// CHECK-EH-11-NEXT: call void @_Z6test25ILb1EE1Xv(%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]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X_I2]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !15 -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]), !noalias !15 -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]]) -// CHECK-EH-11-NEXT: to label [[_Z6TEST25ILB0EE1XV_EXIT:%.*]] unwind label [[LPAD_I3]] -// CHECK-EH-11: lpad.i3: -// CHECK-EH-11-NEXT: [[TMP3]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !15 -// CHECK-EH-11-NEXT: br label [[COMMON_RESUME]] -// CHECK-EH-11: _Z6test25ILb0EE1Xv.exit: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !15 +// CHECK-EH-11-NEXT: call void @_Z6test25ILb0EE1Xv(%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]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void //