[clang] [llvm] [Clang][SME] Detect always_inline used with mismatched streaming attributes (PR #77936)

Sander de Smalen via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 26 09:21:37 PST 2024


================
@@ -814,6 +821,93 @@ Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
                           /*allowHigherAlign*/ false);
 }
 
+class SMEAttributes {
+public:
+  bool IsStreaming = false;
+  bool IsStreamingBody = false;
+  bool IsStreamingCompatible = false;
+  bool HasNewZA = false;
+
+  SMEAttributes(const FunctionDecl *F) {
+    if (F->hasAttr<ArmLocallyStreamingAttr>())
+      IsStreamingBody = true;
+    if (auto *NewAttr = F->getAttr<ArmNewAttr>()) {
+      if (NewAttr->isNewZA())
+        HasNewZA = true;
+    }
+    if (const auto *T = F->getType()->getAs<FunctionProtoType>()) {
+      if (T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask)
+        IsStreaming = true;
+      if (T->getAArch64SMEAttributes() &
+          FunctionType::SME_PStateSMCompatibleMask)
+        IsStreamingCompatible = true;
+    }
+  }
+
+  bool hasStreamingBody() const { return IsStreamingBody; }
+  bool hasStreamingInterface() const { return IsStreaming; }
+  bool hasStreamingCompatibleInterface() const { return IsStreamingCompatible; }
+  bool hasStreamingInterfaceOrBody() const {
+    return hasStreamingBody() || hasStreamingInterface();
+  }
+  bool hasNonStreamingInterface() const {
+    return !hasStreamingInterface() && !hasStreamingCompatibleInterface();
+  }
+  bool hasNonStreamingInterfaceAndBody() const {
+    return hasNonStreamingInterface() && !hasStreamingBody();
+  }
+
+  bool requiresSMChange(const SMEAttributes Callee,
+                        bool BodyOverridesInterface = false) {
+    // If the transition is not through a call (e.g. when considering inlining)
+    // and Callee has a streaming body, then we can ignore the interface of
+    // Callee.
+    if (BodyOverridesInterface && Callee.hasStreamingBody()) {
+      return !hasStreamingInterfaceOrBody();
+    }
+
+    if (Callee.hasStreamingCompatibleInterface())
+      return false;
+
+    if (hasStreamingCompatibleInterface())
+      return true;
+
+    // Both non-streaming
+    if (hasNonStreamingInterfaceAndBody() && Callee.hasNonStreamingInterface())
+      return false;
+
+    // Both streaming
+    if (hasStreamingInterfaceOrBody() && Callee.hasStreamingInterface())
+      return false;
+
+    return Callee.hasStreamingInterface();
+  }
+
+  bool hasNewZABody() { return HasNewZA; }
+  bool requiresLazySave() const { return HasNewZA; }
+};
+
+void AArch64TargetCodeGenInfo::checkFunctionCallABI(
+    CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
+    const FunctionDecl *Callee, const CallArgList &Args) const {
+  if (!Callee->hasAttr<AlwaysInlineAttr>())
+    return;
+
+  SMEAttributes CalleeAttrs(Callee);
+  SMEAttributes CallerAttrs(Caller);
+
+  if (CallerAttrs.requiresSMChange(CalleeAttrs, true))
----------------
sdesmalen-arm wrote:

I think you can write this code without mimicking the (LLVM) SMEAttributes class, which makes the code a lot simpler.

For example, for the streaming-mode diagnostic you could do something like this:
```
bool CallerIsStreaming = Caller->hasAttr<ArmLocallyStreamingAttr>() || (CallerAttrs & SME_PStateSMEnabledMask);
bool CalleeIsStreaming = ...

bool CallerIsStreamingCompatible = !CallerIsStreaming && (CallerAttrs & SME_PStateSMCompatibleMask);
bool CalleeIsStreamingCompatible = ...

if (!CalleeIsStreamingCompatible)
  if (CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible))
    // emit diagnostic
```

https://github.com/llvm/llvm-project/pull/77936


More information about the cfe-commits mailing list