Skip to content

Commit

Permalink
[Sema][AArch64] Add parsing support for arm_sve_vector_bits attribute
Browse files Browse the repository at this point in the history
Summary:

This patch implements parsing support for the 'arm_sve_vector_bits' type
attribute, defined by the Arm C Language Extensions (ACLE, version 00bet5,
section 3.7.3) for SVE [1].

The purpose of this attribute is to define fixed-length (VLST) versions
of existing sizeless types (VLAT). For example:

    #if __ARM_FEATURE_SVE_BITS==512
    typedef svint32_t fixed_svint32_t __attribute__((arm_sve_vector_bits(512)));
    #endif

Creates a type 'fixed_svint32_t' that is a fixed-length version of
'svint32_t' that is normal-sized (rather than sizeless) and contains
exactly 512 bits. Unlike 'svint32_t', this type can be used in places
such as structs and arrays where sizeless types can't.

Implemented in this patch is the following:

  * Defined and tested attribute taking single argument.
  * Checks the argument is an integer constant expression.
  * Attribute can only be attached to a single SVE vector or predicate
    type, excluding tuple types such as svint32x4_t.
  * Added the `-msve-vector-bits=<bits>` flag. When specified the
    `__ARM_FEATURE_SVE_BITS__EXPERIMENTAL` macro is defined.
  * Added a language option to store the vector size specified by the
    `-msve-vector-bits=<bits>` flag. This is used to validate `N ==
    __ARM_FEATURE_SVE_BITS`, where N is the number of bits passed to the
    attribute and `__ARM_FEATURE_SVE_BITS` is the feature macro defined under
    the same flag.

The `__ARM_FEATURE_SVE_BITS` macro will be made non-experimental in the final
patch of the series.

[1] https://developer.arm.com/documentation/100987/latest

This is patch 1/4 of a patch series.

Reviewers: sdesmalen, rsandifo-arm, efriedma, ctetreau, cameron.mcinally, rengolin, aaron.ballman

Reviewed By: sdesmalen, aaron.ballman

Differential Revision: https://reviews.llvm.org/D83550
  • Loading branch information
c-rhodes committed Jul 17, 2020
1 parent 62fd7f7 commit bb160e7
Show file tree
Hide file tree
Showing 17 changed files with 336 additions and 8 deletions.
5 changes: 5 additions & 0 deletions clang/include/clang/AST/Type.h
Expand Up @@ -1925,6 +1925,11 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
bool isSizelessType() const;
bool isSizelessBuiltinType() const;

/// Determines if this is a sizeless type supported by the
/// 'arm_sve_vector_bits' type attribute, which can be applied to a single
/// SVE vector or predicate, excluding tuple types such as svint32x4_t.
bool isVLSTBuiltinType() const;

/// Types are partitioned into 3 broad categories (C99 6.2.5p1):
/// object types, function types, and incomplete types.

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Attr.td
Expand Up @@ -1532,6 +1532,12 @@ def NeonVectorType : TypeAttr {
let ASTNode = 0;
}

def ArmSveVectorBits : TypeAttr {
let Spellings = [GNU<"arm_sve_vector_bits">];
let Args = [IntArgument<"NumBits">];
let Documentation = [ArmSveVectorBitsDocs];
}

def ArmMveStrictPolymorphism : TypeAttr, TargetSpecificAttr<TargetARM> {
let Spellings = [Clang<"__clang_arm_mve_strict_polymorphism">];
let Documentation = [ArmMveStrictPolymorphismDocs];
Expand Down
37 changes: 37 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Expand Up @@ -4855,6 +4855,43 @@ close the handle. It is also assumed to require an open handle to work with.
}];
}

def ArmSveVectorBitsDocs : Documentation {
let Category = DocCatType;
let Content = [{
The ``arm_sve_vector_bits(N)`` attribute is defined by the Arm C Language
Extensions (ACLE) for SVE. It is used to define fixed-length (VLST) variants of
sizeless types (VLAT).

For example:

.. code-block:: c

#include <arm_sve.h>

#if __ARM_FEATURE_SVE_BITS==512
typedef svint32_t fixed_svint32_t __attribute__((arm_sve_vector_bits(512)));
#endif

Creates a type ``fixed_svint32_t`` that is a fixed-length variant of
``svint32_t`` that contains exactly 512-bits. Unlike ``svint32_t``, this type
can be used in globals, structs, unions, and arrays, all of which are
unsupported for sizeless types.

The attribute can be attached to a single SVE vector (such as ``svint32_t``) or
to the SVE predicate type ``svbool_t``, this excludes tuple types such as
``svint32x4_t``. The behavior of the attribute is undefined unless
``N==__ARM_FEATURE_SVE_BITS``, the implementation defined feature macro that is
enabled under the ``-msve-vector-bits`` flag.

NOTE: This feature is currently WIP, the ``-msve-vector-bits=`` flag defines
the ``__ARM_FEATURE_SVE_BITS_EXPERIMENTAL`` macro. This feature is complete
when experimental is dropped.

For more information See `Arm C Language Extensions for SVE
<https://developer.arm.com/documentation/100987/latest>`_ for more information.
}];
}

def ArmMveStrictPolymorphismDocs : Documentation {
let Category = DocCatType;
let Content = [{
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Expand Up @@ -511,4 +511,7 @@ def warn_drv_libstdcxx_not_found : Warning<
def err_drv_cannot_mix_options : Error<"cannot specify '%1' along with '%0'">;

def err_drv_invalid_object_mode : Error<"OBJECT_MODE setting %0 is not recognized and is not a valid setting.">;

def err_drv_invalid_sve_vector_bits : Error<
"'-msve-vector-bits' is not supported without SVE enabled">;
}
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -2810,6 +2810,13 @@ def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">;
def err_attribute_invalid_matrix_type : Error<"invalid matrix element type %0">;
def err_attribute_bad_neon_vector_size : Error<
"Neon vector size must be 64 or 128 bits">;
def err_attribute_invalid_sve_type : Error<
"%0 attribute applied to non-SVE type %1">;
def err_attribute_bad_sve_vector_size : Error<
"invalid SVE vector size '%0', must match value set by "
"'-msve-vector-bits' ('%1')">;
def err_attribute_arm_feature_sve_bits_unsupported : Error<
"%0 is not supported when '-msve-vector-bits=<bits>' is not specified">;
def err_attribute_requires_positive_integer : Error<
"%0 attribute requires a %select{positive|non-negative}1 "
"integral compile time constant expression">;
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Expand Up @@ -382,6 +382,8 @@ LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled")
LANGOPT(RelativeCXXABIVTables, 1, 0,
"Use an ABI-incompatible v-table layout that uses relative references")

LANGOPT(ArmSveVectorBits, 32, 0, "SVE vector size in bits")

#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Driver/Options.td
Expand Up @@ -2343,6 +2343,11 @@ foreach i = {8-15,18} in
def fcall_saved_x#i : Flag<["-"], "fcall-saved-x"#i>, Group<m_aarch64_Features_Group>,
HelpText<"Make the x"#i#" register call-saved (AArch64 only)">;

def msve_vector_bits_EQ : Joined<["-"], "msve-vector-bits=">,
Group<m_aarch64_Features_Group>, Flags<[DriverOption,CC1Option]>,
HelpText<"Set the size of fixed-length SVE vectors in bits.">,
Values<"128,256,512,1024,2048">;

def msign_return_address_EQ : Joined<["-"], "msign-return-address=">,
Flags<[CC1Option]>, Group<m_Group>, Values<"none,all,non-leaf">,
HelpText<"Select return address signing scope">;
Expand Down
24 changes: 24 additions & 0 deletions clang/lib/AST/Type.cpp
Expand Up @@ -2294,6 +2294,30 @@ bool Type::isSizelessBuiltinType() const {

bool Type::isSizelessType() const { return isSizelessBuiltinType(); }

bool Type::isVLSTBuiltinType() const {
if (const BuiltinType *BT = getAs<BuiltinType>()) {
switch (BT->getKind()) {
case BuiltinType::SveInt8:
case BuiltinType::SveInt16:
case BuiltinType::SveInt32:
case BuiltinType::SveInt64:
case BuiltinType::SveUint8:
case BuiltinType::SveUint16:
case BuiltinType::SveUint32:
case BuiltinType::SveUint64:
case BuiltinType::SveFloat16:
case BuiltinType::SveFloat32:
case BuiltinType::SveFloat64:
case BuiltinType::SveBFloat16:
case BuiltinType::SveBool:
return true;
default:
return false;
}
}
return false;
}

bool QualType::isPODType(const ASTContext &Context) const {
// C++11 has a more relaxed definition of POD.
if (Context.getLangOpts().CPlusPlus11)
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Expand Up @@ -1632,6 +1632,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::ArmMveStrictPolymorphism:
OS << "__clang_arm_mve_strict_polymorphism";
break;
case attr::ArmSveVectorBits:
OS << "arm_sve_vector_bits";
break;
}
OS << "))";
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Expand Up @@ -376,6 +376,10 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");

if (Opts.ArmSveVectorBits)
Builder.defineMacro("__ARM_FEATURE_SVE_BITS_EXPERIMENTAL",
Twine(Opts.ArmSveVectorBits));
}

ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/AArch64.cpp
Expand Up @@ -369,6 +369,12 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
if (V8_6Pos != std::end(Features))
V8_6Pos = Features.insert(std::next(V8_6Pos), {"+i8mm", "+bf16"});

bool HasSve = llvm::is_contained(Features, "+sve");
// -msve_vector_bits=<bits> flag is valid only if SVE is enabled.
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ))
if (!HasSve)
D.Diag(diag::err_drv_invalid_sve_vector_bits);

if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access))
if (A->getOption().matches(options::OPT_mno_unaligned_access))
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Expand Up @@ -1715,6 +1715,21 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
}

// Handle -msve_vector_bits=<bits>
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {
StringRef Val = A->getValue();
const Driver &D = getToolChain().getDriver();
if (!Val.equals("128") && !Val.equals("256") && !Val.equals("512") &&
!Val.equals("1024") && !Val.equals("2048")) {
// Handle the unsupported values passed to msve-vector-bits.
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Val;
} else if (A->getOption().matches(options::OPT_msve_vector_bits_EQ)) {
CmdArgs.push_back(
Args.MakeArgString(llvm::Twine("-msve-vector-bits=") + Val));
}
}
}

void Clang::AddMIPSTargetArgs(const ArgList &Args,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Expand Up @@ -2997,6 +2997,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.GNUAsm = !Args.hasArg(OPT_fno_gnu_inline_asm);
Opts.Cmse = Args.hasArg(OPT_mcmse); // Armv8-M Security Extensions

Opts.ArmSveVectorBits =
getLastArgIntValue(Args, options::OPT_msve_vector_bits_EQ, 0, Diags);

// __declspec is enabled by default for the PS4 by the driver, and also
// enabled for Microsoft Extensions or Borland Extensions, here.
//
Expand Down
79 changes: 71 additions & 8 deletions clang/lib/Sema/SemaType.cpp
Expand Up @@ -7686,6 +7686,19 @@ static bool isPermittedNeonBaseType(QualType &Ty,
BTy->getKind() == BuiltinType::BFloat16;
}

bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr,
llvm::APSInt &Result) {
const auto *AttrExpr = Attr.getArgAsExpr(0);
if (AttrExpr->isTypeDependent() || AttrExpr->isValueDependent() ||
!AttrExpr->isIntegerConstantExpr(Result, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
<< Attr << AANT_ArgumentIntegerConstant << AttrExpr->getSourceRange();
Attr.setInvalid();
return false;
}
return true;
}

/// 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
Expand All @@ -7711,16 +7724,10 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
return;
}
// The number of elements must be an ICE.
Expr *numEltsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
llvm::APSInt numEltsInt(32);
if (numEltsExpr->isTypeDependent() || numEltsExpr->isValueDependent() ||
!numEltsExpr->isIntegerConstantExpr(numEltsInt, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
<< Attr << AANT_ArgumentIntegerConstant
<< numEltsExpr->getSourceRange();
Attr.setInvalid();
if (!verifyValidIntegerConstantExpr(S, Attr, numEltsInt))
return;
}

// Only certain element types are supported for Neon vectors.
if (!isPermittedNeonBaseType(CurType, VecKind, S)) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
Expand All @@ -7741,6 +7748,58 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
CurType = S.Context.getVectorType(CurType, numElts, VecKind);
}

/// HandleArmSveVectorBitsTypeAttr - The "arm_sve_vector_bits" attribute is
/// used to create fixed-length versions of sizeless SVE types defined by
/// the ACLE, such as svint32_t and svbool_t.
static void HandleArmSveVectorBitsTypeAttr(QualType &CurType,
const ParsedAttr &Attr, Sema &S) {
// Target must have SVE.
if (!S.Context.getTargetInfo().hasFeature("sve")) {
S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr;
Attr.setInvalid();
return;
}

// Attribute is unsupported if '-msve-vector-bits=<bits>' isn't specified.
if (!S.getLangOpts().ArmSveVectorBits) {
S.Diag(Attr.getLoc(), diag::err_attribute_arm_feature_sve_bits_unsupported)
<< Attr;
Attr.setInvalid();
return;
}

// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< Attr << 1;
Attr.setInvalid();
return;
}

// The vector size must be an integer constant expression.
llvm::APSInt SveVectorSizeInBits(32);
if (!verifyValidIntegerConstantExpr(S, Attr, SveVectorSizeInBits))
return;

unsigned VecSize = static_cast<unsigned>(SveVectorSizeInBits.getZExtValue());

// The attribute vector size must match -msve-vector-bits.
if (VecSize != S.getLangOpts().ArmSveVectorBits) {
S.Diag(Attr.getLoc(), diag::err_attribute_bad_sve_vector_size)
<< VecSize << S.getLangOpts().ArmSveVectorBits;
Attr.setInvalid();
return;
}

// Attribute can only be attached to a single SVE vector or predicate type.
if (!CurType->isVLSTBuiltinType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_sve_type)
<< Attr << CurType;
Attr.setInvalid();
return;
}
}

static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State,
QualType &CurType,
ParsedAttr &Attr) {
Expand Down Expand Up @@ -8004,6 +8063,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
VectorType::NeonPolyVector);
attr.setUsedAsTypeAttr();
break;
case ParsedAttr::AT_ArmSveVectorBits:
HandleArmSveVectorBitsTypeAttr(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
case ParsedAttr::AT_ArmMveStrictPolymorphism: {
HandleArmMveStrictPolymorphismAttr(state, type, attr);
attr.setUsedAsTypeAttr();
Expand Down
63 changes: 63 additions & 0 deletions clang/test/Driver/aarch64-sve-vector-bits.c
@@ -0,0 +1,63 @@
// -----------------------------------------------------------------------------
// Tests for the -msve-vector-bits flag
// -----------------------------------------------------------------------------

// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=128 2>&1 | FileCheck --check-prefix=CHECK-128 %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=256 2>&1 | FileCheck --check-prefix=CHECK-256 %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=512 2>&1 | FileCheck --check-prefix=CHECK-512 %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=1024 2>&1 | FileCheck --check-prefix=CHECK-1024 %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=2048 2>&1 | FileCheck --check-prefix=CHECK-2048 %s

// CHECK-128: "-msve-vector-bits=128"
// CHECK-256: "-msve-vector-bits=256"
// CHECK-512: "-msve-vector-bits=512"
// CHECK-1024: "-msve-vector-bits=1024"
// CHECK-2048: "-msve-vector-bits=2048"

// Bail out if -msve-vector-bits is specified without SVE enabled
// -----------------------------------------------------------------------------
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -msve-vector-bits=128 \
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-SVE-ERROR %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -msve-vector-bits=256 \
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-SVE-ERROR %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -msve-vector-bits=512 \
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-SVE-ERROR %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -msve-vector-bits=1024 \
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-SVE-ERROR %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -msve-vector-bits=2048 \
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-SVE-ERROR %s

// CHECK-NO-SVE-ERROR: error: '-msve-vector-bits' is not supported without SVE enabled

// Error out if an unsupported value is passed to -msve-vector-bits.
// -----------------------------------------------------------------------------
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=64 2>&1 | FileCheck --check-prefix=CHECK-BAD-VALUE-ERROR %s
// RUN: %clang -c %s -### -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=A 2>&1 | FileCheck --check-prefix=CHECK-BAD-VALUE-ERROR %s

// CHECK-BAD-VALUE-ERROR: error: unsupported argument '{{.*}}' to option 'msve-vector-bits='

// Error if using attribute without -msve-vector-bits
// -----------------------------------------------------------------------------
// RUN: not %clang -c %s -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-FLAG-ERROR %s

typedef __SVInt32_t svint32_t;
typedef svint32_t noflag __attribute__((arm_sve_vector_bits(256)));

// CHECK-NO-FLAG-ERROR: error: 'arm_sve_vector_bits' is not supported when '-msve-vector-bits=<bits>' is not specified

// Error if attribute vector size != -msve-vector-bits
// -----------------------------------------------------------------------------
// RUN: not %clang -c %s -target aarch64-none-linux-gnu -march=armv8-a+sve \
// RUN: -msve-vector-bits=128 2>&1 | FileCheck --check-prefix=CHECK-BAD-VECTOR-SIZE-ERROR %s

typedef svint32_t bad_vector_size __attribute__((arm_sve_vector_bits(256)));

// CHECK-BAD-VECTOR-SIZE-ERROR: error: invalid SVE vector size '256', must match value set by '-msve-vector-bits' ('128')

0 comments on commit bb160e7

Please sign in to comment.