[clang] [clang] Update typechecking of builtin elementwise ternary math operators (PR #155620)
Chaitanya Koparkar via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 29 02:55:02 PDT 2025
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 <ckoparkar at 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 at -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 <ckoparkar at 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 <zwuis at outlook.com>
Co-authored-by: Timm Baeder <tbaeder at 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 <ckoparkar at 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 <ckoparkar at 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 <tbaeder at 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 <ckoparkar at 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.");
More information about the cfe-commits
mailing list