[libcxx-commits] [libcxx] 31fc40b - [clang][X86] Emit AVX level mismatch psABI warnings on function definitions (#199091)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 7 08:17:00 PDT 2026
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 at +2 {{AVX vector return of type 'vec256' (vector of 8 'int' values) without 'avx' enabled changes the ABI}}
+// omp-warning at +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 at +3 {{a function definition without a prototype is deprecated in all versions of C and is not supported in C23}}
+// no256-warning at +2 {{AVX vector return of type 'avx256Type' (vector of 16 'short' values) without 'avx' enabled changes the ABI}}
+// no256-warning at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +2 {{AVX vector return of type 'v8f' (vector of 8 'float' values) without 'avx' enabled changes the ABI}}
+// noavx-warning at +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 at +2 {{AVX vector return of type 'v16f' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}}
+// noavx512-warning at +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
More information about the libcxx-commits
mailing list