diff options
author | Cullen Rhodes <cullen.rhodes@arm.com> | 2020-08-11 14:30:02 +0000 |
---|---|---|
committer | Cullen Rhodes <cullen.rhodes@arm.com> | 2020-08-28 15:57:09 +0000 |
commit | 2ddf795e8cac362e142a82ecea805fdf5daa79b8 (patch) | |
tree | b3d5d12fe999702efe5dc5e9e363b0fc8cabee91 /clang/lib/CodeGen/TargetInfo.cpp | |
parent | bfc76366125b846bfdfac5cc19c356542a399e45 (diff) | |
download | llvm-2ddf795e8cac362e142a82ecea805fdf5daa79b8.zip llvm-2ddf795e8cac362e142a82ecea805fdf5daa79b8.tar.gz llvm-2ddf795e8cac362e142a82ecea805fdf5daa79b8.tar.bz2 |
Reland "[CodeGen][AArch64] Support arm_sve_vector_bits attribute"
This relands D85743 with a fix for test
CodeGen/attr-arm-sve-vector-bits-call.c that disables the new pass
manager with '-fno-experimental-new-pass-manager'. Test was failing due
to IR differences with the new pass manager which broke the Fuchsia
builder [1]. Reverted in 2e7041f.
[1] http://lab.llvm.org:8011/builders/fuchsia-x86_64-linux/builds/10375
Original summary:
This patch implements codegen for the 'arm_sve_vector_bits' type
attribute, defined by the Arm C Language Extensions (ACLE) for SVE [1].
The purpose of this attribute is to define vector-length-specific (VLS)
versions of existing vector-length-agnostic (VLA) types.
VLSTs are represented as VectorType in the AST and fixed-length vectors
in the IR everywhere except in function args/return. Implemented in this
patch is codegen support for the following:
* Implicit casting between VLA <-> VLS types.
* Coercion of VLS types in function args/return.
* Mangling of VLS types.
Casting is handled by the CK_BitCast operation, which has been extended
to support the two new vector kinds for fixed-length SVE predicate and
data vectors, where the cast is implemented through memory rather than a
bitcast which is unsupported. Implementing this as a normal bitcast
would require relaxing checks in LLVM to allow bitcasting between
scalable and fixed types. Another option was adding target-specific
intrinsics, although codegen support would need to be added for these
intrinsics. Given this, casting through memory seemed like the best
approach as it's supported today and existing optimisations may remove
unnecessary loads/stores, although there is room for improvement here.
Coercion of VLSTs in function args/return from fixed to scalable is
implemented through the AArch64 ABI in TargetInfo.
The VLA and VLS types are defined by the ACLE to map to the same
machine-level SVE vectors. VLS types are mangled in the same way as:
__SVE_VLS<typename, unsigned>
where the first argument is the underlying variable-length type and the
second argument is the SVE vector length in bits. For example:
#if __ARM_FEATURE_SVE_BITS==512
// Mangled as 9__SVE_VLSIu11__SVInt32_tLj512EE
typedef svint32_t vec __attribute__((arm_sve_vector_bits(512)));
// Mangled as 9__SVE_VLSIu10__SVBool_tLj512EE
typedef svbool_t pred __attribute__((arm_sve_vector_bits(512)));
#endif
The latest ACLE specification (00bet5) does not contain details of this
mangling scheme, it will be specified in the next revision. The
mangling scheme is otherwise defined in the appendices to the Procedure
Call Standard for the Arm Architecture, see [2] for more information.
[1] https://developer.arm.com/documentation/100987/latest
[2] https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#appendix-c-mangling
Reviewed By: efriedma
Differential Revision: https://reviews.llvm.org/D85743
Diffstat (limited to 'clang/lib/CodeGen/TargetInfo.cpp')
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 123 |
1 files changed, 100 insertions, 23 deletions
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index e949455..d6efd54 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5452,6 +5452,7 @@ private: ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; + ABIArgInfo coerceIllegalVector(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; @@ -5585,33 +5586,96 @@ void WindowsAArch64TargetCodeGenInfo::setTargetAttributes( } } +ABIArgInfo AArch64ABIInfo::coerceIllegalVector(QualType Ty) const { + assert(Ty->isVectorType() && "expected vector type!"); + + const auto *VT = Ty->castAs<VectorType>(); + if (VT->getVectorKind() == VectorType::SveFixedLengthPredicateVector) { + assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); + assert(VT->getElementType()->castAs<BuiltinType>()->getKind() == + BuiltinType::UChar && + "unexpected builtin type for SVE predicate!"); + return ABIArgInfo::getDirect(llvm::ScalableVectorType::get( + llvm::Type::getInt1Ty(getVMContext()), 16)); + } + + if (VT->getVectorKind() == VectorType::SveFixedLengthDataVector) { + assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); + + const auto *BT = VT->getElementType()->castAs<BuiltinType>(); + llvm::ScalableVectorType *ResType = nullptr; + switch (BT->getKind()) { + default: + llvm_unreachable("unexpected builtin type for SVE vector!"); + case BuiltinType::SChar: + case BuiltinType::UChar: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getInt8Ty(getVMContext()), 16); + break; + case BuiltinType::Short: + case BuiltinType::UShort: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getInt16Ty(getVMContext()), 8); + break; + case BuiltinType::Int: + case BuiltinType::UInt: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getInt32Ty(getVMContext()), 4); + break; + case BuiltinType::Long: + case BuiltinType::ULong: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getInt64Ty(getVMContext()), 2); + break; + case BuiltinType::Float16: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getHalfTy(getVMContext()), 8); + break; + case BuiltinType::Float: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getFloatTy(getVMContext()), 4); + break; + case BuiltinType::Double: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getDoubleTy(getVMContext()), 2); + break; + case BuiltinType::BFloat16: + ResType = llvm::ScalableVectorType::get( + llvm::Type::getBFloatTy(getVMContext()), 8); + break; + } + return ABIArgInfo::getDirect(ResType); + } + + uint64_t Size = getContext().getTypeSize(Ty); + // Android promotes <2 x i8> to i16, not i32 + if (isAndroid() && (Size <= 16)) { + llvm::Type *ResType = llvm::Type::getInt16Ty(getVMContext()); + return ABIArgInfo::getDirect(ResType); + } + if (Size <= 32) { + llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); + return ABIArgInfo::getDirect(ResType); + } + if (Size == 64) { + auto *ResType = + llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2); + return ABIArgInfo::getDirect(ResType); + } + if (Size == 128) { + auto *ResType = + llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4); + return ABIArgInfo::getDirect(ResType); + } + return getNaturalAlignIndirect(Ty, /*ByVal=*/false); +} + ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. - if (isIllegalVectorType(Ty)) { - uint64_t Size = getContext().getTypeSize(Ty); - // Android promotes <2 x i8> to i16, not i32 - if (isAndroid() && (Size <= 16)) { - llvm::Type *ResType = llvm::Type::getInt16Ty(getVMContext()); - return ABIArgInfo::getDirect(ResType); - } - if (Size <= 32) { - llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); - return ABIArgInfo::getDirect(ResType); - } - if (Size == 64) { - auto *ResType = - llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2); - return ABIArgInfo::getDirect(ResType); - } - if (Size == 128) { - auto *ResType = - llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4); - return ABIArgInfo::getDirect(ResType); - } - return getNaturalAlignIndirect(Ty, /*ByVal=*/false); - } + if (isIllegalVectorType(Ty)) + return coerceIllegalVector(Ty); if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. @@ -5690,6 +5754,12 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); + if (const auto *VT = RetTy->getAs<VectorType>()) { + if (VT->getVectorKind() == VectorType::SveFixedLengthDataVector || + VT->getVectorKind() == VectorType::SveFixedLengthPredicateVector) + return coerceIllegalVector(RetTy); + } + // Large vector types should be returned via memory. if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128) return getNaturalAlignIndirect(RetTy); @@ -5745,6 +5815,13 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, /// isIllegalVectorType - check whether the vector type is legal for AArch64. bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const { if (const VectorType *VT = Ty->getAs<VectorType>()) { + // Check whether VT is a fixed-length SVE vector. These types are + // represented as scalable vectors in function args/return and must be + // coerced from fixed vectors. + if (VT->getVectorKind() == VectorType::SveFixedLengthDataVector || + VT->getVectorKind() == VectorType::SveFixedLengthPredicateVector) + return true; + // Check whether VT is legal. unsigned NumElements = VT->getNumElements(); uint64_t Size = getContext().getTypeSize(VT); |