https://github.com/ckoparkar updated https://github.com/llvm/llvm-project/pull/155620
>From 131965becbc06c875557a51d48113d52df365f87 Mon Sep 17 00:00:00 2001 From: Chaitanya Koparkar <ckopar...@gmail.com> Date: Wed, 27 Aug 2025 07:56:44 -0400 Subject: [PATCH 1/5] [clang] Update typechecking of builtin elementwise ternary math operators For scalars we directly compare their unqualified types. But even if we compare unqualified vector types, a difference in qualifiers in the element types can make the vector types be considered not equal. For example, vector of 4 'const float' values vs vector of 4 'float' values. So we compare unqualified types of their elements and number of elements. --- clang/lib/Sema/SemaChecking.cpp | 69 +++++++++++++++++---- clang/test/Sema/builtins-elementwise-math.c | 21 ++++++- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 908ac31c6ac98..8ce308fd120e8 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15884,6 +15884,58 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS, return false; } +/// Check if all arguments have the same type. If the types don't match, emit an +/// error message and return true. Otherwise return false. +/// +/// For scalars we directly compare their unqualified types. But even if we +/// compare unqualified vector types, a difference in qualifiers in the element +/// types can make the vector types be considered not equal. For example, +/// vector of 4 'const float' values vs vector of 4 'float' values. +/// So we compare unqualified types of their elements and number of elements. +/// See GitHub issue #155405. +static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, unsigned NumArgs, + Expr *Args[]) { + assert(NumArgs > 0 && "Should have at least one argument."); + + auto EmitError = [&](int I) { + SemaRef.Diag(Args[0]->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << Args[0]->getType() << Args[I]->getType(); + }; + + QualType Ty0 = Args[0]->getType(); + + // Compare scalar types. + if (!Ty0->isVectorType()) { + for (unsigned I = 1; I < NumArgs; ++I) + if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, Args[I]->getType())) { + EmitError(I); + return true; + } + + return false; + } + + // Compare vector types. + const auto *Vec0 = Ty0->castAs<VectorType>(); + for (unsigned I = 1; I < NumArgs; ++I) { + QualType TyI = Args[I]->getType(); + if (!TyI->isVectorType()) { + EmitError(I); + return true; + } + const auto *VecI = TyI->castAs<VectorType>(); + if (!SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(), + VecI->getElementType()) || + Vec0->getNumElements() != VecI->getNumElements()) { + EmitError(I); + return true; + } + } + + return false; +} + std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) { @@ -15905,13 +15957,11 @@ Sema::BuiltinVectorMath(CallExpr *TheCall, SourceLocation LocA = Args[0]->getBeginLoc(); QualType TyA = Args[0]->getType(); - QualType TyB = Args[1]->getType(); if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1)) return std::nullopt; - if (!Context.hasSameUnqualifiedType(TyA, TyB)) { - Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB; + if (checkBuiltinVectorMathArgTypes(*this, 2, Args)) { return std::nullopt; } @@ -15948,17 +15998,12 @@ bool Sema::BuiltinElementwiseTernaryMath( return true; } - TheCall->setArg(0, Args[0]); - for (int I = 1; I < 3; ++I) { - if (Args[0]->getType().getCanonicalType() != - Args[I]->getType().getCanonicalType()) { - return Diag(Args[0]->getBeginLoc(), - diag::err_typecheck_call_different_arg_types) - << Args[0]->getType() << Args[I]->getType(); - } + if (checkBuiltinVectorMathArgTypes(*this, 3, Args)) { + return true; + } + for (int I = 0; I < 3; ++I) TheCall->setArg(I, Args[I]); - } TheCall->setType(Args[0]->getType()); return false; diff --git a/clang/test/Sema/builtins-elementwise-math.c b/clang/test/Sema/builtins-elementwise-math.c index 02dd44211e96a..d6ce5c0a34746 100644 --- a/clang/test/Sema/builtins-elementwise-math.c +++ b/clang/test/Sema/builtins-elementwise-math.c @@ -5,6 +5,7 @@ typedef double double4 __attribute__((ext_vector_type(4))); typedef float float2 __attribute__((ext_vector_type(2))); typedef float float3 __attribute__((ext_vector_type(3))); typedef float float4 __attribute__((ext_vector_type(4))); +typedef const float cfloat4 __attribute__((ext_vector_type(4))); typedef int int2 __attribute__((ext_vector_type(2))); typedef int int3 __attribute__((ext_vector_type(3))); @@ -1330,16 +1331,32 @@ void test_builtin_elementwise_fsh(int i32, int2 v2i32, short i16, int3 v3i32, // expected-error@-1 {{arguments are of different types ('int3' (vector of 3 'int' values) vs 'int2' (vector of 2 'int' values))}} } +// Tests corresponding to GitHub issues #141397 and #155405. +// Type mismatch error when 'builtin-elementwise-math' arguments have +// different qualifiers, this should be well-formed. typedef struct { float3 b; } struct_float3; -// This example uncovered a bug #141397 : -// Type mismatch error when 'builtin-elementwise-math' arguments have different qualifiers, this should be well-formed + float3 foo(float3 a,const struct_float3* hi) { float3 b = __builtin_elementwise_max((float3)(0.0f), a); return __builtin_elementwise_pow(b, hi->b.yyy); } +float3 baz(float3 a, const struct_float3* hi) { + return __builtin_elementwise_fma(a, a, hi->b); +} + +cfloat4 qux(cfloat4 x, float4 y, float4 z) { + float a = __builtin_elementwise_fma(x[0],y[0],z[0]); + return __builtin_elementwise_fma(x,y,z); +} + +cfloat4 quux(cfloat4 x, float4 y) { + float a = __builtin_elementwise_pow(x[0],y[0]); + return __builtin_elementwise_pow(x,y); +} + void test_builtin_elementwise_ctlz(int i32, int2 v2i32, short i16, double f64, double2 v2f64) { f64 = __builtin_elementwise_ctlz(f64); >From 24e3abf6a65ce56efc1e15a8e3dd8d9d425e5179 Mon Sep 17 00:00:00 2001 From: Chaitanya Koparkar <ckopar...@gmail.com> Date: Wed, 27 Aug 2025 10:47:04 -0400 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Yanzuo Liu <zw...@outlook.com> Co-authored-by: Timm Baeder <tbae...@redhat.com> --- clang/lib/Sema/SemaChecking.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8ce308fd120e8..503f8ad668309 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15894,10 +15894,10 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS, /// So we compare unqualified types of their elements and number of elements. /// See GitHub issue #155405. static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, unsigned NumArgs, - Expr *Args[]) { + ArrayRef<Expr *> Args) { assert(NumArgs > 0 && "Should have at least one argument."); - auto EmitError = [&](int I) { + auto EmitError = [&](unsigned I) { SemaRef.Diag(Args[0]->getBeginLoc(), diag::err_typecheck_call_different_arg_types) << Args[0]->getType() << Args[I]->getType(); @@ -15907,7 +15907,7 @@ static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, unsigned NumArgs, // Compare scalar types. if (!Ty0->isVectorType()) { - for (unsigned I = 1; I < NumArgs; ++I) + for (unsigned I = 1; I != NumArgs; ++I) if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, Args[I]->getType())) { EmitError(I); return true; @@ -15918,7 +15918,7 @@ static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, unsigned NumArgs, // Compare vector types. const auto *Vec0 = Ty0->castAs<VectorType>(); - for (unsigned I = 1; I < NumArgs; ++I) { + for (unsigned I = 1; I != NumArgs; ++I) { QualType TyI = Args[I]->getType(); if (!TyI->isVectorType()) { EmitError(I); >From d01721df42b0e358a096c19bb3e228ed7521555b Mon Sep 17 00:00:00 2001 From: Chaitanya Koparkar <ckopar...@gmail.com> Date: Thu, 28 Aug 2025 07:37:21 -0400 Subject: [PATCH 3/5] Release notes and better use of ArrayRef --- clang/docs/ReleaseNotes.rst | 4 ++++ clang/lib/Sema/SemaChecking.cpp | 41 +++++++++++++++------------------ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 67178de6efcff..f7eb6376829da 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -179,6 +179,10 @@ Non-comprehensive list of changes in this release Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base specifiers, it also must be used within a template context. +- Builtin elementwise operators now accept vector arguments that have different + qualifiers on their elements. For example, vector of 4 ``const float`` values + and vector of 4 ``float`` values. + New Compiler Flags ------------------ diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 503f8ad668309..4fdbab636019a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15893,23 +15893,24 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS, /// vector of 4 'const float' values vs vector of 4 'float' values. /// So we compare unqualified types of their elements and number of elements. /// See GitHub issue #155405. -static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, unsigned NumArgs, +static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, ArrayRef<Expr *> Args) { - assert(NumArgs > 0 && "Should have at least one argument."); + assert(Args.size() > 0 && "Should have at least one argument."); - auto EmitError = [&](unsigned I) { - SemaRef.Diag(Args[0]->getBeginLoc(), + Expr *Arg0 = Args.front(); + QualType Ty0 = Arg0->getType(); + + auto EmitError = [&](Expr *ArgI) { + SemaRef.Diag(Arg0->getBeginLoc(), diag::err_typecheck_call_different_arg_types) - << Args[0]->getType() << Args[I]->getType(); + << Arg0->getType() << ArgI->getType(); }; - QualType Ty0 = Args[0]->getType(); - // Compare scalar types. if (!Ty0->isVectorType()) { - for (unsigned I = 1; I != NumArgs; ++I) - if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, Args[I]->getType())) { - EmitError(I); + for (Expr *ArgI : Args.drop_front()) + if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) { + EmitError(ArgI); return true; } @@ -15918,17 +15919,13 @@ static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, unsigned NumArgs, // Compare vector types. const auto *Vec0 = Ty0->castAs<VectorType>(); - for (unsigned I = 1; I != NumArgs; ++I) { - QualType TyI = Args[I]->getType(); - if (!TyI->isVectorType()) { - EmitError(I); - return true; - } - const auto *VecI = TyI->castAs<VectorType>(); - if (!SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(), + for (Expr *ArgI : Args.drop_front()) { + const auto *VecI = ArgI->getType()->getAs<VectorType>(); + if (!VecI || + !SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(), VecI->getElementType()) || Vec0->getNumElements() != VecI->getNumElements()) { - EmitError(I); + EmitError(ArgI); return true; } } @@ -15961,9 +15958,8 @@ Sema::BuiltinVectorMath(CallExpr *TheCall, if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1)) return std::nullopt; - if (checkBuiltinVectorMathArgTypes(*this, 2, Args)) { + if (checkBuiltinVectorMathArgTypes(*this, Args)) return std::nullopt; - } TheCall->setArg(0, Args[0]); TheCall->setArg(1, Args[1]); @@ -15998,9 +15994,8 @@ bool Sema::BuiltinElementwiseTernaryMath( return true; } - if (checkBuiltinVectorMathArgTypes(*this, 3, Args)) { + if (checkBuiltinVectorMathArgTypes(*this, Args)) return true; - } for (int I = 0; I < 3; ++I) TheCall->setArg(I, Args[I]); >From 8511b0353c3eb4f3da87f9db34550185c835fee7 Mon Sep 17 00:00:00 2001 From: Chaitanya Koparkar <ckopar...@gmail.com> Date: Thu, 28 Aug 2025 09:39:42 -0400 Subject: [PATCH 4/5] Update clang/lib/Sema/SemaChecking.cpp Co-authored-by: Timm Baeder <tbae...@redhat.com> --- clang/lib/Sema/SemaChecking.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4fdbab636019a..080d4a79f30ba 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15895,7 +15895,7 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS, /// See GitHub issue #155405. static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, ArrayRef<Expr *> Args) { - assert(Args.size() > 0 && "Should have at least one argument."); + assert(!Args.empty() && "Should have at least one argument."); Expr *Arg0 = Args.front(); QualType Ty0 = Arg0->getType(); >From 842decb6b00f1b2be4b4d57c0e0df3044e4c34f8 Mon Sep 17 00:00:00 2001 From: Chaitanya Koparkar <ckopar...@gmail.com> Date: Fri, 29 Aug 2025 05:53:04 -0400 Subject: [PATCH 5/5] Tweak comment and release note --- clang/docs/ReleaseNotes.rst | 7 +++---- clang/lib/Sema/SemaChecking.cpp | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f7eb6376829da..09aaa6c4ae2ad 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -179,10 +179,6 @@ Non-comprehensive list of changes in this release Currently, the use of ``__builtin_dedup_pack`` is limited to template arguments and base specifiers, it also must be used within a template context. -- Builtin elementwise operators now accept vector arguments that have different - qualifiers on their elements. For example, vector of 4 ``const float`` values - and vector of 4 ``float`` values. - New Compiler Flags ------------------ @@ -270,6 +266,9 @@ Bug Fixes in This Version calls another function that requires target features not enabled in the caller. This prevents a fatal error in the backend. - Fixed scope of typedefs present inside a template class. (#GH91451) +- Builtin elementwise operators now accept vector arguments that have different + qualifiers on their elements. For example, vector of 4 ``const float`` values + and vector of 4 ``float`` values. (#GH155620) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 080d4a79f30ba..8ae7803fc4b6b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15892,7 +15892,6 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS, /// types can make the vector types be considered not equal. For example, /// vector of 4 'const float' values vs vector of 4 'float' values. /// So we compare unqualified types of their elements and number of elements. -/// See GitHub issue #155405. static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, ArrayRef<Expr *> Args) { assert(!Args.empty() && "Should have at least one argument."); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits