Author: Benjamin Luke Date: 2026-07-07T11:16:56-04:00 New Revision: 31fc40b0904861d33b926dfd6ea04432e7690c49
URL: https://github.com/llvm/llvm-project/commit/31fc40b0904861d33b926dfd6ea04432e7690c49 DIFF: https://github.com/llvm/llvm-project/commit/31fc40b0904861d33b926dfd6ea04432e7690c49.diff LOG: [clang][X86] Emit AVX level mismatch psABI warnings on function definitions (#199091) Emit -WpsABI for x86_64 function definitions whose return type or parameter type uses a vector wider than 128 bits without the required ABI feature enabled. 256-bit vectors require avx, and 512-bit vectors require avx512f. Previously this diagnostic was only emitted at call sites, so definitions with wide vector signatures could be introduced without a warning until they were called. Use the function feature map so attribute(target("avx/avx512f")) definitions are accepted, and emit no warnings for prototype-only declarations. Added: clang/test/CodeGen/target-avx-abi-diag-knr.c clang/test/CodeGenCXX/target-avx-abi-diag.cpp Modified: clang/docs/ReleaseNotes.md clang/lib/CodeGen/Targets/X86.cpp clang/test/CodeGen/X86/mmx-inline-asm-error.c clang/test/CodeGen/target-builtin-error-3.c clang/test/CodeGen/target-features-error-2.c libcxx/include/__algorithm/simd_utils.h Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index c7806878a4ff4..0a4bf068c8da4 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -626,6 +626,10 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the - Improved `-Wassign-enum` performance by caching enum enumerator values. (#GH176454) +- Clang now emits `-Wpsabi` diagnostics for externally visible x86-64 + function definitions that return or take AVX or AVX-512 vector types without + enabling the corresponding target feature. + - Fixed a false negative in `-Warray-bounds` where the warning was suppressed when accessing a member function on a past-the-end array element. (#GH179128) diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index 4e99ebab6ba34..807d372c3c8fd 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -9,6 +9,7 @@ #include "ABIInfoImpl.h" #include "TargetInfo.h" #include "clang/Basic/DiagnosticFrontend.h" +#include "clang/Basic/SourceLocation.h" #include "llvm/ADT/SmallBitVector.h" using namespace clang; @@ -1509,6 +1510,9 @@ class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { const FunctionDecl *Caller, const FunctionDecl *Callee, const CallArgList &Args, QualType ReturnType) const override; + + void checkFunctionABI(CodeGenModule &CGM, + const FunctionDecl *FD) const override; }; } // namespace @@ -1571,6 +1575,65 @@ static bool checkAVXParam(DiagnosticsEngine &Diag, ASTContext &Ctx, return false; } +void X86_64TargetCodeGenInfo::checkFunctionABI(CodeGenModule &CGM, + const FunctionDecl *FD) const { + auto GetReturnTypeLoc = [](const FunctionDecl *FD) { + if (const TypeSourceInfo *TSI = FD->getTypeSourceInfo()) { + TypeLoc TL = TSI->getTypeLoc(); + + if (auto FTL = TL.IgnoreParens().getAs<FunctionTypeLoc>()) { + SourceLocation Loc = FTL.getReturnLoc().getBeginLoc(); + if (Loc.isValid()) + return Loc; + } + } + + SourceLocation Loc = FD->getLocation(); + if (Loc.isValid()) + return Loc; + + return FD->getBeginLoc(); + }; + + auto Check = [&](QualType Ty, SourceLocation Loc, bool IsReturn) { + if (!Ty->isVectorType()) + return false; + if (CGM.getContext().getTypeSize(Ty) <= 128) + return false; + + StringRef Feature = + CGM.getContext().getTypeSize(Ty) > 256 ? "avx512f" : "avx"; + + llvm::StringMap<bool> FeatureMap; + CGM.getContext().getFunctionFeatureMap(FeatureMap, FD); + if (!FeatureMap.lookup(Feature)) { + CGM.getDiags().Report(Loc, diag::warn_avx_calling_convention) + << !IsReturn << Ty << Feature; + return true; + } + + return false; + }; + + // psABI warnings & errors for function definitions that are only visible + // in this translation unit are handled at call site by checkFunctionCallABI. + if (!FD->isExternallyVisible()) + return; + + // First check the return type and emit diagnostic if required. + Check(FD->getReturnType(), GetReturnTypeLoc(FD), true); + + // Go through the parameters and emit a warning for the first vector found + // without the matching function AVX level attribute. + for (const ParmVarDecl *P : FD->parameters()) { + SourceLocation Loc = P->getLocation(); + if (Loc.isInvalid()) + Loc = P->getBeginLoc(); + if (Check(P->getType(), Loc, false)) + return; + } +} + void X86_64TargetCodeGenInfo::checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller, diff --git a/clang/test/CodeGen/X86/mmx-inline-asm-error.c b/clang/test/CodeGen/X86/mmx-inline-asm-error.c index 8a2f991a537a2..7f7f53a553057 100644 --- a/clang/test/CodeGen/X86/mmx-inline-asm-error.c +++ b/clang/test/CodeGen/X86/mmx-inline-asm-error.c @@ -2,6 +2,8 @@ // RUN: %clang_cc1 -verify=omp -triple x86_64-unknown-unknown -emit-llvm-only -fopenmp %s typedef int vec256 __attribute__((ext_vector_type(8))); +// omp-warning@+2 {{AVX vector return of type 'vec256' (vector of 8 'int' values) without 'avx' enabled changes the ABI}} +// omp-warning@+1 {{AVX vector argument of type 'vec256' (vector of 8 'int' values) without 'avx' enabled changes the ABI}} vec256 foo(vec256 in) { vec256 out; diff --git a/clang/test/CodeGen/target-avx-abi-diag-knr.c b/clang/test/CodeGen/target-avx-abi-diag-knr.c new file mode 100644 index 0000000000000..c9fca7d39e042 --- /dev/null +++ b/clang/test/CodeGen/target-avx-abi-diag-knr.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -std=c17 -verify=no256,knr -o - -S +// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -std=c17 -target-feature +avx -verify=knr -o - -S +// REQUIRES: x86-registered-target + +typedef short avx256Type __attribute__((vector_size(32))); + +// knr-warning@+3 {{a function definition without a prototype is deprecated in all versions of C and is not supported in C23}} +// no256-warning@+2 {{AVX vector return of type 'avx256Type' (vector of 16 'short' values) without 'avx' enabled changes the ABI}} +// no256-warning@+2 {{AVX vector argument of type 'avx256Type' (vector of 16 'short' values) without 'avx' enabled changes the ABI}} +avx256Type knr_def(x) + avx256Type x; +{ + return x; +} diff --git a/clang/test/CodeGen/target-builtin-error-3.c b/clang/test/CodeGen/target-builtin-error-3.c index 056dc940f7a93..75754f40ac44d 100644 --- a/clang/test/CodeGen/target-builtin-error-3.c +++ b/clang/test/CodeGen/target-builtin-error-3.c @@ -17,32 +17,38 @@ typedef __attribute__ ((ext_vector_type(16),__aligned__( 64))) float float16; static inline half8 __attribute__((__overloadable__)) convert_half( float8 a ) { return __extension__ ({ __m256 __a = (a); (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (0x00)); }); // expected-error {{'__builtin_ia32_vcvtps2ph256' needs target feature f16c}} } +// Internal definitions do not warn. static inline half16 __attribute__((__overloadable__)) convert_half( float16 a ) { half16 r; r.lo = convert_half(a.lo); return r; } +// expected-warning@+1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} void avx_test( uint16_t *destData, float16 argbF) { ((half16U *)destData)[0] = convert_half(argbF); } +// expected-warning@+1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} half16 test( float16 a ) { half16 r; r.lo = convert_half(a.lo); return r; } +// expected-warning@+1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} void avx_test2( uint16_t *destData, float16 argbF) { // expected-warning@+1{{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} ((half16U *)destData)[0] = test(argbF); } +// expected-warning@+1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} __attribute__((always_inline)) half16 test2( float16 a ) { half16 r; r.lo = convert_half(a.lo); return r; } +// expected-warning@+1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} void avx_test3( uint16_t *destData, float16 argbF) { ((half16U *)destData)[0] = test2(argbF); diff --git a/clang/test/CodeGen/target-features-error-2.c b/clang/test/CodeGen/target-features-error-2.c index 1599b0135b747..8f2ef35b8a931 100644 --- a/clang/test/CodeGen/target-features-error-2.c +++ b/clang/test/CodeGen/target-features-error-2.c @@ -8,6 +8,7 @@ #include <x86intrin.h> #if NEED_AVX_1 +// expected-warning@+1 {{AVX vector argument of type '__m256i' (vector of 4 'long long' values) without 'avx' enabled changes the ABI}} int baz(__m256i a) { return _mm256_extract_epi32(a, 3); // expected-error {{'__builtin_ia32_vec_ext_v8si' needs target feature avx}} } diff --git a/clang/test/CodeGenCXX/target-avx-abi-diag.cpp b/clang/test/CodeGenCXX/target-avx-abi-diag.cpp new file mode 100644 index 0000000000000..66312d513058e --- /dev/null +++ b/clang/test/CodeGenCXX/target-avx-abi-diag.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm -disable-llvm-passes -verify=noavx,noavx512 -o - %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -target-feature +avx -emit-llvm -disable-llvm-passes -verify=noavx512 -o - %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -target-feature +avx512f -emit-llvm -disable-llvm-passes -verify=both -o - %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -Wno-psabi -emit-llvm -disable-llvm-passes -verify=suppressed -o - %s +// REQUIRES: x86-registered-target + +// both-no-diagnostics +// suppressed-no-diagnostics + +typedef float v8f __attribute__((vector_size(32))); +typedef float v16f __attribute__((vector_size(64))); + +// Prototype-only declarations do not warn. +v8f proto256(v8f); +v16f proto512(v16f); + +// noavx-warning@+2 {{AVX vector return of type 'v8f' (vector of 8 'float' values) without 'avx' enabled changes the ABI}} +// noavx-warning@+1 {{AVX vector argument of type 'v8f' (vector of 8 'float' values) without 'avx' enabled changes the ABI}} +v8f def256(v8f x) { + return x; +} + +// noavx512-warning@+2 {{AVX vector return of type 'v16f' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} +// noavx512-warning@+1 {{AVX vector argument of type 'v16f' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}} +v16f def512(v16f x) { + return x; +} + +// Internal definitions do not warn +static v8f internal_def256(v8f x) { + return x; +} + +__attribute__((target("avx"))) +v8f def256_avx(v8f x) { + return x; +} + +__attribute__((target("avx512f"))) +v16f def512_avx512(v16f x) { + return x; +} + +// Check to make sure deduced return lambdas still have valid source location which allows these pragmas to work +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpsabi" +template <class T> +T template_lambda_return() { + return []() { return T{}; }(); +} + +v8f use_template_lambda_return() { + return template_lambda_return<v8f>(); +} +#pragma clang diagnostic pop diff --git a/libcxx/include/__algorithm/simd_utils.h b/libcxx/include/__algorithm/simd_utils.h index c47f79ac7f1dd..495aed4e21216 100644 --- a/libcxx/include/__algorithm/simd_utils.h +++ b/libcxx/include/__algorithm/simd_utils.h @@ -90,6 +90,9 @@ inline constexpr size_t __native_vector_size = 1; template <class _ArithmeticT, size_t _Np> using __simd_vector __attribute__((__ext_vector_type__(_Np))) _LIBCPP_NODEBUG = _ArithmeticT; +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi") + template <class _VecT> inline constexpr size_t __simd_vector_size_v = []<bool _False = false>() -> size_t { static_assert(_False, "Not a vector!"); @@ -115,8 +118,6 @@ template <class _VecT, class _Iter> } // Load the first _Np elements, zero the rest -_LIBCPP_DIAGNOSTIC_PUSH -_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi") template <class _VecT, size_t _Np, class _Iter> [[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT __partial_load(_Iter __iter) noexcept { return [=]<size_t... _LoadIndices, size_t... _ZeroIndices>( @@ -124,7 +125,6 @@ template <class _VecT, size_t _Np, class _Iter> return _VecT{__iter[_LoadIndices]..., ((void)_ZeroIndices, 0)...}; }(make_index_sequence<_Np>{}, make_index_sequence<__simd_vector_size_v<_VecT> - _Np>{}); } -_LIBCPP_DIAGNOSTIC_POP template <class _Tp, size_t _Np> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __any_of(__simd_vector<_Tp, _Np> __vec) noexcept { @@ -174,6 +174,7 @@ template <class _Tp, size_t _Np> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t __find_first_not_set(__simd_vector<_Tp, _Np> __vec) noexcept { return std::__find_first_set(~__vec); } +_LIBCPP_DIAGNOSTIC_POP _LIBCPP_END_NAMESPACE_STD _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
