[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:
Alex Lorenz 2017-04-27 10:43:48 +00:00
parent 4f46be327c
commit a8a372d85e
5 changed files with 221 additions and 10 deletions

View File

@ -616,6 +616,14 @@ public:
getAvailability(std::string *Message = nullptr, getAvailability(std::string *Message = nullptr,
VersionTuple EnclosingVersion = VersionTuple()) const; 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'. /// \brief Determine whether this declaration is marked 'deprecated'.
/// ///
/// \param Message If non-NULL and the declaration is deprecated, /// \param Message If non-NULL and the declaration is deprecated,

View File

@ -1180,6 +1180,10 @@ def err_objc_kindof_nonobject : Error<
def err_objc_kindof_wrong_position : Error< def err_objc_kindof_wrong_position : Error<
"'__kindof' type specifier must precede the declarator">; "'__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 // C++ declarations
def err_static_assert_expression_is_not_constant : Error< def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">; "static_assert expression is not an integral constant expression">;

View File

@ -415,6 +415,19 @@ const Attr *Decl::getDefiningAttr() const {
return nullptr; 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 /// \brief Determine the availability of the given declaration based on
/// the target platform. /// the target platform.
/// ///
@ -434,20 +447,11 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
if (EnclosingVersion.empty()) if (EnclosingVersion.empty())
return AR_Available; 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 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(); StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
// Match the platform name. // Match the platform name.
if (RealizedPlatform != TargetPlatform) if (getRealizedPlatform(A, Context) != TargetPlatform)
return AR_Available; return AR_Available;
StringRef PrettyPlatformName StringRef PrettyPlatformName
@ -567,6 +571,20 @@ AvailabilityResult Decl::getAvailability(std::string *Message,
return Result; 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 { bool Decl::canBeWeakImported(bool &IsDefinition) const {
IsDefinition = false; IsDefinition = false;

View File

@ -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( Decl *Sema::ActOnMethodDeclaration(
Scope *S, Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc, SourceLocation MethodLoc, SourceLocation EndLoc,
@ -4534,6 +4579,10 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethod->SetRelatedResultType(); ObjCMethod->SetRelatedResultType();
} }
if (MethodDefinition &&
Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
checkObjCMethodX86VectorTypes(*this, ObjCMethod);
ActOnDocumentableDecl(ObjCMethod); ActOnDocumentableDecl(ObjCMethod);
return ObjCMethod; return ObjCMethod;

View File

@ -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