[PATCH] D127762: [Clang][AArch64] Add ACLE attributes for SME.

Sander de Smalen via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 23 04:33:57 PDT 2022


sdesmalen added inline comments.


================
Comment at: clang/include/clang/Basic/Attr.td:2322
 
+def ArmStreamingCompatible : DeclOrTypeAttr, TargetSpecificAttr<TargetAArch64> {
+  let Spellings = [Clang<"arm_streaming_compatible">];
----------------
aaron.ballman wrote:
> sdesmalen wrote:
> > aaron.ballman wrote:
> > > `DeclOrTypeAttr` is only intended to be used for attributes which were historically a declaration attribute but are semantically type attributes (like calling conventions). It seems to me that each of these is purely a type attribute and we shouldn't allow them to be written in the declaration position. WDYT?
> > In this case, I believe the attribute is valid on both the type and the declaration, because the SME ACLE explicitly specifies that the attributes can be applied to both declarations and types.
> > 
> > The [[https://github.com/ARM-software/acle/pull/188/commits/ce878cf6c43fd824ffc634526e5dfec1ddc1839e#diff-516526d4a18101dc85300bc2033d0f86dc46c505b7510a7694baabea851aedfaR8283-R8294|specification]] says:
> > ```Some of the attributes described in this section apply to function types.
> > Their semantics are as follows:
> > 
> > *   If the attribute is attached to a function declaration or definition,
> >     it applies to the type of the function.
> > 
> > *   If the attribute is attached to a function type, it applies to that type.
> > 
> > *   If the attribute is attached to a pointer to a function type, it applies
> >     to that function type.
> > 
> > *   Otherwise, the attribute is [ill-formed](#ill-formed).```
> > In this case, I believe the attribute is valid on both the type and the declaration, because the SME ACLE explicitly specifies that the attributes can be applied to both declarations and types.
> 
> What are the chances that can change? Because there are problems here:
> 
> > If the attribute is attached to a function declaration or definition, it applies to the type of the function.
> 
> This is egregiously opposed to the design of `[[]]` attributes in both C and C++. We came up with `DeclOrTypeAttr` for attributes that previously existed, but that is different than introducing new attributes. It's par for the course for `__attribute__` style attributes, so I don't worry so much there.
> 
> What's the rationale for this confusing of a design? (e.g., is there some reason you basically have to do that, like historically accepting the attributes in both positions?)
The attribute must always apply to the type of the function, because we can't have the streaming-property (or the properties on ZA) being lost between function overrides or function pointer assignments. It's perhaps similar to a calling convention, because the caller may have to set up streaming- or ZA state before the call, and restore state after the call.

I'm not too familiar with the different spellings/syntaxes and their implications, so I've now limited the attribute to `GNU` style attributes (`__attribute__((..))`) and to being a `TypeAttr`, with the exception of the `arm_locally_streaming` attribute, because that one can only be applied to function definitions and is not part of the type.

I've also added some new tests to ensure the properties are correctly propagated (using `decltype()`) and tests to ensure virtual function overloads require the same attributes.

Is this a step in the right direction? :)


================
Comment at: clang/lib/Sema/SemaType.cpp:7676
+      return false;
+    }
+
----------------
aaron.ballman wrote:
> sdesmalen wrote:
> > aaron.ballman wrote:
> > > Unfortunately, type attributes do not yet have any of the automated checking generated by tablegen, so there are no calls to `Sema::checkCommonAttributeFeatures()`, which means you have to manually check things like mutual exclusions, not accepting arguments, etc.
> > After some experimenting I found that:
> > * When I add the `MutualExclusions` to Attr.td and compile `typedef __attribute__((arm_streaming, arm_streaming_compatible)) void (*ptrty1) (void);`, I still get the diagnostic for conflicting attributes 'for free', even without any code being added here to check for conflicting attributes. However, when I then apply it to a declaration (e.g. `void __attribute__((arm_streaming, arm_streaming_compatible)) foo(void);`), I get the diagnostics twice.
> > * When I add some code here to mark the attribute as invalid, I get no diagnostic whatsoever unless I explicitly emit it here, rendering the use of `MutualExclusions` in Attr.td ineffective.
> > 
> > Based on the above observation, I've chosen to keep the code in SemaDeclAttr.cpp and not use the `MutualExclusions`, because it generates the best diagnostics (an error + a note) and only emits it once. Let me know what you think.
> Yeah, I can see why we'd hit that problem -- when we go to form the function type to be able to make the declaration, we'd issue the warning once, and then after forming the declaration and trying to apply attributes to it, we'd issue the warning a second time. We do not have any other `DeclOrTypeAttr` which has mutual exclusions.
> 
> I don't want to lose the declarative nature of using `MutualExclusions` in Attr.td unless there's no other choice; that's a helpful piece of documentation to reviewers when reviewing additional attributes in the future. If you elect to keep the attribute as a declaration and type attribute, I think you'll need to try to fix this to work properly.
By changing the attributes to become `TypeAttr`, the `MutualExclusions` no longer kick in at all (you mentioned this in a previous comment), so I've had to keep the manual code to check the attributes here. Are you okay with that?


================
Comment at: clang/test/Sema/aarch64-sme-func-attrs.c:89
+// expected-note at +2 {{conflicting attribute is here}}
+__attribute__((arm_preserves_za, arm_new_za)) void preserves_new_za(void);
+
----------------
aaron.ballman wrote:
> sdesmalen wrote:
> > aaron.ballman wrote:
> > > If you keep the attribute as a declaration attribute, you're also missing tests like:
> > > ```
> > > __attribute__((arm_new_za)) void func(void);
> > > __attribute__((arm_preserves_za)) void func(void) {}
> > > ```
> > > 
> > I'm not sure what you mean, there are tests for:
> > * `__attribute__((arm_new_za)) void sme_arm_new_za(void);`
> > * `__attribute__((arm_preserves_za)) void sme_arm_preserves_za(void);`
> > ?
> Those test applying mutually exclusive attributes to unique declarations, but I was asking for applying mutually exclusive attributes to redeclarations.
Good point, I've had to add some new checks to ensure we get a diagnostic when compiling for C. For C++ it already gave a `conflicting types for <function>` diagnostic. I'm not really sure why that behaviour is different between C and C++.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D127762/new/

https://reviews.llvm.org/D127762



More information about the cfe-commits mailing list