Skip to content

Conversation

paulwalker-arm
Copy link
Collaborator

Adds SEMA tests to verify correct SVE/SME builtin usage based on the calling function's type (i.e. normal, streaming or streaming compatible).

For invalid uses the tests verify the expected diagnostic is emitted. This exposed an issue whereby some builtins are incorrectly callable by streaming compatible functions, which this PR fixes.

The tests are autogenerated based on the builtin definitions (e.g. arm_sve.td). This is achieved by extending SVEEmitter, which can now emit a JSON file containing builtin usage information that can be fed to aarch64_builtins_test_generator.py that is also part of this PR.

Everything currently in clang/test/Sema/AArch64 is the result of:

clang/utils/aarch64_builtins_test_generator.py --gen-streaming-guard-tests <LLVM_BUILD_DIR>/tools/clang/include/clang/Basic/arm_sve_builtins.json --out-dir clang/test/Sema/AArch64/
clang/utils/aarch64_builtins_test_generator.py --gen-streaming-guard-tests <LLVM_BUILD_DIR>/tools/clang/include/clang/Basic/arm_sme_builtins.json --out-dir clang/test/Sema/AArch64/

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:ARM backend:AArch64 clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-aarch64

Author: Paul Walker (paulwalker-arm)

Changes

Adds SEMA tests to verify correct SVE/SME builtin usage based on the calling function's type (i.e. normal, streaming or streaming compatible).

For invalid uses the tests verify the expected diagnostic is emitted. This exposed an issue whereby some builtins are incorrectly callable by streaming compatible functions, which this PR fixes.

The tests are autogenerated based on the builtin definitions (e.g. arm_sve.td). This is achieved by extending SVEEmitter, which can now emit a JSON file containing builtin usage information that can be fed to aarch64_builtins_test_generator.py that is also part of this PR.

Everything currently in clang/test/Sema/AArch64 is the result of:

clang/utils/aarch64_builtins_test_generator.py --gen-streaming-guard-tests &lt;LLVM_BUILD_DIR&gt;/tools/clang/include/clang/Basic/arm_sve_builtins.json --out-dir clang/test/Sema/AArch64/
clang/utils/aarch64_builtins_test_generator.py --gen-streaming-guard-tests &lt;LLVM_BUILD_DIR&gt;/tools/clang/include/clang/Basic/arm_sme_builtins.json --out-dir clang/test/Sema/AArch64/

Patch is 4.27 MiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/156908.diff

68 Files Affected:

  • (modified) clang/include/clang/Basic/CMakeLists.txt (+6)
  • (modified) clang/lib/Sema/SemaARM.cpp (+2-2)
  • (modified) clang/test/CodeGen/AArch64/sve2-intrinsics/acle_sve2_rax1.c (+5-6)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme.c (+48)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme_AND_sme2.c (+33)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme.c (+1491)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_LP_sme-f16f16_OR_sme-f8f16_RP.c (+70)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme-b16b16.c (+215)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme-f16f16.c (+175)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme-f64f64.c (+46)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme-f8f16.c (+198)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme-f8f32.c (+208)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme-i16i64.c (+155)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme-lutv2.c (+309)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2.c (+308)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-f64f64.c (+192)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-i16i64.c (+759)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-mop4.c (+782)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-mop4_AND_sme-b16b16.c (+106)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-mop4_AND_sme-f16f16.c (+106)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-mop4_AND_sme-f64f64.c (+106)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-mop4_AND_sme-f8f16.c (+69)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-mop4_AND_sme-f8f32.c (+69)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-mop4_AND_sme-i16i64.c (+352)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-tmop.c (+152)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-tmop_AND_sme-b16b16.c (+39)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-tmop_AND_sme-f16f16.c (+39)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-tmop_AND_sme-f8f16.c (+42)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2_AND_sme-tmop_AND_sme-f8f32.c (+42)
  • (added) clang/test/Sema/AArch64/arm_sme_streaming_only_sme_AND_sme2p1.c (+713)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_LP_sve2p1_OR_sme2_RP___sme_AND_LP_sve2p1_OR_sme2_RP.c (+415)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_LP_sve2p1_OR_sme2p1_RP___sme_AND_LP_sve2p1_OR_sme2p1_RP.c (+2317)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_LP_sve2p1_OR_sme_RP___sme.c (+360)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_bf16___sme_AND_bf16.c (+111)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_i8mm___sme_AND_i8mm.c (+72)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve-aes___sme_AND_ssve-aes.c (+144)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve-b16b16___sme_AND_sme2_AND_sve-b16b16.c (+611)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve-bitperm___sme_AND_ssve-bitperm.c (+383)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve-sha3___sme_AND_sve-sha3_AND_sme2p1.c (+48)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2_AND_faminmax___sme_AND_sme2_AND_faminmax.c (+548)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2_AND_fp8___sme_AND_sme2_AND_fp8.c (+206)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2_AND_fp8dot2___sme_AND_ssve-fp8dot2.c (+77)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2_AND_fp8dot4___sme_AND_ssve-fp8dot4.c (+77)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2_AND_fp8fma___sme_AND_ssve-fp8fma.c (+290)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2_AND_lut___sme_AND_sme2_AND_lut.c (+277)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2___sme.c (+16470)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve_AND_sve2p1___sme_AND_sme2.c (+3690)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve___sme.c (+19470)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve___sme_AND_sme2_AND_ssve-fexpa.c (+61)
  • (added) clang/test/Sema/AArch64/arm_sve_feature_dependent_sve___sme_AND_sme2p2.c (+103)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve.c (+5881)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve_AND_bf16.c (+36)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve_AND_f32mm.c (+33)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve_AND_f64mm.c (+958)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve_AND_i8mm.c (+62)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve_AND_sve-sm4.c (+43)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve_AND_sve2.c (+2386)
  • (added) clang/test/Sema/AArch64/arm_sve_non_streaming_only_sve_AND_sve2p1.c (+1754)
  • (added) clang/test/Sema/AArch64/arm_sve_streaming_only_sme_AND_sme-f16f16.c (+43)
  • (added) clang/test/Sema/AArch64/arm_sve_streaming_only_sme_AND_sme2.c (+4034)
  • (added) clang/test/Sema/AArch64/arm_sve_streaming_only_sme_AND_sme2_AND_faminmax.c (+158)
  • (added) clang/test/Sema/AArch64/arm_sve_streaming_only_sme_AND_sme2_AND_fp8.c (+314)
  • (added) clang/test/Sema/AArch64/arm_sve_streaming_only_sme_AND_sme2_AND_sve-b16b16.c (+209)
  • (removed) clang/test/Sema/aarch64-streaming-sme-or-nonstreaming-sve-builtins.c (-70)
  • (modified) clang/utils/TableGen/SveEmitter.cpp (+107-3)
  • (modified) clang/utils/TableGen/TableGen.cpp (+12)
  • (modified) clang/utils/TableGen/TableGenBackends.h (+4)
  • (added) clang/utils/aarch64_builtins_test_generator.py (+453)
diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index 81736006a21a0..cfd165e6fa7e1 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -159,6 +159,9 @@ clang_tablegen(arm_mve_builtin_aliases.inc -gen-arm-mve-builtin-aliases
 clang_tablegen(arm_sve_builtins.inc -gen-arm-sve-builtins
   SOURCE arm_sve.td
   TARGET ClangARMSveBuiltins)
+clang_tablegen(arm_sve_builtins.json -gen-arm-sve-builtins-json
+  SOURCE arm_sve.td
+  TARGET ClangARMSveBuiltinsJSON)
 clang_tablegen(arm_sve_builtin_cg.inc -gen-arm-sve-builtin-codegen
   SOURCE arm_sve.td
   TARGET ClangARMSveBuiltinCG)
@@ -174,6 +177,9 @@ clang_tablegen(arm_sve_streaming_attrs.inc -gen-arm-sve-streaming-attrs
 clang_tablegen(arm_sme_builtins.inc -gen-arm-sme-builtins
   SOURCE arm_sme.td
   TARGET ClangARMSmeBuiltins)
+clang_tablegen(arm_sme_builtins.json -gen-arm-sme-builtins-json
+  SOURCE arm_sme.td
+  TARGET ClangARMSmeBuiltinsJSON)
 clang_tablegen(arm_sme_builtin_cg.inc -gen-arm-sme-builtin-codegen
   SOURCE arm_sme.td
   TARGET ClangARMSmeBuiltinCG)
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index e09c35296ef3b..1c7c832d7edfa 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -603,8 +603,8 @@ static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
     bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
         StreamingBuiltinGuard, CallerFeatures);
 
-    if ((SatisfiesSVE && SatisfiesSME) ||
-        (SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible))
+    if (SatisfiesSVE && SatisfiesSME)
+      // Function type is irrelevant for streaming-agnostic builtins.
       return false;
     else if (SatisfiesSVE)
       BuiltinType = SemaARM::ArmNonStreaming;
diff --git a/clang/test/CodeGen/AArch64/sve2-intrinsics/acle_sve2_rax1.c b/clang/test/CodeGen/AArch64/sve2-intrinsics/acle_sve2_rax1.c
index 42bc37b9ef17c..480d4e4744f0a 100644
--- a/clang/test/CodeGen/AArch64/sve2-intrinsics/acle_sve2_rax1.c
+++ b/clang/test/CodeGen/AArch64/sve2-intrinsics/acle_sve2_rax1.c
@@ -1,10 +1,9 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
-// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sve -target-feature +sve2 -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2 -target-feature +sme2p1 -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sve -target-feature +sve2 -target-feature +sme2p1 -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sve -target-feature +sve2 -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK
-// RUN: %clang_cc1 -fclang-abi-compat=latest -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -target-feature +sve2 -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -fclang-abi-compat=latest -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -target-feature +sve2 -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK
+// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sve -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sme -target-feature +sme2p1 -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fclang-abi-compat=latest -triple aarch64 -target-feature +sve -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK
+// RUN: %clang_cc1 -fclang-abi-compat=latest -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fclang-abi-compat=latest -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +sve -target-feature +sve-sha3 -O1 -Werror -Wall -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefix=CPP-CHECK
 
 // REQUIRES: aarch64-registered-target
 
diff --git a/clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme.c b/clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme.c
new file mode 100644
index 0000000000000..f695e278d91ad
--- /dev/null
+++ b/clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme.c
@@ -0,0 +1,48 @@
+// NOTE: File has been autogenerated by utils/aarch64_builtins_test_generator.py
+// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -verify
+// expected-no-diagnostics
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_sme.h>
+
+// Properties: guard="" streaming_guard="sme" flags="streaming-compatible,requires-za"
+
+void test(void) __arm_inout("za"){
+  int64_t int64_t_val;
+  uint32_t uint32_t_val;
+  void * void_ptr_val;
+
+  svldr_vnum_za(uint32_t_val, void_ptr_val, int64_t_val);
+  svldr_za(uint32_t_val, void_ptr_val);
+  svstr_vnum_za(uint32_t_val, void_ptr_val, int64_t_val);
+  svstr_za(uint32_t_val, void_ptr_val);
+  svzero_mask_za(2);
+  svzero_za();
+}
+
+void test_streaming(void) __arm_streaming __arm_inout("za"){
+  int64_t int64_t_val;
+  uint32_t uint32_t_val;
+  void * void_ptr_val;
+
+  svldr_vnum_za(uint32_t_val, void_ptr_val, int64_t_val);
+  svldr_za(uint32_t_val, void_ptr_val);
+  svstr_vnum_za(uint32_t_val, void_ptr_val, int64_t_val);
+  svstr_za(uint32_t_val, void_ptr_val);
+  svzero_mask_za(2);
+  svzero_za();
+}
+
+void test_streaming_compatible(void) __arm_streaming_compatible __arm_inout("za"){
+  int64_t int64_t_val;
+  uint32_t uint32_t_val;
+  void * void_ptr_val;
+
+  svldr_vnum_za(uint32_t_val, void_ptr_val, int64_t_val);
+  svldr_za(uint32_t_val, void_ptr_val);
+  svstr_vnum_za(uint32_t_val, void_ptr_val, int64_t_val);
+  svstr_za(uint32_t_val, void_ptr_val);
+  svzero_mask_za(2);
+  svzero_za();
+}
diff --git a/clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme_AND_sme2.c b/clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme_AND_sme2.c
new file mode 100644
index 0000000000000..ea17ab9c6a5d0
--- /dev/null
+++ b/clang/test/Sema/AArch64/arm_sme_streaming_compatible_sme_AND_sme2.c
@@ -0,0 +1,33 @@
+// NOTE: File has been autogenerated by utils/aarch64_builtins_test_generator.py
+// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -verify
+// expected-no-diagnostics
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_sme.h>
+
+// Properties: guard="" streaming_guard="sme,sme2" flags="streaming-compatible,requires-zt"
+
+void test(void) __arm_inout("zt0"){
+  void * void_ptr_val;
+
+  svldr_zt(0, void_ptr_val);
+  svstr_zt(0, void_ptr_val);
+  svzero_zt(0);
+}
+
+void test_streaming(void) __arm_streaming __arm_inout("zt0"){
+  void * void_ptr_val;
+
+  svldr_zt(0, void_ptr_val);
+  svstr_zt(0, void_ptr_val);
+  svzero_zt(0);
+}
+
+void test_streaming_compatible(void) __arm_streaming_compatible __arm_inout("zt0"){
+  void * void_ptr_val;
+
+  svldr_zt(0, void_ptr_val);
+  svstr_zt(0, void_ptr_val);
+  svzero_zt(0);
+}
diff --git a/clang/test/Sema/AArch64/arm_sme_streaming_only_sme.c b/clang/test/Sema/AArch64/arm_sme_streaming_only_sme.c
new file mode 100644
index 0000000000000..29bc3aab3f9c6
--- /dev/null
+++ b/clang/test/Sema/AArch64/arm_sme_streaming_only_sme.c
@@ -0,0 +1,1491 @@
+// NOTE: File has been autogenerated by utils/aarch64_builtins_test_generator.py
+// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sve -verify=streaming-guard
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_sme.h>
+
+// Properties: guard="" streaming_guard="sme" flags="streaming-only,requires-za"
+
+void test(void) __arm_inout("za"){
+  int64_t int64_t_val;
+  svbfloat16_t svbfloat16_t_val;
+  svbool_t svbool_t_val;
+  svfloat16_t svfloat16_t_val;
+  svfloat32_t svfloat32_t_val;
+  svfloat64_t svfloat64_t_val;
+  svint8_t svint8_t_val;
+  svint16_t svint16_t_val;
+  svint32_t svint32_t_val;
+  svint64_t svint64_t_val;
+  svmfloat8_t svmfloat8_t_val;
+  svuint8_t svuint8_t_val;
+  svuint16_t svuint16_t_val;
+  svuint32_t svuint32_t_val;
+  svuint64_t svuint64_t_val;
+  uint32_t uint32_t_val;
+  void * void_ptr_val;
+
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddha_za32_m(2, svbool_t_val, svbool_t_val, svint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddha_za32_m(2, svbool_t_val, svbool_t_val, svuint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddha_za32_s32_m(2, svbool_t_val, svbool_t_val, svint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddha_za32_u32_m(2, svbool_t_val, svbool_t_val, svuint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddva_za32_m(2, svbool_t_val, svbool_t_val, svint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddva_za32_m(2, svbool_t_val, svbool_t_val, svuint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddva_za32_s32_m(2, svbool_t_val, svbool_t_val, svint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svaddva_za32_u32_m(2, svbool_t_val, svbool_t_val, svuint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_vnum_za8(0, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_vnum_za16(1, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_vnum_za32(2, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_vnum_za64(2, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_vnum_za128(2, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_za8(0, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_za16(1, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_za32(2, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_za64(2, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_hor_za128(2, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_vnum_za8(0, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_vnum_za16(1, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_vnum_za32(2, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_vnum_za64(2, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_vnum_za128(2, uint32_t_val, svbool_t_val, void_ptr_val, int64_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_za8(0, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_za16(1, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_za32(2, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_za64(2, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svld1_ver_za128(2, uint32_t_val, svbool_t_val, void_ptr_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_bf16_m(2, svbool_t_val, svbool_t_val, svbfloat16_t_val, svbfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_f16_m(2, svbool_t_val, svbool_t_val, svfloat16_t_val, svfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_f32_m(2, svbool_t_val, svbool_t_val, svfloat32_t_val, svfloat32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_m(2, svbool_t_val, svbool_t_val, svbfloat16_t_val, svbfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_m(2, svbool_t_val, svbool_t_val, svfloat16_t_val, svfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_m(2, svbool_t_val, svbool_t_val, svfloat32_t_val, svfloat32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_m(2, svbool_t_val, svbool_t_val, svint8_t_val, svint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_m(2, svbool_t_val, svbool_t_val, svuint8_t_val, svuint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_s8_m(2, svbool_t_val, svbool_t_val, svint8_t_val, svint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmopa_za32_u8_m(2, svbool_t_val, svbool_t_val, svuint8_t_val, svuint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_bf16_m(2, svbool_t_val, svbool_t_val, svbfloat16_t_val, svbfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_f16_m(2, svbool_t_val, svbool_t_val, svfloat16_t_val, svfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_f32_m(2, svbool_t_val, svbool_t_val, svfloat32_t_val, svfloat32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_m(2, svbool_t_val, svbool_t_val, svbfloat16_t_val, svbfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_m(2, svbool_t_val, svbool_t_val, svfloat16_t_val, svfloat16_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_m(2, svbool_t_val, svbool_t_val, svfloat32_t_val, svfloat32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_m(2, svbool_t_val, svbool_t_val, svint8_t_val, svint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_m(2, svbool_t_val, svbool_t_val, svuint8_t_val, svuint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_s8_m(2, svbool_t_val, svbool_t_val, svint8_t_val, svint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svmops_za32_u8_m(2, svbool_t_val, svbool_t_val, svuint8_t_val, svuint8_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za8_m(svint8_t_val, svbool_t_val, 0, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za8_m(svmfloat8_t_val, svbool_t_val, 0, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za8_m(svuint8_t_val, svbool_t_val, 0, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za8_mf8_m(svmfloat8_t_val, svbool_t_val, 0, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za8_s8_m(svint8_t_val, svbool_t_val, 0, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za8_u8_m(svuint8_t_val, svbool_t_val, 0, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_bf16_m(svbfloat16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_f16_m(svfloat16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_m(svbfloat16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_m(svfloat16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_m(svint16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_m(svuint16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_s16_m(svint16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za16_u16_m(svuint16_t_val, svbool_t_val, 1, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za32_f32_m(svfloat32_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za32_m(svfloat32_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za32_m(svint32_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za32_m(svuint32_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za32_s32_m(svint32_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za32_u32_m(svuint32_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za64_f64_m(svfloat64_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za64_m(svfloat64_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za64_m(svint64_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za64_m(svuint64_t_val, svbool_t_val, 2, uint32_t_val);
+  // streaming-guard-error@+1 {{builtin can only be called from a streaming function}}
+  svread_hor_za64_s64_m(svint64_t_val, svbool_t_val, 2, uint32_t_val);
...
[truncated]

Copy link

github-actions bot commented Sep 4, 2025

✅ With the latest revision this PR passed the Python code formatter.

@paulwalker-arm
Copy link
Collaborator Author

ping


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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would help to make the names a bit more readable if the sve & sme parts of the guard don't appear and are just separated by ___, similar to how the TargetGuards were changed recently?

For example:
arm_sve_feature_dependent_sve_AND_LP_sve2p1_OR_sme2_RP___sme_AND_LP_sve2p1_OR_sme2_RP.c
->
arm_sve_feature_dependent_sve2p1_OR_sme2___sve2p1_OR_sme2.c

Maybe it's not worth the extra complication here, so it's just a suggestion.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that might be more confusing. There are tests that only use sve and/or sme where omitting them would look weird. I could keep them for those cases but then the naming will be inconsistent. There's also the small possibility that we'll have similar tests for the NEON instructions available in streaming mode, where we'll not want the non-streaming case to imply SVE is available.

Adds SEMA tests to verify correct SVE/SME builtin usage based on the
calling function's type (i.e. normal, streaming or streaming compatible).

For invalid uses the tests verify the expected diagnostic is emitted.
This exposed an issue whereby some builtins are incorrectly callable by
streaming compatible functions, which this PR fixes.

The tests are autogenerated based on the builtin definitions (e.g.
arm_sve.td). This is achieved by extending SVEEmitter, which can now
emit a JSON file containing builtin usage information that can be
fed to aarch64_builtins_test_generator.py that is also part of this PR.
svsub_za16_f16_vg1x4(uint32_t_val, svfloat16x4_t_val);
svsub_za16_vg1x2(uint32_t_val, svfloat16x2_t_val);
svsub_za16_vg1x4(uint32_t_val, svfloat16x4_t_val);
}
Copy link
Contributor

@kmclaughlin-arm kmclaughlin-arm Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do tests which shouldn't result in a diagnostic need to be included by the script, since there should already be CodeGen tests elsewhere for all the builtins with the correct features?
(For example, this last builtin is tested in acle_sme2_add_sub_za16.c)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. My plan is to make the Sema tests (that are quick to run) exhaustively test feature flag combinations to ensure correct diagnostic behaviour. Once this is in place I can start reducing the number of RUN lines in the CodeGen tests (that are slow to run) to the minimum required to verify Clang is emitting the correct IR.

Copy link
Contributor

@kmclaughlin-arm kmclaughlin-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for answering my questions @paulwalker-arm, LGTM.

@paulwalker-arm paulwalker-arm merged commit ff9cdbd into llvm:main Oct 8, 2025
9 checks passed
@paulwalker-arm paulwalker-arm deleted the sve-acle-test-refactor branch October 8, 2025 09:58
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 8, 2025

LLVM Buildbot has detected a new failure on builder ppc64le-lld-multistage-test running on ppc64le-lld-multistage-test while building clang at step 13 "test-build-stage2-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/168/builds/16551

Here is the relevant piece of the build log for the reference
Step 13 (test-build-stage2-unified-tree-check-all) failure: 1200 seconds without output running [b'ninja', b'check-all'], attempting to kill
805.965 [1/2/1] Preparing lit tests
command timed out: 1200 seconds without output running [b'ninja', b'check-all'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=2006.850887

svkeerthy pushed a commit that referenced this pull request Oct 9, 2025
Adds SEMA tests to verify correct SVE/SME builtin usage based on the
calling function's type (i.e. normal, streaming or streaming
compatible).

For invalid uses the tests verify the expected diagnostic is emitted.
This exposed an issue whereby some builtins are incorrectly callable by
streaming compatible functions, which this PR fixes.

The tests are autogenerated based on the builtin definitions (e.g.
arm_sve.td). This is achieved by extending SVEEmitter, which can now
emit a JSON file containing builtin usage information that can be fed to
aarch64_builtins_test_generator.py that is also part of this PR.

Everything currently in `clang/test/Sema/AArch64` is the result of:
```
clang/utils/aarch64_builtins_test_generator.py --gen-streaming-guard-tests <LLVM_BUILD_DIR>/tools/clang/include/clang/Basic/arm_sve_builtins.json --out-dir clang/test/Sema/AArch64/
clang/utils/aarch64_builtins_test_generator.py --gen-streaming-guard-tests <LLVM_BUILD_DIR>/tools/clang/include/clang/Basic/arm_sme_builtins.json --out-dir clang/test/Sema/AArch64/
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 backend:ARM clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants