[clang] [Clang][AArch64] Generalise streaming mode checks for builtins. (PR #93802)

Paul Walker via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 4 09:53:01 PDT 2024


================
@@ -561,16 +561,61 @@ SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
 
 static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
                                      const FunctionDecl *FD,
-                                     SemaARM::ArmStreamingType BuiltinType) {
+                                     SemaARM::ArmStreamingType BuiltinType,
+                                     unsigned BuiltinID) {
   SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD);
-  if (BuiltinType == SemaARM::ArmStreamingOrSVE2p1) {
-    // Check intrinsics that are available in [sve2p1 or sme/sme2].
-    llvm::StringMap<bool> CallerFeatureMap;
-    S.Context.getFunctionFeatureMap(CallerFeatureMap, FD);
-    if (Builtin::evaluateRequiredTargetFeatures("sve2p1", CallerFeatureMap))
+
+  // Check if the intrinsic is available in the right mode, i.e.
+  // * When compiling for SME only, the caller must be in streaming mode.
+  // * When compiling for SVE only, the caller must be in non-streaming mode.
+  // * When compiling for both SVE and SME, the caller can be in either mode.
+  if (BuiltinType == SemaARM::ArmStreamingOrHasSVE) {
+    static const FunctionDecl *CachedFD = nullptr;
+    bool SatisfiesSVE = false, SatisfiesSME = false;
+
+    if (FD != CachedFD) {
+      // We know the builtin requires either some combination of SVE flags, or
+      // some combination of SME flags, but we need to figure out which part
+      // of the required features is satisfied by the target features.
+      //
+      // For a builtin with target guard 'sve2p1|sme2', if we compile with
+      // '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we
+      // evaluate the features for '+sve2p1,+sme,+nosme'.
+      //
+      // Similarly, if we compile with '+sve2,+sme2', then we know it satisfies
+      // the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'.
+      llvm::StringMap<bool> CallerFeatureMap;
+      auto DisableFeatures = [&CallerFeatureMap](StringRef S) {
+        for (StringRef K : CallerFeatureMap.keys())
+          if (K.starts_with(S))
+            CallerFeatureMap[K] = false;
+      };
+
+      StringRef BuiltinTargetGuards(
+          S.Context.BuiltinInfo.getRequiredFeatures(BuiltinID));
+
+      S.Context.getFunctionFeatureMap(CallerFeatureMap, FD);
+      DisableFeatures("sme");
+      SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
+          BuiltinTargetGuards, CallerFeatureMap);
+
+      S.Context.getFunctionFeatureMap(CallerFeatureMap, FD);
+      DisableFeatures("sve");
+      SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
+          BuiltinTargetGuards, CallerFeatureMap);
+
+      CachedFD = FD;
+    }
+
+    if (SatisfiesSVE && SatisfiesSME)
----------------
paulwalker-arm wrote:

Does this effectively prevent streaming compatible functions when only SVE feature flags are available?

My updated understand of streaming compatible functions is that SME features play no role and the user is expected to use SVE feature flags to direct the compiler to the level of SVE support a streaming compatible function can have, much like they would for ordinary functions.

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


More information about the cfe-commits mailing list