Skip to content

Commit 28b5f30

Browse files
committed
[Clang][AArch64] Add/implement ACLE keywords for SME.
This patch adds all the language-level function keywords defined in: ARM-software/acle#188 (merged) ARM-software/acle#261 (update after D148700 landed) The keywords are used to control PSTATE.ZA and PSTATE.SM, which are respectively used for enabling the use of the ZA matrix array and Streaming mode. This information needs to be available on call sites, since the use of ZA or streaming mode may have to be enabled or disabled around the call-site (depending on the IR attributes set on the caller and the callee). For calls to functions from a function pointer, there is no IR declaration available, so the IR attributes must be added explicitly to the call-site. With the exception of '__arm_locally_streaming' and '__arm_new_za' the information is part of the function's interface, not just the function definition, and thus needs to be propagated through the FunctionProtoType::ExtProtoInfo. This patch adds the defintions of these keywords, as well as codegen and semantic analysis to ensure conversions between function pointers are valid and that no conflicting keywords are set. For example, '__arm_streaming' and '__arm_streaming_compatible' are mutually exclusive. Differential Revision: https://reviews.llvm.org/D127762
1 parent 24c91d4 commit 28b5f30

20 files changed

+1212
-34
lines changed

clang/include/clang/AST/Type.h

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3968,14 +3968,33 @@ class FunctionType : public Type {
39683968
/// because TrailingObjects cannot handle repeated types.
39693969
struct ExceptionType { QualType Type; };
39703970

3971+
/// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number
3972+
/// of function type attributes that can be set on function types, including
3973+
/// function pointers.
3974+
enum AArch64SMETypeAttributes : unsigned {
3975+
SME_NormalFunction = 0,
3976+
SME_PStateSMEnabledMask = 1 << 0,
3977+
SME_PStateSMCompatibleMask = 1 << 1,
3978+
SME_PStateZASharedMask = 1 << 2,
3979+
SME_PStateZAPreservedMask = 1 << 3,
3980+
SME_AttributeMask = 0b111'111 // We only support maximum 6 bits because of the
3981+
// bitmask in FunctionTypeExtraBitfields.
3982+
};
3983+
39713984
/// A simple holder for various uncommon bits which do not fit in
39723985
/// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
39733986
/// alignment of subsequent objects in TrailingObjects.
39743987
struct alignas(void *) FunctionTypeExtraBitfields {
39753988
/// The number of types in the exception specification.
39763989
/// A whole unsigned is not needed here and according to
39773990
/// [implimits] 8 bits would be enough here.
3978-
uint16_t NumExceptionType = 0;
3991+
unsigned NumExceptionType : 10;
3992+
3993+
/// Any AArch64 SME ACLE type attributes that need to be propagated
3994+
/// on declarations and function pointers.
3995+
unsigned AArch64SMEAttributes : 6;
3996+
FunctionTypeExtraBitfields()
3997+
: NumExceptionType(0), AArch64SMEAttributes(SME_NormalFunction) {}
39793998
};
39803999

39814000
protected:
@@ -4154,18 +4173,22 @@ class FunctionProtoType final
41544173
/// the various bits of extra information about a function prototype.
41554174
struct ExtProtoInfo {
41564175
FunctionType::ExtInfo ExtInfo;
4157-
bool Variadic : 1;
4158-
bool HasTrailingReturn : 1;
4176+
unsigned Variadic : 1;
4177+
unsigned HasTrailingReturn : 1;
4178+
unsigned AArch64SMEAttributes : 6;
41594179
Qualifiers TypeQuals;
41604180
RefQualifierKind RefQualifier = RQ_None;
41614181
ExceptionSpecInfo ExceptionSpec;
41624182
const ExtParameterInfo *ExtParameterInfos = nullptr;
41634183
SourceLocation EllipsisLoc;
41644184

4165-
ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {}
4185+
ExtProtoInfo()
4186+
: Variadic(false), HasTrailingReturn(false),
4187+
AArch64SMEAttributes(SME_NormalFunction) {}
41664188

41674189
ExtProtoInfo(CallingConv CC)
4168-
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {}
4190+
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false),
4191+
AArch64SMEAttributes(SME_NormalFunction) {}
41694192

41704193
ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) {
41714194
ExtProtoInfo Result(*this);
@@ -4174,7 +4197,15 @@ class FunctionProtoType final
41744197
}
41754198

41764199
bool requiresFunctionProtoTypeExtraBitfields() const {
4177-
return ExceptionSpec.Type == EST_Dynamic;
4200+
return ExceptionSpec.Type == EST_Dynamic ||
4201+
AArch64SMEAttributes != SME_NormalFunction;
4202+
}
4203+
4204+
void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) {
4205+
if (Enable)
4206+
AArch64SMEAttributes |= Kind;
4207+
else
4208+
AArch64SMEAttributes &= ~Kind;
41784209
}
41794210
};
41804211

@@ -4301,6 +4332,7 @@ class FunctionProtoType final
43014332
EPI.TypeQuals = getMethodQuals();
43024333
EPI.RefQualifier = getRefQualifier();
43034334
EPI.ExtParameterInfos = getExtParameterInfosOrNull();
4335+
EPI.AArch64SMEAttributes = getAArch64SMEAttributes();
43044336
return EPI;
43054337
}
43064338

@@ -4482,6 +4514,15 @@ class FunctionProtoType final
44824514
return getTrailingObjects<ExtParameterInfo>();
44834515
}
44844516

4517+
/// Return a bitmask describing the SME attributes on the function type, see
4518+
/// AArch64SMETypeAttributes for their values.
4519+
unsigned getAArch64SMEAttributes() const {
4520+
if (!hasExtraBitfields())
4521+
return SME_NormalFunction;
4522+
return getTrailingObjects<FunctionTypeExtraBitfields>()
4523+
->AArch64SMEAttributes;
4524+
}
4525+
44854526
ExtParameterInfo getExtParameterInfo(unsigned I) const {
44864527
assert(I < getNumParams() && "parameter index out of range");
44874528
if (hasExtParameterInfos())

clang/include/clang/AST/TypeProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ let Class = FunctionProtoType in {
323323
? node->getExtParameterInfos()
324324
: llvm::ArrayRef<FunctionProtoType::ExtParameterInfo>() }];
325325
}
326+
def : Property<"AArch64SMEAttributes", UInt32> {
327+
let Read = [{ node->getAArch64SMEAttributes() }];
328+
}
326329

327330
def : Creator<[{
328331
auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm,
@@ -338,6 +341,7 @@ let Class = FunctionProtoType in {
338341
epi.ExceptionSpec = exceptionSpecifier;
339342
epi.ExtParameterInfos =
340343
extParameterInfo.empty() ? nullptr : extParameterInfo.data();
344+
epi.AArch64SMEAttributes = AArch64SMEAttributes;
341345
return ctx.getFunctionType(returnType, parameters, epi);
342346
}]>;
343347
}

clang/include/clang/Basic/Attr.td

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,6 +2439,39 @@ def ArmStreaming : TypeAttr, TargetSpecificAttr<TargetAArch64> {
24392439
let Documentation = [ArmSmeStreamingDocs];
24402440
}
24412441

2442+
def ArmStreamingCompatible : TypeAttr, TargetSpecificAttr<TargetAArch64> {
2443+
let Spellings = [RegularKeyword<"__arm_streaming_compatible">];
2444+
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
2445+
let Documentation = [ArmSmeStreamingCompatibleDocs];
2446+
}
2447+
2448+
def ArmSharedZA : TypeAttr, TargetSpecificAttr<TargetAArch64> {
2449+
let Spellings = [RegularKeyword<"__arm_shared_za">];
2450+
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
2451+
let Documentation = [ArmSmeSharedZADocs];
2452+
}
2453+
2454+
def ArmPreservesZA : TypeAttr, TargetSpecificAttr<TargetAArch64> {
2455+
let Spellings = [RegularKeyword<"__arm_preserves_za">];
2456+
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
2457+
let Documentation = [ArmSmePreservesZADocs];
2458+
}
2459+
2460+
def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
2461+
let Spellings = [RegularKeyword<"__arm_locally_streaming">];
2462+
let Subjects = SubjectList<[Function], ErrorDiag>;
2463+
let Documentation = [ArmSmeLocallyStreamingDocs];
2464+
}
2465+
2466+
def ArmNewZA : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
2467+
let Spellings = [RegularKeyword<"__arm_new_za">];
2468+
let Subjects = SubjectList<[Function], ErrorDiag>;
2469+
let Documentation = [ArmSmeNewZADocs];
2470+
}
2471+
def : MutualExclusions<[ArmNewZA, ArmSharedZA]>;
2472+
def : MutualExclusions<[ArmNewZA, ArmPreservesZA]>;
2473+
2474+
24422475
def Pure : InheritableAttr {
24432476
let Spellings = [GCC<"pure">];
24442477
let Documentation = [Undocumented];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 126 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6581,40 +6581,147 @@ Requirements on Development Tools - Engineering Specification Documentation
65816581
}];
65826582
}
65836583

6584-
def ArmSmeStreamingDocs : Documentation {
6585-
let Category = DocCatType;
6584+
def DocCatArmSmeAttributes : DocumentationCategory<"AArch64 SME Attributes"> {
65866585
let Content = [{
6587-
.. Note:: This attribute has not been implemented yet, but once it is
6588-
implemented, it will behave as described below.
6586+
Clang supports a number of AArch64-specific attributes to manage state
6587+
added by the Scalable Matrix Extension (SME). This state includes the
6588+
runtime mode that the processor is in (e.g. non-streaming or streaming)
6589+
as well as the state of the ``ZA`` Matrix Storage.
65896590

6590-
The ``__arm_streaming`` keyword is only available on AArch64 targets.
6591-
It applies to function types and specifies that the function has a
6592-
"streaming interface". This means that:
6591+
The attributes come in the form of type- and declaration attributes:
65936592

6594-
* the function requires the Scalable Matrix Extension (SME)
6593+
* The SME declaration attributes can appear anywhere that a standard
6594+
``[[...]]`` declaration attribute can appear.
65956595

6596-
* the function must be entered in streaming mode (that is, with PSTATE.SM
6597-
set to 1)
6596+
* The SME type attributes apply only to prototyped functions and can appear
6597+
anywhere that a standard ``[[...]]`` type attribute can appear. The SME
6598+
type attributes do not apply to functions having a K&R-style
6599+
unprototyped function type.
65986600

6599-
* the function must return in streaming mode
6600-
6601-
* the function does not have a K&R-style unprototyped function type.
6601+
See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
6602+
for more details about the features related to the SME extension.
66026603

66036604
See `Procedure Call Standard for the Arm® 64-bit Architecture (AArch64)
66046605
<https://github.com/ARM-software/abi-aa>`_ for more details about
6605-
streaming-interface functions.
6606+
streaming-interface functions and shared/private-ZA interface functions.
6607+
}];
6608+
}
6609+
6610+
def ArmSmeStreamingDocs : Documentation {
6611+
let Category = DocCatArmSmeAttributes;
6612+
let Content = [{
6613+
The ``__arm_streaming`` keyword applies to prototyped function types and specifies
6614+
that the function has a "streaming interface". This means that:
6615+
6616+
* the function requires that the processor implements the Scalable Matrix
6617+
Extension (SME).
6618+
6619+
* the function must be entered in streaming mode (that is, with PSTATE.SM
6620+
set to 1)
6621+
6622+
* the function must return in streaming mode
66066623

66076624
Clang manages PSTATE.SM automatically; it is not the source code's
6608-
responsibility to do this. For example, if a normal non-streaming
6625+
responsibility to do this. For example, if a non-streaming
66096626
function calls an ``__arm_streaming`` function, Clang generates code
66106627
that switches into streaming mode before calling the function and
66116628
switches back to non-streaming mode on return.
6629+
}];
6630+
}
6631+
6632+
def ArmSmeStreamingCompatibleDocs : Documentation {
6633+
let Category = DocCatArmSmeAttributes;
6634+
let Content = [{
6635+
The ``__arm_streaming_compatible`` keyword applies to prototyped function types and
6636+
specifies that the function has a “streaming compatible interface”. This
6637+
means that:
66126638

6613-
``__arm_streaming`` can appear anywhere that a standard ``[[...]]`` type
6614-
attribute can appear.
6639+
* the function may be entered in either non-streaming mode (PSTATE.SM=0) or
6640+
in streaming mode (PSTATE.SM=1).
66156641

6616-
See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
6617-
for more details about this extension, and for other related SME features.
6642+
* the function must return in the same mode as it was entered.
6643+
6644+
* the code executed in the function is compatible with either mode.
6645+
6646+
Clang manages PSTATE.SM automatically; it is not the source code's
6647+
responsibility to do this. Clang will ensure that the generated code in
6648+
streaming-compatible functions is valid in either mode (PSTATE.SM=0 or
6649+
PSTATE.SM=1). For example, if an ``__arm_streaming_compatible`` function calls a
6650+
non-streaming function, Clang generates code to temporarily switch out of streaming
6651+
mode before calling the function and switch back to streaming-mode on return if
6652+
``PSTATE.SM`` is ``1`` on entry of the caller. If ``PSTATE.SM`` is ``0`` on
6653+
entry to the ``__arm_streaming_compatible`` function, the call will be executed
6654+
without changing modes.
6655+
}];
6656+
}
6657+
6658+
def ArmSmeSharedZADocs : Documentation {
6659+
let Category = DocCatArmSmeAttributes;
6660+
let Content = [{
6661+
The ``__arm_shared_za`` keyword applies to prototyped function types and specifies
6662+
that the function shares SME's matrix storage (ZA) with its caller. This
6663+
means that:
6664+
6665+
* the function requires that the processor implements the Scalable Matrix
6666+
Extension (SME).
6667+
6668+
* the function enters with ZA in an active state.
6669+
6670+
* the function returns with ZA in an active state.
6671+
}];
6672+
}
6673+
6674+
def ArmSmePreservesZADocs : Documentation {
6675+
let Category = DocCatArmSmeAttributes;
6676+
let Content = [{
6677+
The ``__arm_preserves_za`` keyword applies to prototyped function types and
6678+
specifies that the function does not modify ZA state.
6679+
}];
6680+
}
6681+
6682+
6683+
def ArmSmeLocallyStreamingDocs : Documentation {
6684+
let Category = DocCatArmSmeAttributes;
6685+
let Content = [{
6686+
The ``__arm_locally_streaming`` keyword applies to function declarations
6687+
and specifies that all the statements in the function are executed in
6688+
streaming mode. This means that:
6689+
6690+
* the function requires that the target processor implements the Scalable Matrix
6691+
Extension (SME).
6692+
6693+
* the program automatically puts the machine into streaming mode before
6694+
executing the statements and automatically restores the previous mode
6695+
afterwards.
6696+
6697+
Clang manages PSTATE.SM automatically; it is not the source code's
6698+
responsibility to do this. For example, Clang will emit code to enable
6699+
streaming mode at the start of the function, and disable streaming mode
6700+
at the end of the function.
6701+
}];
6702+
}
6703+
6704+
def ArmSmeNewZADocs : Documentation {
6705+
let Category = DocCatArmSmeAttributes;
6706+
let Content = [{
6707+
The ``__arm_new_za`` keyword applies to function declarations and specifies
6708+
that the function will be set up with a fresh ZA context.
6709+
6710+
This means that:
6711+
6712+
* the function requires that the target processor implements the Scalable Matrix
6713+
Extension (SME).
6714+
6715+
* the function will commit any lazily saved ZA data.
6716+
6717+
* the function will create a new ZA context and enable PSTATE.ZA.
6718+
6719+
* the function will disable PSTATE.ZA (by setting it to 0) before returning.
6720+
6721+
For ``__arm_new_za`` functions Clang will set up the ZA context automatically
6722+
on entry to the function, and disable it before returning. For example, if ZA is
6723+
in a dormant state Clang will generate the code to commit a lazy-save and set up
6724+
a new ZA state before executing user code.
66186725
}];
66196726
}
66206727

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2035,6 +2035,10 @@ def err_different_return_type_for_overriding_virtual_function : Error<
20352035
"than the function it overrides}1,2">;
20362036
def note_overridden_virtual_function : Note<
20372037
"overridden virtual function is here">;
2038+
def err_conflicting_overriding_attributes : Error<
2039+
"virtual function %0 has different attributes "
2040+
"%diff{($) than the function it overrides (which has $)|"
2041+
"than the function it overrides}1,2">;
20382042
def err_conflicting_overriding_cc_attributes : Error<
20392043
"virtual function %0 has different calling convention attributes "
20402044
"%diff{($) than the function it overrides (which has calling convention $)|"
@@ -3621,6 +3625,8 @@ def err_attribute_vecreturn_only_vector_member : Error<
36213625
"the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">;
36223626
def err_attribute_vecreturn_only_pod_record : Error<
36233627
"the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">;
3628+
def err_sme_attr_mismatch : Error<
3629+
"function declared %0 was previously declared %1, which has different SME function attributes">;
36243630
def err_cconv_change : Error<
36253631
"function declared '%0' here was previously declared "
36263632
"%select{'%2'|without calling convention}1">;

clang/include/clang/Sema/Sema.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7086,6 +7086,16 @@ class Sema final {
70867086
NestedNameSpecInfo &IdInfo,
70877087
bool EnteringContext);
70887088

7089+
/// The kind of conversion to check for. Either all attributes must match exactly,
7090+
/// or the converted type may add/drop '__arm_preserves_za'.
7091+
enum class AArch64SMECallConversionKind {
7092+
MatchExactly,
7093+
MayAddPreservesZA,
7094+
MayDropPreservesZA,
7095+
};
7096+
bool IsInvalidSMECallConversion(QualType FromType, QualType ToType,
7097+
AArch64SMECallConversionKind C);
7098+
70897099
/// The parser has parsed a nested-name-specifier
70907100
/// 'template[opt] template-name < template-args >::'.
70917101
///

0 commit comments

Comments
 (0)