This patch is a prototype demonstrating an alternative approach to D83553 which
turned out to be an unviable solution.
In that approach vector-length-specific types (VLSTs) defined by the attribute
were by default represented as scalable vectors except in constructs where
scalable vectors aren't supported in IR, such as globals and structs, where they
were represented as fixed-length arrays. When loading from a VLST to a VLAT, or
when storing a VLAT to a VLST, the address was bitcasted, e.g.
bitcast [N x i8]* %addr.ptr to <vscale x 16 x i8>*
The issue with that approach was VLSTs were represented as AttributedType in
the AST and were not part of the canonical type. This was problematic in places
such as CodeGenTypes that look at the canonical type as special handling was
required for types such as ConstantArrayType that needed to be lowered to
fixed-length arrays. See the patch for more information on issues with that
approach.
In this implementation VLSTs are represented as VectorType in the AST and
fixed-length vectors in the IR everywhere except in function args/return.
Predicates are represented with i8 as they were in D83553 to avoid layout
issues in structs. For example, in the following C code:
#if __ARM_FEATURE_SVE_BITS==512 typedef svbool_t fixed_bool_t __attribute__((arm_sve_vector_bits(512))); #endif
fixed_bool_t becomes <8 x i8> in the IR.
In function args/return VLSTs are coerced from fixed to scalable vectors. This
is implemented through the AArch64 ABI in TargetInfo. As BuiltinType::SveBool
and BuiltinType::SveUint8 are both represented as a VectorType of element
type BuiltinType::UChar, to support this in the ABI two new vectors kinds were
required to distinguish between predicates and data vectors.
Casting between VLAT/VLST is handled by the CK_BitCast operation and this has
been extended in CodeGen to support the new vector kinds, 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.
The semantics implemented in D83551 are changed as the AttributedType has been
replaced by VectorType in the AST. When VLSTs were represented as sizeless
types only minimal changes in Sema were necessary to permit them in places such
as structs, but no changes were required for implicit casting as the canonical
types were the same.
The AArch64 ACLE states VLSTs defined by the attribute map to the same AAPCS64
types as the sizeless variants. In the previous approach mangling wasn't
necessary as the canonical types were the same. The mangling scheme is defined
in the appendices to the Procedure Call Standard for the Arm Architecture, see
https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#appendix-c-mangling
For more information on the attribute see:
https://developer.arm.com/documentation/100987/latest