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

Reply via email to