Skip to content

[Clang][AArch64] Change SME attributes for shared/new/preserved state. #76971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -4036,12 +4036,27 @@ class FunctionType : public Type {
SME_NormalFunction = 0,
SME_PStateSMEnabledMask = 1 << 0,
SME_PStateSMCompatibleMask = 1 << 1,
SME_PStateZASharedMask = 1 << 2,
SME_PStateZAPreservedMask = 1 << 3,
SME_AttributeMask = 0b111'111 // We only support maximum 6 bits because of the
// bitmask in FunctionTypeExtraBitfields.

// Describes the value of the state using ArmStateValue.
SME_ZAShift = 2,
SME_ZAMask = 0b111 << SME_ZAShift,

SME_AttributeMask = 0b111'111 // We only support maximum 6 bits because of
// the bitmask in FunctionTypeExtraBitfields.
};

enum ArmStateValue : unsigned {
ARM_None = 0,
ARM_Preserves = 1,
ARM_In = 2,
ARM_Out = 3,
ARM_InOut = 4,
};

static ArmStateValue getArmZAState(unsigned AttrBits) {
return (ArmStateValue)((AttrBits & SME_ZAMask) >> SME_ZAShift);
}

/// A simple holder for various uncommon bits which do not fit in
/// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
/// alignment of subsequent objects in TrailingObjects.
Expand Down
49 changes: 35 additions & 14 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2539,16 +2539,45 @@ def ArmStreamingCompatible : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Documentation = [ArmSmeStreamingCompatibleDocs];
}

def ArmSharedZA : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_shared_za">];
def ArmNew : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_new">];
let Args = [VariadicStringArgument<"NewArgs">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [ArmNewDocs];

let AdditionalMembers = [{
bool isNewZA() const {
return llvm::is_contained(newArgs(), "za");
}
}];
}

def ArmIn : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_in">];
let Args = [VariadicStringArgument<"InArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmInDocs];
}

def ArmOut : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_out">];
let Args = [VariadicStringArgument<"OutArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmOutDocs];
}

def ArmInOut : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_inout">];
let Args = [VariadicStringArgument<"InOutArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmSmeSharedZADocs];
let Documentation = [ArmInOutDocs];
}

def ArmPreservesZA : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_preserves_za">];
def ArmPreserves : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_preserves">];
let Args = [VariadicStringArgument<"PreserveArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmSmePreservesZADocs];
let Documentation = [ArmPreservesDocs];
}

def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
Expand All @@ -2557,14 +2586,6 @@ def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
let Documentation = [ArmSmeLocallyStreamingDocs];
}

def ArmNewZA : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_new_za">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [ArmSmeNewZADocs];
}
def : MutualExclusions<[ArmNewZA, ArmSharedZA]>;
def : MutualExclusions<[ArmNewZA, ArmPreservesZA]>;


def Pure : InheritableAttr {
let Spellings = [GCC<"pure">];
Expand Down
82 changes: 65 additions & 17 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -6861,30 +6861,73 @@ without changing modes.
}];
}

def ArmSmeSharedZADocs : Documentation {
def ArmInDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_shared_za`` keyword applies to prototyped function types and specifies
that the function shares SME's matrix storage (ZA) with its caller. This
means that:
The ``__arm_in`` keyword applies to prototyped function types and specifies
that the function shares a given state S with its caller. For ``__arm_in``, the
function takes the state S as input and returns with the state S unchanged.

* the function requires that the processor implements the Scalable Matrix
Extension (SME).
The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* the function enters with ZA in an active state.
* ``"za"`` for Matrix Storage (requires SME)

* the function returns with ZA in an active state.
The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmSmePreservesZADocs : Documentation {
def ArmOutDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_preserves_za`` keyword applies to prototyped function types and
specifies that the function does not modify ZA state.
The ``__arm_out`` keyword applies to prototyped function types and specifies
that the function shares a given state S with its caller. For ``__arm_out``,
the function ignores the incoming state for S and returns new state for S.

The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmInOutDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_inout`` keyword applies to prototyped function types and specifies
that the function shares a given state S with its caller. For ``__arm_inout``,
the function takes the state S as input and returns new state for S.

The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmPreservesDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_preserves`` keyword applies to prototyped function types and
specifies that the function does not read a given state S and returns
with state S unchanged.

The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmSmeLocallyStreamingDocs : Documentation {
let Category = DocCatArmSmeAttributes;
Expand All @@ -6907,13 +6950,18 @@ at the end of the function.
}];
}

def ArmSmeNewZADocs : Documentation {
def ArmNewDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_new_za`` keyword applies to function declarations and specifies
that the function will be set up with a fresh ZA context.
The ``__arm_new`` keyword applies to function declarations and specifies
that the function will create a new scope for state S.

The attribute takes string arguments to instruct the compiler for which state
to create new scope. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

This means that:
For state ``"za"``, this means that:

* the function requires that the target processor implements the Scalable Matrix
Extension (SME).
Expand All @@ -6924,8 +6972,8 @@ This means that:

* the function will disable PSTATE.ZA (by setting it to 0) before returning.

For ``__arm_new_za`` functions Clang will set up the ZA context automatically
on entry to the function, and disable it before returning. For example, if ZA is
For ``__arm_new("za")`` functions Clang will set up the ZA context automatically
on entry to the function and disable it before returning. For example, if ZA is
in a dormant state Clang will generate the code to commit a lazy-save and set up
a new ZA state before executing user code.
}];
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/AttributeCommonInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,19 @@ class AttributeCommonInfo {
return SpellingIndex != SpellingNotCalculated;
}
};

inline bool doesKeywordAttributeTakeArgs(tok::TokenKind Kind) {
switch (Kind) {
default:
return false;
#define KEYWORD_ATTRIBUTE(NAME, HASARG) \
case tok::kw_##NAME: \
return HASARG;
#include "clang/Basic/RegularKeywordAttrInfo.inc"
#undef KEYWORD_ATTRIBUTE
}
}

} // namespace clang

#endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
SOURCE Attr.td
TARGET ClangAttrSubjectMatchRuleList)

clang_tablegen(AttrTokenKinds.inc -gen-clang-attr-token-kinds
clang_tablegen(RegularKeywordAttrInfo.inc -gen-clang-regular-keyword-attr-info
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
TARGET ClangAttrTokenKinds
TARGET ClangRegularKeywordAttrInfo
)

clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3700,6 +3700,12 @@ def err_sme_definition_using_sm_in_non_sme_target : Error<
"function executed in streaming-SVE mode requires 'sme'">;
def err_sme_definition_using_za_in_non_sme_target : Error<
"function using ZA state requires 'sme'">;
def err_conflicting_attributes_arm_state : Error<
"conflicting attributes for state '%0'">;
def err_unknown_arm_state : Error<
"unknown state '%0'">;
def err_missing_arm_state : Error<
"missing state for %0">;
def err_cconv_change : Error<
"function declared '%0' here was previously declared "
"%select{'%2'|without calling convention}1">;
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,9 @@ KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL)

// Keywords defined by Attr.td.
#ifndef KEYWORD_ATTRIBUTE
#define KEYWORD_ATTRIBUTE(X) KEYWORD(X, KEYALL)
#define KEYWORD_ATTRIBUTE(X, ...) KEYWORD(X, KEYALL)
#endif
#include "clang/Basic/AttrTokenKinds.inc"
#include "clang/Basic/RegularKeywordAttrInfo.inc"

// Clang-specific keywords enabled only in testing.
TESTING_KEYWORD(__unknown_anytype , KEYALL)
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/TokenKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ bool isPragmaAnnotation(TokenKind K);

inline constexpr bool isRegularKeywordAttribute(TokenKind K) {
return (false
#define KEYWORD_ATTRIBUTE(X) || (K == tok::kw_##X)
#include "clang/Basic/AttrTokenKinds.inc"
#define KEYWORD_ATTRIBUTE(X, ...) || (K == tok::kw_##X)
#include "clang/Basic/RegularKeywordAttrInfo.inc"
);
}

Expand Down
10 changes: 1 addition & 9 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -7110,15 +7110,7 @@ class Sema final {
NestedNameSpecInfo &IdInfo,
bool EnteringContext);

/// The kind of conversion to check for. Either all attributes must match exactly,
/// or the converted type may add/drop '__arm_preserves_za'.
enum class AArch64SMECallConversionKind {
MatchExactly,
MayAddPreservesZA,
MayDropPreservesZA,
};
bool IsInvalidSMECallConversion(QualType FromType, QualType ToType,
AArch64SMECallConversionKind C);
bool IsInvalidSMECallConversion(QualType FromType, QualType ToType);

/// The parser has parsed a nested-name-specifier
/// 'template[opt] template-name < template-args >::'.
Expand Down
31 changes: 15 additions & 16 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -937,15 +937,20 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
OS << ')';

FunctionType::ExtInfo Info = T->getExtInfo();
unsigned SMEBits = T->getAArch64SMEAttributes();

if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask))
if (SMEBits & FunctionType::SME_PStateSMCompatibleMask)
OS << " __arm_streaming_compatible";
if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask))
if (SMEBits & FunctionType::SME_PStateSMEnabledMask)
OS << " __arm_streaming";
if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask))
OS << " __arm_shared_za";
if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZAPreservedMask))
OS << " __arm_preserves_za";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Preserves)
OS << " __arm_preserves(\"za\")";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_In)
OS << " __arm_in(\"za\")";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Out)
OS << " __arm_out(\"za\")";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut)
OS << " __arm_inout(\"za\")";

printFunctionAfter(Info, OS);

Expand Down Expand Up @@ -1788,14 +1793,6 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << "__arm_streaming_compatible";
return;
}
if (T->getAttrKind() == attr::ArmSharedZA) {
OS << "__arm_shared_za";
return;
}
if (T->getAttrKind() == attr::ArmPreservesZA) {
OS << "__arm_preserves_za";
return;
}

OS << " __attribute__((";
switch (T->getAttrKind()) {
Expand Down Expand Up @@ -1839,8 +1836,10 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::WebAssemblyFuncref:
case attr::ArmStreaming:
case attr::ArmStreamingCompatible:
case attr::ArmSharedZA:
case attr::ArmPreservesZA:
case attr::ArmIn:
case attr::ArmOut:
case attr::ArmInOut:
case attr::ArmPreserves:
llvm_unreachable("This attribute should have been handled already");

case attr::NSReturnsRetained:
Expand Down
18 changes: 11 additions & 7 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1767,14 +1767,21 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
FPT->isNothrow())
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);

if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask)
unsigned SMEBits = FPT->getAArch64SMEAttributes();
if (SMEBits & FunctionType::SME_PStateSMEnabledMask)
FuncAttrs.addAttribute("aarch64_pstate_sm_enabled");
if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask)
if (SMEBits & FunctionType::SME_PStateSMCompatibleMask)
FuncAttrs.addAttribute("aarch64_pstate_sm_compatible");
if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask)

// ZA
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Out ||
FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut)
FuncAttrs.addAttribute("aarch64_pstate_za_shared");
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Preserves ||
FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_In) {
FuncAttrs.addAttribute("aarch64_pstate_za_shared");
if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZAPreservedMask)
FuncAttrs.addAttribute("aarch64_pstate_za_preserved");
}
}

static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs,
Expand Down Expand Up @@ -2446,9 +2453,6 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,

if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>())
FuncAttrs.addAttribute("aarch64_pstate_sm_body");

if (TargetDecl->hasAttr<ArmNewZAAttr>())
FuncAttrs.addAttribute("aarch64_pstate_za_new");
}

// Attach "no-builtins" attributes to:
Expand Down
Loading