https://github.com/CarolineConcatto updated 
https://github.com/llvm/llvm-project/pull/227722

>From 60354a0ecab4cd3c2a8b8226e7fcaea6d434b76a Mon Sep 17 00:00:00 2001
From: CarolineConcatto <[email protected]>
Date: Wed, 30 Sep 2026 08:44:34 +0000
Subject: [PATCH] [Clang][AArch64] Diagnose invalid FPM scale arguments

Add builtins for the FPM scale helpers and diagnose constant
arguments outside their valid ranges.
---
 clang/include/clang/Basic/BuiltinHeaders.def |  1 +
 clang/include/clang/Basic/BuiltinsAArch64.td |  6 ++
 clang/lib/CodeGen/TargetBuiltins/ARM.cpp     | 33 ++++++++++
 clang/lib/Sema/SemaARM.cpp                   | 30 +++++++++-
 clang/test/CodeGen/AArch64/fpm-helpers.c     |  6 +-
 clang/test/Sema/aarch64-fpm-helpers.c        | 63 ++++++++++++++++++++
 clang/utils/TableGen/NeonEmitter.cpp         | 17 +-----
 7 files changed, 138 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/Sema/aarch64-fpm-helpers.c

diff --git a/clang/include/clang/Basic/BuiltinHeaders.def 
b/clang/include/clang/Basic/BuiltinHeaders.def
index 73a8e387cc4cb..6b564f168f38b 100644
--- a/clang/include/clang/Basic/BuiltinHeaders.def
+++ b/clang/include/clang/Basic/BuiltinHeaders.def
@@ -13,6 +13,7 @@
 
 HEADER(NO_HEADER, nullptr)
 HEADER(ARM_ACLE_H, "arm_acle.h")
+HEADER(ARM_VECTOR_TYPES_H, "arm_vector_types.h")
 HEADER(BLOCKS_H, "Blocks.h")
 HEADER(COMPLEX_H, "complex.h")
 HEADER(CTYPE_H, "ctype.h")
diff --git a/clang/include/clang/Basic/BuiltinsAArch64.td 
b/clang/include/clang/Basic/BuiltinsAArch64.td
index 30aa3d526cbbb..bd579d90b4646 100644
--- a/clang/include/clang/Basic/BuiltinsAArch64.td
+++ b/clang/include/clang/Basic/BuiltinsAArch64.td
@@ -48,6 +48,12 @@ def sev     : AArch64Builtin<"void ()">;
 def sevl    : AArch64Builtin<"void ()">;
 def chkfeat : AArch64Builtin<"uint64_t (uint64_t)">;
 
+let Attributes = [NoThrow, RequireDeclaration], Header = "arm_vector_types.h" 
in {
+        def __arm_set_fpm_lscale : AArch64NoPrefixTargetLibBuiltin<"uint64_t 
(uint64_t, uint64_t)">;
+        def __arm_set_fpm_nscale   : AArch64NoPrefixTargetLibBuiltin<"uint64_t 
(uint64_t, int64_t)">;
+        def __arm_set_fpm_lscale2   : 
AArch64NoPrefixTargetLibBuiltin<"uint64_t (uint64_t, uint64_t)">;
+}
+
 let Attributes = [RequireDeclaration], Languages = "ALL_LANGUAGES", Header = 
"arm_acle.h" in {
        def __yield : AArch64NoPrefixTargetLibBuiltin<"void ()">;
        def __wfe   : AArch64NoPrefixTargetLibBuiltin<"void ()">;
diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp 
b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index 52a7564789fb7..9ea1c85b871af 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -4922,6 +4922,39 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned 
BuiltinID,
     MTEIntrinsicID = Intrinsic::aarch64_subp; break;
   }
 
+  if (BuiltinID == clang::AArch64::BI__arm_set_fpm_lscale) {
+    Value *FPM = EmitScalarExpr(E->getArg(0));
+    Value *Scale = EmitScalarExpr(E->getArg(1));
+
+    Scale = Builder.CreateZExtOrTrunc(Scale, FPM->getType());
+    Value *MaskedFPM = Builder.CreateAnd(FPM, Builder.getInt64(~0x7f0000ULL));
+    Value *ShiftedScale = Builder.CreateShl(Scale, Builder.getInt64(16));
+
+    return Builder.CreateOr(MaskedFPM, ShiftedScale);
+  }
+  if (BuiltinID == clang::AArch64::BI__arm_set_fpm_nscale) {
+    Value *FPM = EmitScalarExpr(E->getArg(0));
+    Value *Scale = EmitScalarExpr(E->getArg(1));
+
+    Scale = Builder.CreateZExtOrTrunc(Scale, FPM->getType());
+    Scale = Builder.CreateAnd(Scale, Builder.getInt64(0xff));
+
+    Value *MaskedFPM = Builder.CreateAnd(FPM, 
Builder.getInt64(~0xff000000ULL));
+    Value *ShiftedScale = Builder.CreateShl(Scale, Builder.getInt64(24));
+
+    return Builder.CreateOr(MaskedFPM, ShiftedScale);
+  }
+  if (BuiltinID == clang::AArch64::BI__arm_set_fpm_lscale2) {
+    Value *FPM = EmitScalarExpr(E->getArg(0));
+    Value *LowFPM = Builder.CreateAnd(FPM, Builder.getInt64(0xffffffff));
+    Value *Scale = EmitScalarExpr(E->getArg(1));
+
+    Scale = Builder.CreateZExtOrTrunc(Scale, FPM->getType());
+    Value *ShiftedScale = Builder.CreateShl(Scale, Builder.getInt64(32));
+
+    return Builder.CreateOr(LowFPM, ShiftedScale);
+  }
+
   if (MTEIntrinsicID != Intrinsic::not_intrinsic) {
     if (MTEIntrinsicID == Intrinsic::aarch64_irg) {
       Value *Pointer = EmitScalarExpr(E->getArg(0));
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index 2bf6901bcc07f..1310bb80908fe 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1156,6 +1156,26 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(const 
TargetInfo &TI,
   return false;
 }
 
+static bool checkFPMScaleIfConstant(Sema &S, CallExpr *Call, unsigned ArgNum,
+                                    int64_t Low, int64_t High) {
+  Expr *Arg = Call->getArg(ArgNum);
+
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(S.Context);
+
+  // Runtime value: accept it.
+  if (!Value)
+    return false;
+
+  if (*Value < Low || *Value > High)
+    return S.Diag(Call->getBeginLoc(), diag::warn_argument_invalid_range)
+           << toString(*Value, 10) << Low << High << Arg->getSourceRange();
+
+  return false;
+}
+
 bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI,
                                           unsigned BuiltinID,
                                           CallExpr *TheCall) {
@@ -1189,7 +1209,6 @@ bool SemaARM::CheckARMBuiltinFunctionCall(const 
TargetInfo &TI,
     return true;
   if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))
     return true;
-
   // For intrinsics which take an immediate value as part of the instruction,
   // range check them here.
   // FIXME: VFP Intrinsics should error if VFP not present.
@@ -1345,6 +1364,15 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const 
TargetInfo &TI,
   if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))
     return true;
 
+  if (BuiltinID == AArch64::BI__arm_set_fpm_lscale)
+    return checkFPMScaleIfConstant(SemaRef, TheCall, 1, 0, 127);
+
+  if (BuiltinID == AArch64::BI__arm_set_fpm_nscale)
+    return checkFPMScaleIfConstant(SemaRef, TheCall, 1, -128, 127);
+
+  if (BuiltinID == AArch64::BI__arm_set_fpm_lscale2)
+    return checkFPMScaleIfConstant(SemaRef, TheCall, 1, 0, 63);
+
   // For intrinsics which take an immediate value as part of the instruction,
   // range check them here.
   unsigned i = 0, l = 0, u = 0;
diff --git a/clang/test/CodeGen/AArch64/fpm-helpers.c 
b/clang/test/CodeGen/AArch64/fpm-helpers.c
index 6264b5caeb4f5..f2e84bcd378c5 100644
--- a/clang/test/CodeGen/AArch64/fpm-helpers.c
+++ b/clang/test/CodeGen/AArch64/fpm-helpers.c
@@ -139,21 +139,21 @@ fpm_t test_lscale() { return 
__arm_set_fpm_lscale(INIT_ZERO, 127); }
 //
 fpm_t test_lscale2() { return __arm_set_fpm_lscale2(INIT_ZERO, 63); }
 
-// CHECK-LABEL: define dso_local noundef range(i64 0, 4278190081) i64 
@test_nscale_1(
+// CHECK-LABEL: define dso_local noundef i64 @test_nscale_1(
 // CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    ret i64 2147483648
 //
 fpm_t test_nscale_1() { return __arm_set_fpm_nscale(INIT_ZERO, -128); }
 
-// CHECK-LABEL: define dso_local noundef range(i64 0, 4278190081) i64 
@test_nscale_2(
+// CHECK-LABEL: define dso_local noundef i64 @test_nscale_2(
 // CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    ret i64 2130706432
 //
 fpm_t test_nscale_2() { return __arm_set_fpm_nscale(INIT_ZERO, 127); }
 
-// CHECK-LABEL: define dso_local noundef range(i64 0, 4278190081) i64 
@test_nscale_3(
+// CHECK-LABEL: define dso_local noundef i64 @test_nscale_3(
 // CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    ret i64 4278190080
diff --git a/clang/test/Sema/aarch64-fpm-helpers.c 
b/clang/test/Sema/aarch64-fpm-helpers.c
new file mode 100644
index 0000000000000..d1f38efc7a174
--- /dev/null
+++ b/clang/test/Sema/aarch64-fpm-helpers.c
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple aarch64 -fsyntax-only -verify -DUSE_NEON_H %s
+// RUN: %clang_cc1 -triple aarch64 -fsyntax-only -verify -DUSE_SVE_H %s
+// RUN: %clang_cc1 -triple aarch64 -fsyntax-only -verify -DUSE_SME_H %s
+// RUN: %clang_cc1 -triple aarch64 -x c++ -fsyntax-only -verify -DUSE_NEON_H %s
+// RUN: %clang_cc1 -triple aarch64 -x c++ -fsyntax-only -verify -DUSE_SVE_H %s
+// RUN: %clang_cc1 -triple aarch64 -x c++ -fsyntax-only -verify -DUSE_SME_H %s
+
+// REQUIRES: aarch64-registered-target
+
+#ifdef USE_NEON_H
+#include "arm_neon.h"
+#endif
+
+#ifdef USE_SVE_H
+#include "arm_sve.h"
+#endif
+
+#ifdef USE_SME_H
+#include "arm_sme.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test_lscale(fpm_t fpm, uint64_t variable) {
+  __arm_set_fpm_lscale(fpm, 0);
+  __arm_set_fpm_lscale(fpm, 127);
+  __arm_set_fpm_lscale(fpm, variable);
+
+  __arm_set_fpm_lscale(fpm, 128);
+  // expected-error@-1 {{argument value 128 is outside the valid range [0, 
127]}}
+
+  __arm_set_fpm_lscale(fpm, -1);
+  // expected-error@-1 {{argument value 18446744073709551615 is outside the 
valid range [0, 127]}}
+}
+
+void test_nscale(fpm_t fpm, int64_t variable) {
+  __arm_set_fpm_nscale(fpm, -128);
+  __arm_set_fpm_nscale(fpm, 127);
+  __arm_set_fpm_nscale(fpm, variable);
+
+  __arm_set_fpm_nscale(fpm, -129);
+  // expected-error@-1 {{argument value -129 is outside the valid range [-128, 
127]}}
+
+  __arm_set_fpm_nscale(fpm, 128);
+  // expected-error@-1 {{argument value 128 is outside the valid range [-128, 
127]}}
+}
+
+void test_lscale2(fpm_t fpm, uint64_t variable) {
+  __arm_set_fpm_lscale2(fpm, 0);
+  __arm_set_fpm_lscale2(fpm, 63);
+  __arm_set_fpm_lscale2(fpm, variable);
+
+  __arm_set_fpm_lscale2(fpm, 64);
+  // expected-error@-1 {{argument value 64 is outside the valid range [0, 63]}}
+
+  __arm_set_fpm_lscale2(fpm, -1);
+  // expected-error@-1 {{argument value 18446744073709551615 is outside the 
valid range [0, 63]}}
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/clang/utils/TableGen/NeonEmitter.cpp 
b/clang/utils/TableGen/NeonEmitter.cpp
index 6c90b55dbf648..e567a27032d12 100644
--- a/clang/utils/TableGen/NeonEmitter.cpp
+++ b/clang/utils/TableGen/NeonEmitter.cpp
@@ -2694,20 +2694,9 @@ __arm_set_fpm_overflow_cvt(fpm_t __fpm, enum 
__ARM_FPM_OVERFLOW __behaviour) {
   return (__fpm & ~0x8000ull) | ((fpm_t)__behaviour << 15u);
 }
 
-static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__))
-__arm_set_fpm_lscale(fpm_t __fpm, uint64_t __scale) {
-  return (__fpm & ~0x7f0000ull) | (__scale << 16u);
-}
-
-static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__))
-__arm_set_fpm_nscale(fpm_t __fpm, int64_t __scale) {
-  return (__fpm & ~0xff000000ull) | (((fpm_t)__scale & 0xffu) << 24u);
-}
-
-static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__))
-__arm_set_fpm_lscale2(fpm_t __fpm, uint64_t __scale) {
-  return (uint32_t)__fpm | (__scale << 32u);
-}
+__inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) 
__arm_set_fpm_lscale(fpm_t __fpm, uint64_t __scale);
+__inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) 
__arm_set_fpm_nscale(fpm_t __fpm, int64_t __scale);
+__inline__ fpm_t __attribute__((__always_inline__, __nodebug__))  
__arm_set_fpm_lscale2(fpm_t __fpm, uint64_t __scale);
 
 )";
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to