forked from OSchip/llvm-project
[ObjC] Disallow vector parameters and return values in Objective-C methods
for iOS < 9 and OS X < 10.11 X86 targets This commit adds a new error that disallows methods that have parameters/return values with a vector type for some older X86 targets. This diagnostic is needed because objc_msgSend doesn't support SIMD vector registers/return values on X86 in iOS < 9 and OS X < 10.11. Note that we don't necessarily know if the vector argument/return value will use a SIMD register, so instead we chose to be conservative and prohibit all vector types. rdar://21662309 Differential Revision: https://reviews.llvm.org/D28670 llvm-svn: 301532
This commit is contained in:
parent
4f46be327c
commit
a8a372d85e
|
@ -616,6 +616,14 @@ public:
|
|||
getAvailability(std::string *Message = nullptr,
|
||||
VersionTuple EnclosingVersion = VersionTuple()) const;
|
||||
|
||||
/// \brief Retrieve the version of the target platform in which this
|
||||
/// declaration was introduced.
|
||||
///
|
||||
/// \returns An empty version tuple if this declaration has no 'introduced'
|
||||
/// availability attributes, or the version tuple that's specified in the
|
||||
/// attribute otherwise.
|
||||
VersionTuple getVersionIntroduced() const;
|
||||
|
||||
/// \brief Determine whether this declaration is marked 'deprecated'.
|
||||
///
|
||||
/// \param Message If non-NULL and the declaration is deprecated,
|
||||
|
|
|
@ -1180,6 +1180,10 @@ def err_objc_kindof_nonobject : Error<
|
|||
def err_objc_kindof_wrong_position : Error<
|
||||
"'__kindof' type specifier must precede the declarator">;
|
||||
|
||||
def err_objc_method_unsupported_param_ret_type : Error<
|
||||
"%0 %select{parameter|return}1 type is unsupported; "
|
||||
"support for vector types for this target is introduced in %2">;
|
||||
|
||||
// C++ declarations
|
||||
def err_static_assert_expression_is_not_constant : Error<
|
||||
"static_assert expression is not an integral constant expression">;
|
||||
|
|
|
@ -415,6 +415,19 @@ const Attr *Decl::getDefiningAttr() const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
StringRef getRealizedPlatform(const AvailabilityAttr *A,
|
||||
const ASTContext &Context) {
|
||||
// Check if this is an App Extension "platform", and if so chop off
|
||||
// the suffix for matching with the actual platform.
|
||||
StringRef RealizedPlatform = A->getPlatform()->getName();
|
||||
if (!Context.getLangOpts().AppExt)
|
||||
return RealizedPlatform;
|
||||
size_t suffix = RealizedPlatform.rfind("_app_extension");
|
||||
if (suffix != StringRef::npos)
|
||||
return RealizedPlatform.slice(0, suffix);
|
||||
return RealizedPlatform;
|
||||
}
|
||||
|
||||
/// \brief Determine the availability of the given declaration based on
|
||||
/// the target platform.
|
||||
///
|
||||
|
@ -434,20 +447,11 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
|
|||
if (EnclosingVersion.empty())
|
||||
return AR_Available;
|
||||
|
||||
// Check if this is an App Extension "platform", and if so chop off
|
||||
// the suffix for matching with the actual platform.
|
||||
StringRef ActualPlatform = A->getPlatform()->getName();
|
||||
StringRef RealizedPlatform = ActualPlatform;
|
||||
if (Context.getLangOpts().AppExt) {
|
||||
size_t suffix = RealizedPlatform.rfind("_app_extension");
|
||||
if (suffix != StringRef::npos)
|
||||
RealizedPlatform = RealizedPlatform.slice(0, suffix);
|
||||
}
|
||||
|
||||
StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
|
||||
|
||||
// Match the platform name.
|
||||
if (RealizedPlatform != TargetPlatform)
|
||||
if (getRealizedPlatform(A, Context) != TargetPlatform)
|
||||
return AR_Available;
|
||||
|
||||
StringRef PrettyPlatformName
|
||||
|
@ -567,6 +571,20 @@ AvailabilityResult Decl::getAvailability(std::string *Message,
|
|||
return Result;
|
||||
}
|
||||
|
||||
VersionTuple Decl::getVersionIntroduced() const {
|
||||
const ASTContext &Context = getASTContext();
|
||||
StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
|
||||
for (const auto *A : attrs()) {
|
||||
if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
|
||||
if (getRealizedPlatform(Availability, Context) != TargetPlatform)
|
||||
continue;
|
||||
if (!Availability->getIntroduced().empty())
|
||||
return Availability->getIntroduced();
|
||||
}
|
||||
}
|
||||
return VersionTuple();
|
||||
}
|
||||
|
||||
bool Decl::canBeWeakImported(bool &IsDefinition) const {
|
||||
IsDefinition = false;
|
||||
|
||||
|
|
|
@ -4313,6 +4313,51 @@ static void mergeInterfaceMethodToImpl(Sema &S,
|
|||
}
|
||||
}
|
||||
|
||||
/// Verify that the method parameters/return value have types that are supported
|
||||
/// by the x86 target.
|
||||
static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
|
||||
const ObjCMethodDecl *Method) {
|
||||
assert(SemaRef.getASTContext().getTargetInfo().getTriple().getArch() ==
|
||||
llvm::Triple::x86 &&
|
||||
"x86-specific check invoked for a different target");
|
||||
SourceLocation Loc;
|
||||
QualType T;
|
||||
for (const ParmVarDecl *P : Method->parameters()) {
|
||||
if (P->getType()->isVectorType()) {
|
||||
Loc = P->getLocStart();
|
||||
T = P->getType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Loc.isInvalid()) {
|
||||
if (Method->getReturnType()->isVectorType()) {
|
||||
Loc = Method->getReturnTypeSourceRange().getBegin();
|
||||
T = Method->getReturnType();
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
// Vector parameters/return values are not supported by objc_msgSend on x86 in
|
||||
// iOS < 9 and macOS < 10.11.
|
||||
const auto &Triple = SemaRef.getASTContext().getTargetInfo().getTriple();
|
||||
VersionTuple AcceptedInVersion;
|
||||
if (Triple.getOS() == llvm::Triple::IOS)
|
||||
AcceptedInVersion = VersionTuple(/*Major=*/9);
|
||||
else if (Triple.isMacOSX())
|
||||
AcceptedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/11);
|
||||
else
|
||||
return;
|
||||
VersionTuple MethodVersion = Method->getVersionIntroduced();
|
||||
if (SemaRef.getASTContext().getTargetInfo().getPlatformMinVersion() >=
|
||||
AcceptedInVersion &&
|
||||
(MethodVersion.empty() || MethodVersion >= AcceptedInVersion))
|
||||
return;
|
||||
SemaRef.Diag(Loc, diag::err_objc_method_unsupported_param_ret_type)
|
||||
<< T << (Method->getReturnType()->isVectorType() ? /*return value*/ 1
|
||||
: /*parameter*/ 0)
|
||||
<< (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9");
|
||||
}
|
||||
|
||||
Decl *Sema::ActOnMethodDeclaration(
|
||||
Scope *S,
|
||||
SourceLocation MethodLoc, SourceLocation EndLoc,
|
||||
|
@ -4534,6 +4579,10 @@ Decl *Sema::ActOnMethodDeclaration(
|
|||
ObjCMethod->SetRelatedResultType();
|
||||
}
|
||||
|
||||
if (MethodDefinition &&
|
||||
Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
|
||||
checkObjCMethodX86VectorTypes(*this, ObjCMethod);
|
||||
|
||||
ActOnDocumentableDecl(ObjCMethod);
|
||||
|
||||
return ObjCMethod;
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.10 -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-macosx10.4 -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -verify -DMAC -triple=i686-apple-darwin14 -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -verify -triple=i686-apple-ios8 -Wno-objc-root-class %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-macosx10.11 -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -verify -DALLOW -DMAC -triple=i686-apple-darwin15 -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -verify -DALLOW -DIOS -triple=i686-apple-ios9 -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-watchos -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=i686-apple-tvos -Wno-objc-root-class %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -DALLOW -DOTHER -triple=x86_64-apple-macosx10.10 -Wno-objc-root-class %s
|
||||
|
||||
// rdar://21662309
|
||||
|
||||
typedef __attribute__((__ext_vector_type__(3))) float float3;
|
||||
|
||||
typedef float __m128 __attribute__((__vector_size__(16)));
|
||||
|
||||
struct Aggregate { __m128 v; };
|
||||
struct AggregateFloat { float v; };
|
||||
|
||||
#define AVAILABLE_MACOS_10_10 __attribute__((availability(macos, introduced = 10.10)))
|
||||
#define AVAILABLE_MACOS_10_11 __attribute__((availability(macos, introduced = 10.11)))
|
||||
|
||||
#define AVAILABLE_IOS_8 __attribute__((availability(ios, introduced = 8.0)))
|
||||
#define AVAILABLE_IOS_9 __attribute__((availability(ios, introduced = 9.0)))
|
||||
|
||||
@interface VectorMethods
|
||||
|
||||
-(void)takeVector:(float3)v; // there should be no diagnostic at declaration
|
||||
-(void)takeM128:(__m128)v;
|
||||
|
||||
@end
|
||||
|
||||
@implementation VectorMethods
|
||||
|
||||
#ifndef ALLOW
|
||||
|
||||
-(void)takeVector:(float3)v {
|
||||
#ifdef MAC
|
||||
// expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in macOS 10.11}}
|
||||
#else
|
||||
// expected-error@-4 {{'float3' (vector of 3 'float' values) parameter type is unsupported; support for vector types for this target is introduced in iOS 9}}
|
||||
#endif
|
||||
}
|
||||
|
||||
-(float3)retVector { // expected-error {{'float3' (vector of 3 'float' values) return type is unsupported}}
|
||||
}
|
||||
|
||||
-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
|
||||
}
|
||||
|
||||
-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
|
||||
}
|
||||
|
||||
-(void)takeVector4:(float3)v AVAILABLE_IOS_8 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
|
||||
}
|
||||
|
||||
-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // expected-error {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
|
||||
}
|
||||
|
||||
- (__m128)retM128 { // expected-error {{'__m128' (vector of 4 'float' values) return type is unsupported}}
|
||||
}
|
||||
|
||||
- (void)takeM128:(__m128)v { // expected-error {{'__m128' (vector of 4 'float' values) parameter type is unsupported}}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
-(void)takeVector:(float3)v {
|
||||
}
|
||||
|
||||
-(float3)retVector {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (__m128)retM128 {
|
||||
__m128 value;
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)takeM128:(__m128)v {
|
||||
}
|
||||
|
||||
-(void)takeVector2:(float3)v AVAILABLE_MACOS_10_10 {
|
||||
#ifdef MAC
|
||||
// expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (__m128)retM128_2 AVAILABLE_MACOS_10_10 {
|
||||
#ifdef MAC
|
||||
// expected-error@-2 {{'__m128' (vector of 4 'float' values) return type is unsupported}}
|
||||
#endif
|
||||
__m128 value;
|
||||
return value;
|
||||
}
|
||||
|
||||
-(void)takeVector3:(float3)v AVAILABLE_MACOS_10_11 { // no error
|
||||
}
|
||||
|
||||
-(void)takeVector4:(float3)v AVAILABLE_IOS_8 {
|
||||
#ifdef IOS
|
||||
// expected-error@-2 {{'float3' (vector of 3 'float' values) parameter type is unsupported}}
|
||||
#endif
|
||||
}
|
||||
|
||||
-(void)takeVector5:(float3)v AVAILABLE_IOS_9 { // no error
|
||||
}
|
||||
|
||||
#ifdef OTHER
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
-(void)doStuff:(int)m { // no error
|
||||
}
|
||||
|
||||
-(struct Aggregate)takesAndRetVectorInAggregate:(struct Aggregate)f { // no error
|
||||
struct Aggregate result;
|
||||
return result;
|
||||
}
|
||||
|
||||
-(struct AggregateFloat)takesAndRetFloatInAggregate:(struct AggregateFloat)f { // no error
|
||||
struct AggregateFloat result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end
|
Loading…
Reference in New Issue