https://github.com/CarolineConcatto updated https://github.com/llvm/llvm-project/pull/227722
>From 49658d14e1bbee471e40813da9c201220bc4b5c6 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 | 34 +++++++++++ clang/lib/Sema/SemaARM.cpp | 30 +++++++++- clang/test/CodeGen/AArch64/fpm-helpers.c | 45 +++++++++++++- clang/test/Sema/aarch64-fpm-helpers.c | 63 ++++++++++++++++++++ clang/utils/TableGen/NeonEmitter.cpp | 17 +----- 7 files changed, 178 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 73a8e387cc4cb35..6b564f168f38bb8 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 30aa3d526cbbb73..bd579d90b46467e 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 52a7564789fb770..a1ae8fb58c99b5b 100644 --- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp @@ -4922,6 +4922,40 @@ 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()); + Scale = Builder.CreateAnd(Scale, Builder.getInt64(0x7f)); + + 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 *Scale = EmitScalarExpr(E->getArg(1)); + Scale = Builder.CreateZExtOrTrunc(Scale, FPM->getType()); + Scale = Builder.CreateAnd(Scale, Builder.getInt64(0x3f)); + + Value *ShiftedScale = Builder.CreateShl(Scale, Builder.getInt64(32)); + Value *LowFPM = Builder.CreateAnd(FPM, Builder.getInt64(0xffffffffULL)); + + 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 2bf6901bcc07f23..1310bb80908febb 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 6264b5caeb4f50d..3737b03ffcc382c 100644 --- a/clang/test/CodeGen/AArch64/fpm-helpers.c +++ b/clang/test/CodeGen/AArch64/fpm-helpers.c @@ -132,6 +132,19 @@ fpm_t test_of_cvt_2() { // fpm_t test_lscale() { return __arm_set_fpm_lscale(INIT_ZERO, 127); } +// CHECK-LABEL: define dso_local i64 @test_lscale_variable( +// CHECK-SAME: i64 noundef [[FPM:%.*]], i64 noundef [[SCALE:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = and i64 [[FPM]], -8323073 +// CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[SCALE]], 16 +// CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 8323072 +// CHECK-NEXT: [[TMP3:%.*]] = or disjoint i64 [[TMP2]], [[TMP0]] +// CHECK-NEXT: ret i64 [[TMP3]] +// +fpm_t test_lscale_variable(fpm_t fpm, uint64_t scale) { + return __arm_set_fpm_lscale(fpm, scale); +} + // CHECK-LABEL: define dso_local noundef i64 @test_lscale2( // CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] @@ -139,27 +152,53 @@ 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 range(i64 0, 274877906944) i64 @test_lscale2_variable( +// CHECK-SAME: i64 noundef [[FPM:%.*]], i64 noundef [[SCALE:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = shl i64 [[SCALE]], 32 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 270582939648 +// CHECK-NEXT: [[TMP2:%.*]] = and i64 [[FPM]], 4294967295 +// CHECK-NEXT: [[TMP3:%.*]] = or disjoint i64 [[TMP1]], [[TMP2]] +// CHECK-NEXT: ret i64 [[TMP3]] +// +fpm_t test_lscale2_variable(fpm_t fpm, uint64_t scale) { + return __arm_set_fpm_lscale2(fpm, scale); +} + +// 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 // fpm_t test_nscale_3() { return __arm_set_fpm_nscale(INIT_ZERO, -1); } +// CHECK-LABEL: define dso_local i64 @test_nscale_variable( +// CHECK-SAME: i64 noundef [[FPM:%.*]], i64 noundef [[SCALE:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = and i64 [[FPM]], -4278190081 +// CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[SCALE]], 24 +// CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 4278190080 +// CHECK-NEXT: [[TMP3:%.*]] = or disjoint i64 [[TMP2]], [[TMP0]] +// CHECK-NEXT: ret i64 [[TMP3]] +// +fpm_t test_nscale_variable(fpm_t fpm, int64_t scale) { + return __arm_set_fpm_nscale(fpm, scale); +} + #ifdef __cplusplus } #endif diff --git a/clang/test/Sema/aarch64-fpm-helpers.c b/clang/test/Sema/aarch64-fpm-helpers.c new file mode 100644 index 000000000000000..d1f38efc7a17446 --- /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 6c90b55dbf648b5..e567a27032d129b 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
