[clang] [Clang][Sema] Extend test coverage for SVE/SME builtin usage. (PR #156908)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 4 08:21:23 PDT 2025


github-actions[bot] wrote:

<!--LLVM CODE FORMAT COMMENT: {darker}-->


:warning: Python code formatter, darker found issues in your code. :warning:

<details>
<summary>
You can test this locally with the following command:
</summary>

``````````bash
darker --check --diff -r origin/main...HEAD clang/utils/aarch64_builtins_test_generator.py
``````````

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:

</details>

<details>
<summary>
View the diff from darker here.
</summary>

``````````diff
--- aarch64_builtins_test_generator.py	2025-09-04 15:15:53.000000 +0000
+++ aarch64_builtins_test_generator.py	2025-09-04 15:20:52.422430 +0000
@@ -24,37 +24,43 @@
 from enum import Enum
 from itertools import product
 from pathlib import Path
 from typing import Dict, Iterable, List, Sequence, Tuple
 
+
 # Are we testing arm_sve.h or arm_sme.h based builtins.
 class Mode(Enum):
     SVE = "sve"
     SME = "sme"
 
+
 class FunctionType(Enum):
     NORMAL = "normal"
     STREAMING = "streaming"
     STREAMING_COMPATIBLE = "streaming-compatible"
+
 
 # Builtins are grouped by their required features.
 @dataclass(frozen=True, order=True, slots=True)
 class BuiltinContext:
     guard: str
     streaming_guard: str
     flags: tuple[str, ...]
 
     def __str__(self) -> str:
-        return (f'// Properties: '
-                f'guard="{self.guard}" '
-                f'streaming_guard="{self.streaming_guard}" '
-                f'flags="{",".join(self.flags)}"')
+        return (
+            f"// Properties: "
+            f'guard="{self.guard}" '
+            f'streaming_guard="{self.streaming_guard}" '
+            f'flags="{",".join(self.flags)}"'
+        )
 
     @classmethod
     def from_json(cls, obj: dict[str, Any]) -> "BuiltinContext":
         flags = tuple(p.strip() for p in obj["flags"].split(",") if p.strip())
         return cls(obj["guard"], obj["streaming_guard"], flags)
+
 
 # --- Parsing builtins -------------------------------------------------------
 
 # Captures the full function *declaration* inside the builtin string, e.g.:
 #   "svint16_t svrevd_s16_z(svbool_t, svint16_t);"
@@ -63,10 +69,11 @@
 FUNC_RE = re.compile(r"^\s*([a-zA-Z_][\w\s\*]*[\w\*])\s*\(\s*([^)]*)\s*\)\s*;\s*$")
 
 # Pulls the final word out of the left side (the function name).
 NAME_RE = re.compile(r"([a-zA-Z_][\w]*)\s*$")
 
+
 def parse_builtin_declaration(decl: str) -> Tuple[str, List[str]]:
     """Return (func_name, param_types) from a builtin declaration string.
 
     Example:
       decl = "svint16_t svrevd_s16_z(svbool_t, svint16_t);"
@@ -86,13 +93,14 @@
 
     if not params:
         param_types: List[str] = []
     else:
         # Split by commas respecting no pointers/arrays with commas (not expected here)
-        param_types = [p.strip() for p in params.split(',') if p.strip()]
+        param_types = [p.strip() for p in params.split(",") if p.strip()]
 
     return func_name, param_types
+
 
 # --- Variable synthesis -----------------------------------------------------
 
 # Pick a safe (ideally non-zero) value for literal types
 LITERAL_TYPES_MAP: dict[str, str] = {
@@ -123,12 +131,13 @@
     "ImmCheckShiftLeft": "2",
     "ImmCheckShiftRightNarrow": "2",
     "ImmCheckShiftRight": "2",
     "enum svpattern": "SV_MUL3",
     "enum svprfop": "SV_PSTL1KEEP",
-    "void": ""
-    }
+    "void": "",
+}
+
 
 def make_arg_for_type(ty: str) -> Tuple[str, str]:
     """Return (var_decl, var_use) for a parameter type.
 
     Literal types return an empty declaration and a value that will be accepted
@@ -140,22 +149,25 @@
         return "", LITERAL_TYPES_MAP[ty]
 
     name = ty.replace(" ", "_").replace("*", "ptr") + "_val"
     return f"{ty} {name};", name
 
+
 # NOTE: Parsing is limited to the minimum required for guard strings.
 # Specifically the expected input is of the form:
 #   feat1,feat2,...(feat3 | feat4 | ...),...
-def expand_feature_guard(guard: str, flags: str, base_feature: str = None) -> list[set[str]]:
+def expand_feature_guard(
+    guard: str, flags: str, base_feature: str = None
+) -> list[set[str]]:
     """
     Expand a guard expression where ',' = AND and '|' = OR, with parentheses
     grouping OR-expressions. Returns a list of feature sets.
     """
     if not guard:
-        return [];
-
-    parts = re.split(r',(?![^(]*\))', guard)
+        return []
+
+    parts = re.split(r",(?![^(]*\))", guard)
 
     choices_per_part = []
     for part in parts:
         if part.startswith("(") and part.endswith(")"):
             choices_per_part.append(part[1:-1].split("|"))
@@ -183,12 +195,14 @@
         if s not in unique:
             unique.append(s)
 
     return unique
 
+
 def cc1_args_for_features(features: set[str]) -> str:
     return " ".join("-target-feature +" + s for s in sorted(features))
+
 
 def sanitise_guard(s: str) -> str:
     """Rewrite guard strings in a form more suitable for file naming."""
     replacements = {
         ",": "_AND_",
@@ -201,10 +215,11 @@
 
     # Collapse multiple underscores
     s = re.sub(r"_+", "_", s)
     return s.strip("_")
 
+
 def make_filename(prefix: str, ctx: BuiltinContext, ext: str) -> str:
     parts = [sanitise_guard(ctx.guard), sanitise_guard(ctx.streaming_guard)]
     sanitised_guard = "___".join(p for p in parts if p)
 
     if "streaming-only" in ctx.flags:
@@ -216,46 +231,56 @@
     else:
         prefix += "_non_streaming_only"
 
     return f"{prefix}_{sanitised_guard}{ext}"
 
+
 # --- Code Generation --------------------------------------------------------
+
 
 def emit_streaming_guard_run_lines(ctx: BuiltinContext) -> str:
     """Emit lit RUN lines that will exercise the relevent Sema diagnistics."""
     run_prefix = "// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-none-linux-gnu"
     out: List[str] = []
 
     # All RUN lines have SVE and SME enabled
     guard_features = expand_feature_guard(ctx.guard, ctx.flags, "sme")
-    streaming_guard_features = expand_feature_guard(ctx.streaming_guard, ctx.flags, "sve")
+    streaming_guard_features = expand_feature_guard(
+        ctx.streaming_guard, ctx.flags, "sve"
+    )
 
     if "streaming-only" in ctx.flags:
         assert not guard_features
         # Generate RUN lines for features only availble to streaming functions
         for feats in streaming_guard_features:
-            out.append(f"{run_prefix} {cc1_args_for_features(feats)} -verify=streaming-guard")
+            out.append(
+                f"{run_prefix} {cc1_args_for_features(feats)} -verify=streaming-guard"
+            )
     elif "streaming-compatible" in ctx.flags:
         assert not guard_features
         # NOTE: Streaming compatible builtins don't require SVE.
         # Generate RUN lines for features available to all functions.
         for feats in expand_feature_guard(ctx.streaming_guard, ctx.flags):
             out.append(f"{run_prefix} {cc1_args_for_features(feats)} -verify")
         out.append("// expected-no-diagnostics")
     elif "feature-dependent" in ctx.flags:
         assert guard_features and streaming_guard_features
-        combined_features = expand_feature_guard(ctx.guard + "," + ctx.streaming_guard, ctx.flags)
+        combined_features = expand_feature_guard(
+            ctx.guard + "," + ctx.streaming_guard, ctx.flags
+        )
 
         # Generate RUN lines for features only availble to normal functions
         for feats in guard_features:
             if feats not in combined_features:
                 out.append(f"{run_prefix} {cc1_args_for_features(feats)} -verify=guard")
 
         # Geneate RUN lines for features only available to streaming functions
         for feats in streaming_guard_features:
             if feats not in combined_features:
-                out.append(f"{run_prefix} {cc1_args_for_features(feats)} -verify=streaming-guard")
+                out.append(
+                    f"{run_prefix} {cc1_args_for_features(feats)} -verify=streaming-guard"
+                )
 
         # Generate RUN lines for features available to all functions
         for feats in combined_features:
             out.append(f"{run_prefix} {cc1_args_for_features(feats)} -verify")
 
@@ -266,32 +291,45 @@
         for feats in guard_features:
             out.append(f"{run_prefix} {cc1_args_for_features(feats)} -verify=guard")
 
     return "\n".join(out)
 
-def emit_streaming_guard_function(ctx: BuiltinContext, var_decls: Sequence[str], calls: Sequence[str], func_name: str, func_type: FunctionType = FunctionType.NORMAL) -> str:
+
+def emit_streaming_guard_function(
+    ctx: BuiltinContext,
+    var_decls: Sequence[str],
+    calls: Sequence[str],
+    func_name: str,
+    func_type: FunctionType = FunctionType.NORMAL,
+) -> str:
     """Emit a C function calling all builtins.
 
     `calls` is a sequence of tuples: (name, call_line)
     """
     # Expected Sema diagnostics for invalid usage
     require_diagnostic = require_streaming_diagnostic = False
     if "streaming-only" in ctx.flags:
         if func_type != FunctionType.STREAMING:
             require_streaming_diagnostic = True
     elif "streaming-compatible" in ctx.flags:
-        pass # streaming compatible builtins are always available
+        pass  # streaming compatible builtins are always available
     elif "feature-dependent" in ctx.flags:
         guard_features = expand_feature_guard(ctx.guard, ctx.flags, "sme")
-        streaming_guard_features = expand_feature_guard(ctx.streaming_guard, ctx.flags, "sve")
-        combined_features = expand_feature_guard(ctx.guard + "," + ctx.streaming_guard, ctx.flags)
+        streaming_guard_features = expand_feature_guard(
+            ctx.streaming_guard, ctx.flags, "sve"
+        )
+        combined_features = expand_feature_guard(
+            ctx.guard + "," + ctx.streaming_guard, ctx.flags
+        )
 
         if func_type != FunctionType.NORMAL:
             if any(feats not in combined_features for feats in guard_features):
                 require_diagnostic = True
         if func_type != FunctionType.STREAMING:
-            if any(feats not in combined_features for feats in streaming_guard_features):
+            if any(
+                feats not in combined_features for feats in streaming_guard_features
+            ):
                 require_streaming_diagnostic = True
     else:
         if func_type != FunctionType.NORMAL:
             require_diagnostic = True
 
@@ -317,30 +355,39 @@
         out.append("")
 
     # Emit calls
     for call in calls:
         if require_diagnostic and require_streaming_diagnostic:
-            out.append("  // guard-error at +2 {{builtin can only be called from a non-streaming function}}")
-            out.append("  // streaming-guard-error at +1 {{builtin can only be called from a streaming function}}")
+            out.append(
+                "  // guard-error at +2 {{builtin can only be called from a non-streaming function}}"
+            )
+            out.append(
+                "  // streaming-guard-error at +1 {{builtin can only be called from a streaming function}}"
+            )
         elif require_diagnostic:
-            out.append("  // guard-error at +1 {{builtin can only be called from a non-streaming function}}")
+            out.append(
+                "  // guard-error at +1 {{builtin can only be called from a non-streaming function}}"
+            )
         elif require_streaming_diagnostic:
-            out.append("  // streaming-guard-error at +1 {{builtin can only be called from a streaming function}}")
+            out.append(
+                "  // streaming-guard-error at +1 {{builtin can only be called from a streaming function}}"
+            )
         out.append(f"  {call}")
 
     out.append("}")
     return "\n".join(out) + "\n"
 
+
 def natural_key(s: str):
     """Allow sorting akin to "sort -V"""
-    return [int(text) if text.isdigit() else text
-            for text in re.split(r'(\d+)', s)]
+    return [int(text) if text.isdigit() else text for text in re.split(r"(\d+)", s)]
+
 
 def build_calls_for_group(builtins: Iterable[str]) -> Tuple[List[str], List[str]]:
     """From a list of builtin declaration strings, produce:
-      - a sorted list of unique variable declarations
-      - a sorted list of builtin calls
+    - a sorted list of unique variable declarations
+    - a sorted list of builtin calls
     """
     var_decls: List[str] = []
     seen_types: set[str] = set()
     calls: List[Tuple[str, str]] = []
 
@@ -361,10 +408,11 @@
     calls.sort(key=lambda t: natural_key(t))
     var_decls.sort(key=natural_key)
 
     return var_decls, calls
 
+
 def gen_streaming_guard_tests(mode: MODE, json_path: Path, out_dir: Path) -> None:
     """Generate a set of Clang Sema test files to ensure SVE/SME builtins are
     callable based on the function type, or the required diagnostic is emitted.
     """
     try:
@@ -379,67 +427,100 @@
 
     # For each guard pair, emit 3 functions
     for builtin_ctx, builtin_decls in by_guard.items():
         var_decls, calls = build_calls_for_group(builtin_decls)
 
-        out_parts: List[str] = [];
-        out_parts.append("// NOTE: File has been autogenerated by utils/aarch64_builtins_test_generator.py")
+        out_parts: List[str] = []
+        out_parts.append(
+            "// NOTE: File has been autogenerated by utils/aarch64_builtins_test_generator.py"
+        )
         out_parts.append(emit_streaming_guard_run_lines(builtin_ctx))
         out_parts.append("")
         out_parts.append("// REQUIRES: aarch64-registered-target")
         out_parts.append("")
         out_parts.append(f"#include <arm_{mode.value}.h>")
         out_parts.append("")
         out_parts.append(str(builtin_ctx))
         out_parts.append("")
-        out_parts.append(emit_streaming_guard_function(builtin_ctx, var_decls, calls, "test"))
-        out_parts.append(emit_streaming_guard_function(builtin_ctx, var_decls, calls, "test_streaming", FunctionType.STREAMING))
-        out_parts.append(emit_streaming_guard_function(builtin_ctx, var_decls, calls, "test_streaming_compatible", FunctionType.STREAMING_COMPATIBLE))
+        out_parts.append(
+            emit_streaming_guard_function(builtin_ctx, var_decls, calls, "test")
+        )
+        out_parts.append(
+            emit_streaming_guard_function(
+                builtin_ctx, var_decls, calls, "test_streaming", FunctionType.STREAMING
+            )
+        )
+        out_parts.append(
+            emit_streaming_guard_function(
+                builtin_ctx,
+                var_decls,
+                calls,
+                "test_streaming_compatible",
+                FunctionType.STREAMING_COMPATIBLE,
+            )
+        )
 
         output = "\n".join(out_parts).rstrip() + "\n"
 
         if out_dir:
             out_dir.mkdir(parents=True, exist_ok=True)
             filename = make_filename(f"arm_{mode.value}", builtin_ctx, ".c")
             (out_dir / filename).write_text(output)
         else:
-           print(output)
+            print(output)
 
     return 0
 
+
 # --- Main -------------------------------------------------------------------
+
 
 def existing_file(path: str) -> Path:
     p = Path(path)
     if not p.is_file():
         raise argparse.ArgumentTypeError(f"{p} is not a valid file")
     return p
 
+
 def main(argv: Sequence[str] | None = None) -> int:
     ap = argparse.ArgumentParser(description="Emit C tests for SVE/SME builtins")
-    ap.add_argument("json", type=existing_file,
-                    help="Path to json formatted builtin descriptions")
-    ap.add_argument("--out-dir", type=Path, default=None,
-                    help="Output directory (default: stdout)")
-    ap.add_argument("--gen-streaming-guard-tests", action="store_true",
-                    help="Generate C tests to validate SVE/SME builtin usage base on streaming attribute")
-    ap.add_argument("--gen-target-guard-tests", action="store_true",
-                    help="Generate C tests to validate SVE/SME builtin usage based on target features")
-    ap.add_argument("--gen-builtin-tests", action="store_true",
-                    help="Generate C tests to exercise SVE/SME builtins")
-    ap.add_argument("--base-target-feature", choices=["sve", "sme"],
-                    help="Force builtin source (sve: arm_sve.h, sme: arm_sme.h)")
+    ap.add_argument(
+        "json", type=existing_file, help="Path to json formatted builtin descriptions"
+    )
+    ap.add_argument(
+        "--out-dir", type=Path, default=None, help="Output directory (default: stdout)"
+    )
+    ap.add_argument(
+        "--gen-streaming-guard-tests",
+        action="store_true",
+        help="Generate C tests to validate SVE/SME builtin usage base on streaming attribute",
+    )
+    ap.add_argument(
+        "--gen-target-guard-tests",
+        action="store_true",
+        help="Generate C tests to validate SVE/SME builtin usage based on target features",
+    )
+    ap.add_argument(
+        "--gen-builtin-tests",
+        action="store_true",
+        help="Generate C tests to exercise SVE/SME builtins",
+    )
+    ap.add_argument(
+        "--base-target-feature",
+        choices=["sve", "sme"],
+        help="Force builtin source (sve: arm_sve.h, sme: arm_sme.h)",
+    )
 
     args = ap.parse_args(argv)
 
     # When not forced, try to infer the mode from the input, defaulting to SVE.
     if args.base_target_feature:
-        mode=Mode(args.base_target_feature)
+        mode = Mode(args.base_target_feature)
     elif args.json and args.json.name == "arm_sme_builtins.json":
-        mode=Mode.SME
+        mode = Mode.SME
     else:
-        mode=Mode.SVE
+        mode = Mode.SVE
 
     # Generate test file
     if args.gen_streaming_guard_tests:
         gen_streaming_guard_tests(mode, args.json, args.out_dir)
     if args.gen_target_guard_tests:
@@ -447,7 +528,8 @@
     if args.gen_builtin_tests:
         ap.error("--gen-builtin-tests not implemented yet!")
 
     return 0
 
+
 if __name__ == "__main__":
     raise SystemExit(main())

``````````

</details>


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


More information about the cfe-commits mailing list