diff options
| author | Tim Northover <tnorthover@apple.com> | 2013-08-01 09:23:19 +0000 |
|---|---|---|
| committer | Tim Northover <tnorthover@apple.com> | 2013-08-01 09:23:19 +0000 |
| commit | 2fe823a6c39b332b1a38ab22ab1f88b5dc580090 (patch) | |
| tree | ba976de785979cb7cf12a02b26fcecd966cd8856 /clang/lib/Sema | |
| parent | 40e9efd725d12b4d9d8d6480b64ae8442db5f28e (diff) | |
| download | bcm5719-llvm-2fe823a6c39b332b1a38ab22ab1f88b5dc580090.tar.gz bcm5719-llvm-2fe823a6c39b332b1a38ab22ab1f88b5dc580090.zip | |
AArch64: initial NEON support
Patch by Ana Pazos
- Completed implementation of instruction formats:
AdvSIMD three same
AdvSIMD modified immediate
AdvSIMD scalar pairwise
- Completed implementation of instruction classes
(some of the instructions in these classes
belong to yet unfinished instruction formats):
Vector Arithmetic
Vector Immediate
Vector Pairwise Arithmetic
- Initial implementation of instruction formats:
AdvSIMD scalar two-reg misc
AdvSIMD scalar three same
- Intial implementation of instruction class:
Scalar Arithmetic
- Initial clang changes to support arm v8 intrinsics.
Note: no clang changes for scalar intrinsics function name mangling yet.
- Comprehensive test cases for added instructions
To verify auto codegen, encoding, decoding, diagnosis, intrinsics.
llvm-svn: 187568
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 87 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 47 |
2 files changed, 131 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e417949013f..9f2dc345752 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -306,6 +306,10 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::aarch64: + if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -342,6 +346,9 @@ static unsigned RFT(unsigned t, bool shift = false) { case NeonTypeFlags::Float32: assert(!shift && "cannot shift float types!"); return (2 << IsQuad) - 1; + case NeonTypeFlags::Float64: + assert(!shift && "cannot shift float types!"); + return (1 << IsQuad) - 1; } llvm_unreachable("Invalid NeonTypeFlag!"); } @@ -367,10 +374,90 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) { return Context.UnsignedShortTy; case NeonTypeFlags::Float32: return Context.FloatTy; + case NeonTypeFlags::Float64: + return Context.DoubleTy; } llvm_unreachable("Invalid NeonTypeFlag!"); } +bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + + llvm::APSInt Result; + + uint64_t mask = 0; + unsigned TV = 0; + int PtrArgNum = -1; + bool HasConstPtr = false; + switch (BuiltinID) { +#define GET_NEON_AARCH64_OVERLOAD_CHECK +#include "clang/Basic/arm_neon.inc" +#undef GET_NEON_AARCH64_OVERLOAD_CHECK + } + + // For NEON intrinsics which are overloaded on vector element type, validate + // the immediate which specifies which variant to emit. + unsigned ImmArg = TheCall->getNumArgs() - 1; + if (mask) { + if (SemaBuiltinConstantArg(TheCall, ImmArg, Result)) + return true; + + TV = Result.getLimitedValue(64); + if ((TV > 63) || (mask & (1ULL << TV)) == 0) + return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code) + << TheCall->getArg(ImmArg)->getSourceRange(); + } + + if (PtrArgNum >= 0) { + // Check that pointer arguments have the specified type. + Expr *Arg = TheCall->getArg(PtrArgNum); + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) + Arg = ICE->getSubExpr(); + ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg); + QualType RHSTy = RHS.get()->getType(); + QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context); + if (HasConstPtr) + EltTy = EltTy.withConst(); + QualType LHSTy = Context.getPointerType(EltTy); + AssignConvertType ConvTy; + ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); + if (RHS.isInvalid()) + return true; + if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy, + RHS.get(), AA_Assigning)) + return true; + } + + // For NEON intrinsics which take an immediate value as part of the + // instruction, range check them here. + unsigned i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: + return false; +#define GET_NEON_AARCH64_IMMEDIATE_CHECK +#include "clang/Basic/arm_neon.inc" +#undef GET_NEON_AARCH64_IMMEDIATE_CHECK + } + ; + + // We can't check the value of a dependent argument. + if (TheCall->getArg(i)->isTypeDependent() || + TheCall->getArg(i)->isValueDependent()) + return false; + + // Check that the immediate argument is actually a constant. + if (SemaBuiltinConstantArg(TheCall, i, Result)) + return true; + + // Range check against the upper/lower values for this isntruction. + unsigned Val = Result.getZExtValue(); + if (Val < l || Val > (u + l)) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << l << u + l << TheCall->getArg(i)->getSourceRange(); + + return false; +} + bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall) { assert((BuiltinID == ARM::BI__builtin_arm_ldrex || BuiltinID == ARM::BI__builtin_arm_strex) && diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 0106a679b94..bc6b6a52fa3 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4603,6 +4603,42 @@ static void HandleExtVectorTypeAttr(QualType &CurType, CurType = T; } +static bool isPermittedNeonBaseType(QualType &Ty, + VectorType::VectorKind VecKind, + bool IsAArch64) { + const BuiltinType *BTy = Ty->getAs<BuiltinType>(); + if (!BTy) + return false; + + if (VecKind == VectorType::NeonPolyVector) { + if (IsAArch64) { + // AArch64 polynomial vectors are unsigned + return BTy->getKind() == BuiltinType::UChar || + BTy->getKind() == BuiltinType::UShort; + } else { + // AArch32 polynomial vector are signed. + return BTy->getKind() == BuiltinType::SChar || + BTy->getKind() == BuiltinType::Short; + } + } + + // Non-polynomial vector types: the usual suspects are allowed, as well as + // float64_t on AArch64. + if (IsAArch64 && BTy->getKind() == BuiltinType::Double) + return true; + + return BTy->getKind() == BuiltinType::SChar || + BTy->getKind() == BuiltinType::UChar || + BTy->getKind() == BuiltinType::Short || + BTy->getKind() == BuiltinType::UShort || + BTy->getKind() == BuiltinType::Int || + BTy->getKind() == BuiltinType::UInt || + BTy->getKind() == BuiltinType::LongLong || + BTy->getKind() == BuiltinType::ULongLong || + BTy->getKind() == BuiltinType::Float || + BTy->getKind() == BuiltinType::Half; +} + /// HandleNeonVectorTypeAttr - The "neon_vector_type" and /// "neon_polyvector_type" attributes are used to create vector types that /// are mangled according to ARM's ABI. Otherwise, these types are identical @@ -4646,9 +4682,14 @@ static void HandleNeonVectorTypeAttr(QualType& CurType, BTy->getKind() != BuiltinType::LongLong && BTy->getKind() != BuiltinType::ULongLong && BTy->getKind() != BuiltinType::Float)) { - S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) <<CurType; - Attr.setInvalid(); - return; + llvm::Triple::ArchType Arch = + S.Context.getTargetInfo().getTriple().getArch(); + if (!isPermittedNeonBaseType(CurType, VecKind, + Arch == llvm::Triple::aarch64)) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; + Attr.setInvalid(); + return; + } } // The total size of the vector must be 64 or 128 bits. unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); |

