|  | // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s | 
|  | // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fcxx-exceptions -fexceptions -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s | 
|  |  | 
|  | // CHECK: %[[STRUCT_SMALL:.*]] = type { i32* } | 
|  | // CHECK: %[[STRUCT_LARGE:.*]] = type { i32*, [128 x i32] } | 
|  | // CHECK: %[[STRUCT_TRIVIAL:.*]] = type { i32 } | 
|  | // CHECK: %[[STRUCT_NONTRIVIAL:.*]] = type { i32 } | 
|  |  | 
|  | struct __attribute__((trivial_abi)) Small { | 
|  | int *p; | 
|  | Small(); | 
|  | ~Small(); | 
|  | Small(const Small &) noexcept; | 
|  | Small &operator=(const Small &); | 
|  | }; | 
|  |  | 
|  | struct __attribute__((trivial_abi)) Large { | 
|  | int *p; | 
|  | int a[128]; | 
|  | Large(); | 
|  | ~Large(); | 
|  | Large(const Large &) noexcept; | 
|  | Large &operator=(const Large &); | 
|  | }; | 
|  |  | 
|  | struct Trivial { | 
|  | int a; | 
|  | }; | 
|  |  | 
|  | struct NonTrivial { | 
|  | NonTrivial(); | 
|  | ~NonTrivial(); | 
|  | int a; | 
|  | }; | 
|  |  | 
|  | struct HasTrivial { | 
|  | Small s; | 
|  | Trivial m; | 
|  | }; | 
|  |  | 
|  | struct HasNonTrivial { | 
|  | Small s; | 
|  | NonTrivial m; | 
|  | }; | 
|  |  | 
|  | // CHECK: define void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]]) | 
|  | // CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8 | 
|  | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[A]], i32 0, i32 0 | 
|  | // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i32* | 
|  | // CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8 | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* %[[A]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testParamSmall(Small a) noexcept { | 
|  | } | 
|  |  | 
|  | // CHECK: define i64 @_Z15testReturnSmallv() | 
|  | // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8 | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* %[[RETVAL]]) | 
|  | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[RETVAL]], i32 0, i32 0 | 
|  | // CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE]], align 8 | 
|  | // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64 | 
|  | // CHECK: ret i64 %[[COERCE_VAL_PI]] | 
|  | // CHECK: } | 
|  |  | 
|  | Small testReturnSmall() { | 
|  | Small t; | 
|  | return t; | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z14testCallSmall0v() | 
|  | // CHECK: %[[T:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8 | 
|  | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL]], align 8 | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* %[[T]]) | 
|  | // CHECK: %[[CALL1:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallC1ERKS_(%[[STRUCT_SMALL]]* %[[AGG_TMP]], %[[STRUCT_SMALL]]* dereferenceable(8) %[[T]]) | 
|  | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0 | 
|  | // CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE]], align 8 | 
|  | // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64 | 
|  | // CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]]) | 
|  | // CHECK: %[[CALL2:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* %[[T]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testCallSmall0() { | 
|  | Small t; | 
|  | testParamSmall(t); | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z14testCallSmall1v() | 
|  | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8 | 
|  | // CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv() | 
|  | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0 | 
|  | // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32* | 
|  | // CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8 | 
|  | // CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0 | 
|  | // CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE1]], align 8 | 
|  | // CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64 | 
|  | // CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testCallSmall1() { | 
|  | testParamSmall(testReturnSmall()); | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z16testIgnoredSmallv() | 
|  | // CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8 | 
|  | // CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv() | 
|  | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP_ENSURED]], i32 0, i32 0 | 
|  | // CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32* | 
|  | // CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8 | 
|  | // CHECK: %[[CALL1:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* %[[AGG_TMP_ENSURED]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testIgnoredSmall() { | 
|  | testReturnSmall(); | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z14testParamLarge5Large(%[[STRUCT_LARGE:.*]]* %[[A:.*]]) | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[A]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testParamLarge(Large a) noexcept { | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z15testReturnLargev(%[[STRUCT_LARGE:.*]]* noalias sret %[[AGG_RESULT:.*]]) | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[AGG_RESULT]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | Large testReturnLarge() { | 
|  | Large t; | 
|  | return t; | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z14testCallLarge0v() | 
|  | // CHECK: %[[T:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8 | 
|  | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE]], align 8 | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[T]]) | 
|  | // CHECK: %[[CALL1:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1ERKS_(%[[STRUCT_LARGE]]* %[[AGG_TMP]], %[[STRUCT_LARGE]]* dereferenceable(520) %[[T]]) | 
|  | // CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* %[[AGG_TMP]]) | 
|  | // CHECK: %[[CALL2:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[T]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testCallLarge0() { | 
|  | Large t; | 
|  | testParamLarge(t); | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z14testCallLarge1v() | 
|  | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8 | 
|  | // CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP]]) | 
|  | // CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* %[[AGG_TMP]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testCallLarge1() { | 
|  | testParamLarge(testReturnLarge()); | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z16testIgnoredLargev() | 
|  | // CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8 | 
|  | // CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP_ENSURED]]) | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[AGG_TMP_ENSURED]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | void testIgnoredLarge() { | 
|  | testReturnLarge(); | 
|  | } | 
|  |  | 
|  | // CHECK: define i64 @_Z20testReturnHasTrivialv() | 
|  | // CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_TRIVIAL:.*]], align 4 | 
|  | // CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_TRIVIAL]], %[[STRUCT_TRIVIAL]]* %[[RETVAL]], i32 0, i32 0 | 
|  | // CHECK: %[[V0:.*]] = load i32, i32* %[[COERCE_DIVE]], align 4 | 
|  | // CHECK: %[[COERCE_VAL_II:.*]] = zext i32 %[[V0]] to i64 | 
|  | // CHECK: ret i64 %[[COERCE_VAL_II]] | 
|  | // CHECK: } | 
|  |  | 
|  | Trivial testReturnHasTrivial() { | 
|  | Trivial t; | 
|  | return t; | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z23testReturnHasNonTrivialv(%[[STRUCT_NONTRIVIAL:.*]]* noalias sret %[[AGG_RESULT:.*]]) | 
|  | // CHECK: %[[CALL:.*]] = call %[[STRUCT_NONTRIVIAL]]* @_ZN10NonTrivialC1Ev(%[[STRUCT_NONTRIVIAL]]* %[[AGG_RESULT]]) | 
|  | // CHECK: ret void | 
|  | // CHECK: } | 
|  |  | 
|  | NonTrivial testReturnHasNonTrivial() { | 
|  | NonTrivial t; | 
|  | return t; | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z18testExceptionSmallv() | 
|  | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL]], align 8 | 
|  | // CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_SMALL]], align 8 | 
|  | // CHECK: call %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* %[[AGG_TMP]]) | 
|  | // CHECK: invoke %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* %[[AGG_TMP1]]) | 
|  |  | 
|  | // CHECK: call void @_Z20calleeExceptionSmall5SmallS_(i64 %{{.*}}, i64 %{{.*}}) | 
|  | // CHECK-NEXT: ret void | 
|  |  | 
|  | // CHECK: landingpad { i8*, i32 } | 
|  | // CHECK: call %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* %[[AGG_TMP]]) | 
|  | // CHECK: br | 
|  |  | 
|  | // CHECK: resume { i8*, i32 } | 
|  |  | 
|  | void calleeExceptionSmall(Small, Small); | 
|  |  | 
|  | void testExceptionSmall() { | 
|  | calleeExceptionSmall(Small(), Small()); | 
|  | } | 
|  |  | 
|  | // CHECK: define void @_Z18testExceptionLargev() | 
|  | // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE]], align 8 | 
|  | // CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_LARGE]], align 8 | 
|  | // CHECK: call %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[AGG_TMP]]) | 
|  | // CHECK: invoke %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[AGG_TMP1]]) | 
|  |  | 
|  | // CHECK: call void @_Z20calleeExceptionLarge5LargeS_(%[[STRUCT_LARGE]]* %[[AGG_TMP]], %[[STRUCT_LARGE]]* %[[AGG_TMP1]]) | 
|  | // CHECK-NEXT: ret void | 
|  |  | 
|  | // CHECK: landingpad { i8*, i32 } | 
|  | // CHECK: call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[AGG_TMP]]) | 
|  | // CHECK: br | 
|  |  | 
|  | // CHECK: resume { i8*, i32 } | 
|  |  | 
|  | void calleeExceptionLarge(Large, Large); | 
|  |  | 
|  | void testExceptionLarge() { | 
|  | calleeExceptionLarge(Large(), Large()); | 
|  | } |