mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 12:16:09 +00:00

registers. This patch fixes a bug in r328731 that caused structs transitively containing __weak fields to be passed in registers. The patch replaces the flag RecordDecl::CanPassInRegisters with a 2-bit enum that indicates whether the struct or structs containing the struct are forced to be passed indirectly. This reapplies r329617. r329617 didn't specify the underlying type for enum ArgPassingKind, which caused regression tests to fail on a windows bot. rdar://problem/39194693 Differential Revision: https://reviews.llvm.org/D45384 llvm-svn: 329635
181 lines
7.4 KiB
Plaintext
181 lines
7.4 KiB
Plaintext
// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
|
|
// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
|
|
// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
|
|
// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
|
|
|
|
// Check that structs consisting solely of __strong or __weak pointer fields are
|
|
// destructed in the callee function and structs consisting solely of __strong
|
|
// pointer fields are passed directly.
|
|
|
|
// CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* }
|
|
// CHECK: %[[STRUCT_CONTAINSSTRONGWEAK:.*]] = type { %[[STRUCT_STRONGWEAK]] }
|
|
// CHECK: %[[STRUCT_DERIVEDSTRONGWEAK:.*]] = type { %[[STRUCT_STRONGWEAK]] }
|
|
// CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
|
|
// CHECK: %[[STRUCT_S:.*]] = type { i8* }
|
|
// CHECK: %[[STRUCT_CONTAINSNONTRIVIAL:.*]] = type { %{{.*}}, i8* }
|
|
|
|
#ifdef TRIVIALABI
|
|
struct __attribute__((trivial_abi)) StrongWeak {
|
|
#else
|
|
struct StrongWeak {
|
|
#endif
|
|
id fstrong;
|
|
__weak id fweak;
|
|
};
|
|
|
|
#ifdef TRIVIALABI
|
|
struct __attribute__((trivial_abi)) ContainsStrongWeak {
|
|
#else
|
|
struct ContainsStrongWeak {
|
|
#endif
|
|
StrongWeak sw;
|
|
};
|
|
|
|
#ifdef TRIVIALABI
|
|
struct __attribute__((trivial_abi)) DerivedStrongWeak : StrongWeak {
|
|
#else
|
|
struct DerivedStrongWeak : StrongWeak {
|
|
#endif
|
|
};
|
|
|
|
#ifdef TRIVIALABI
|
|
struct __attribute__((trivial_abi)) Strong {
|
|
#else
|
|
struct Strong {
|
|
#endif
|
|
id fstrong;
|
|
};
|
|
|
|
template<class T>
|
|
#ifdef TRIVIALABI
|
|
struct __attribute__((trivial_abi)) S {
|
|
#else
|
|
struct S {
|
|
#endif
|
|
T a;
|
|
};
|
|
|
|
struct NonTrivial {
|
|
NonTrivial();
|
|
NonTrivial(const NonTrivial &);
|
|
~NonTrivial();
|
|
int *a;
|
|
};
|
|
|
|
// This struct is not passed directly nor destructed in the callee because f0
|
|
// has type NonTrivial.
|
|
struct ContainsNonTrivial {
|
|
NonTrivial f0;
|
|
id f1;
|
|
};
|
|
|
|
// CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}})
|
|
// CHECK: call %struct.StrongWeak* @_ZN10StrongWeakD1Ev(
|
|
// CHECK-NEXT: ret void
|
|
|
|
void testParamStrongWeak(StrongWeak a) {
|
|
}
|
|
|
|
// CHECK: define void @_Z18testCallStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[A:.*]])
|
|
// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8
|
|
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8
|
|
// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
|
|
// CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
|
|
// CHECK-NOT: call
|
|
// CHECK: ret void
|
|
|
|
void testCallStrongWeak(StrongWeak *a) {
|
|
testParamStrongWeak(*a);
|
|
}
|
|
|
|
// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]])
|
|
// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8
|
|
// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_RESULT]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
|
|
// CHECK: ret void
|
|
|
|
StrongWeak testReturnStrongWeak(StrongWeak *a) {
|
|
return *a;
|
|
}
|
|
|
|
// CHECK: define void @_Z27testParamContainsStrongWeak18ContainsStrongWeak(%[[STRUCT_CONTAINSSTRONGWEAK]]* %[[A:.*]])
|
|
// CHECK: call %[[STRUCT_CONTAINSSTRONGWEAK]]* @_ZN18ContainsStrongWeakD1Ev(%[[STRUCT_CONTAINSSTRONGWEAK]]* %[[A]])
|
|
|
|
void testParamContainsStrongWeak(ContainsStrongWeak a) {
|
|
}
|
|
|
|
// CHECK: define void @_Z26testParamDerivedStrongWeak17DerivedStrongWeak(%[[STRUCT_DERIVEDSTRONGWEAK]]* %[[A:.*]])
|
|
// CHECK: call %[[STRUCT_DERIVEDSTRONGWEAK]]* @_ZN17DerivedStrongWeakD1Ev(%[[STRUCT_DERIVEDSTRONGWEAK]]* %[[A]])
|
|
|
|
void testParamDerivedStrongWeak(DerivedStrongWeak a) {
|
|
}
|
|
|
|
// CHECK: define void @_Z15testParamStrong6Strong(i64 %[[A_COERCE:.*]])
|
|
// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG]], align 8
|
|
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[A]], i32 0, i32 0
|
|
// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i8*
|
|
// CHECK: store i8* %[[COERCE_VAL_IP]], i8** %[[COERCE_DIVE]], align 8
|
|
// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(%[[STRUCT_STRONG]]* %[[A]])
|
|
// CHECK: ret void
|
|
|
|
// CHECK: define linkonce_odr %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(
|
|
|
|
void testParamStrong(Strong a) {
|
|
}
|
|
|
|
// CHECK: define void @_Z14testCallStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]])
|
|
// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8
|
|
// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
|
|
// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[AGG_TMP]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]])
|
|
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0
|
|
// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
|
|
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64
|
|
// CHECK: call void @_Z15testParamStrong6Strong(i64 %[[COERCE_VAL_PI]])
|
|
// CHECK: ret void
|
|
|
|
void testCallStrong(Strong *a) {
|
|
testParamStrong(*a);
|
|
}
|
|
|
|
// CHECK: define i64 @_Z16testReturnStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]])
|
|
// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8
|
|
// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8
|
|
// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
|
|
// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[RETVAL]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]])
|
|
// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0
|
|
// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
|
|
// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64
|
|
// CHECK: ret i64 %[[COERCE_VAL_PI]]
|
|
|
|
Strong testReturnStrong(Strong *a) {
|
|
return *a;
|
|
}
|
|
|
|
// CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}})
|
|
// CHECK: call %struct.S* @_ZN1SIU6__weakP11objc_objectED1Ev(
|
|
// CHECK-NEXT: ret void
|
|
|
|
void testParamWeakTemplate(S<__weak id> a) {
|
|
}
|
|
|
|
// CHECK: define void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
|
|
// CHECK-NOT: call
|
|
// CHECK: ret void
|
|
|
|
void testParamContainsNonTrivial(ContainsNonTrivial a) {
|
|
}
|
|
|
|
// CHECK: define void @_Z26testCallContainsNonTrivialP18ContainsNonTrivial(
|
|
// CHECK: call void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
|
|
// CHECK: call %struct.ContainsNonTrivial* @_ZN18ContainsNonTrivialD1Ev(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
|
|
|
|
void testCallContainsNonTrivial(ContainsNonTrivial *a) {
|
|
testParamContainsNonTrivial(*a);
|
|
}
|