Skip to content

Commit 5e97338

Browse files
authored
[Clang] Update typechecking of builtin elementwise ternary math operators (llvm#155620)
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. Fixes llvm#155405
1 parent 6ed64df commit 5e97338

File tree

3 files changed

+74
-15
lines changed

3 files changed

+74
-15
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ Bug Fixes in This Version
286286
calls another function that requires target features not enabled in the caller. This
287287
prevents a fatal error in the backend.
288288
- Fixed scope of typedefs present inside a template class. (#GH91451)
289+
- Builtin elementwise operators now accept vector arguments that have different
290+
qualifiers on their elements. For example, vector of 4 ``const float`` values
291+
and vector of 4 ``float`` values. (#GH155405)
289292

290293
Bug Fixes to Compiler Builtins
291294
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaChecking.cpp

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15870,6 +15870,54 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
1587015870
return false;
1587115871
}
1587215872

15873+
/// Check if all arguments have the same type. If the types don't match, emit an
15874+
/// error message and return true. Otherwise return false.
15875+
///
15876+
/// For scalars we directly compare their unqualified types. But even if we
15877+
/// compare unqualified vector types, a difference in qualifiers in the element
15878+
/// types can make the vector types be considered not equal. For example,
15879+
/// vector of 4 'const float' values vs vector of 4 'float' values.
15880+
/// So we compare unqualified types of their elements and number of elements.
15881+
static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef,
15882+
ArrayRef<Expr *> Args) {
15883+
assert(!Args.empty() && "Should have at least one argument.");
15884+
15885+
Expr *Arg0 = Args.front();
15886+
QualType Ty0 = Arg0->getType();
15887+
15888+
auto EmitError = [&](Expr *ArgI) {
15889+
SemaRef.Diag(Arg0->getBeginLoc(),
15890+
diag::err_typecheck_call_different_arg_types)
15891+
<< Arg0->getType() << ArgI->getType();
15892+
};
15893+
15894+
// Compare scalar types.
15895+
if (!Ty0->isVectorType()) {
15896+
for (Expr *ArgI : Args.drop_front())
15897+
if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) {
15898+
EmitError(ArgI);
15899+
return true;
15900+
}
15901+
15902+
return false;
15903+
}
15904+
15905+
// Compare vector types.
15906+
const auto *Vec0 = Ty0->castAs<VectorType>();
15907+
for (Expr *ArgI : Args.drop_front()) {
15908+
const auto *VecI = ArgI->getType()->getAs<VectorType>();
15909+
if (!VecI ||
15910+
!SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(),
15911+
VecI->getElementType()) ||
15912+
Vec0->getNumElements() != VecI->getNumElements()) {
15913+
EmitError(ArgI);
15914+
return true;
15915+
}
15916+
}
15917+
15918+
return false;
15919+
}
15920+
1587315921
std::optional<QualType>
1587415922
Sema::BuiltinVectorMath(CallExpr *TheCall,
1587515923
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
@@ -15891,15 +15939,12 @@ Sema::BuiltinVectorMath(CallExpr *TheCall,
1589115939

1589215940
SourceLocation LocA = Args[0]->getBeginLoc();
1589315941
QualType TyA = Args[0]->getType();
15894-
QualType TyB = Args[1]->getType();
1589515942

1589615943
if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
1589715944
return std::nullopt;
1589815945

15899-
if (!Context.hasSameUnqualifiedType(TyA, TyB)) {
15900-
Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
15946+
if (checkBuiltinVectorMathArgTypes(*this, Args))
1590115947
return std::nullopt;
15902-
}
1590315948

1590415949
TheCall->setArg(0, Args[0]);
1590515950
TheCall->setArg(1, Args[1]);
@@ -15934,17 +15979,11 @@ bool Sema::BuiltinElementwiseTernaryMath(
1593415979
return true;
1593515980
}
1593615981

15937-
TheCall->setArg(0, Args[0]);
15938-
for (int I = 1; I < 3; ++I) {
15939-
if (Args[0]->getType().getCanonicalType() !=
15940-
Args[I]->getType().getCanonicalType()) {
15941-
return Diag(Args[0]->getBeginLoc(),
15942-
diag::err_typecheck_call_different_arg_types)
15943-
<< Args[0]->getType() << Args[I]->getType();
15944-
}
15982+
if (checkBuiltinVectorMathArgTypes(*this, Args))
15983+
return true;
1594515984

15985+
for (int I = 0; I < 3; ++I)
1594615986
TheCall->setArg(I, Args[I]);
15947-
}
1594815987

1594915988
TheCall->setType(Args[0]->getType());
1595015989
return false;

clang/test/Sema/builtins-elementwise-math.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ typedef double double4 __attribute__((ext_vector_type(4)));
55
typedef float float2 __attribute__((ext_vector_type(2)));
66
typedef float float3 __attribute__((ext_vector_type(3)));
77
typedef float float4 __attribute__((ext_vector_type(4)));
8+
typedef const float cfloat4 __attribute__((ext_vector_type(4)));
89

910
typedef int int2 __attribute__((ext_vector_type(2)));
1011
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,
13301331
// expected-error@-1 {{arguments are of different types ('int3' (vector of 3 'int' values) vs 'int2' (vector of 2 'int' values))}}
13311332
}
13321333

1334+
// Tests corresponding to GitHub issues #141397 and #155405.
1335+
// Type mismatch error when 'builtin-elementwise-math' arguments have
1336+
// different qualifiers, this should be well-formed.
13331337
typedef struct {
13341338
float3 b;
13351339
} struct_float3;
1336-
// This example uncovered a bug #141397 :
1337-
// Type mismatch error when 'builtin-elementwise-math' arguments have different qualifiers, this should be well-formed
1340+
13381341
float3 foo(float3 a,const struct_float3* hi) {
13391342
float3 b = __builtin_elementwise_max((float3)(0.0f), a);
13401343
return __builtin_elementwise_pow(b, hi->b.yyy);
13411344
}
13421345

1346+
float3 baz(float3 a, const struct_float3* hi) {
1347+
return __builtin_elementwise_fma(a, a, hi->b);
1348+
}
1349+
1350+
cfloat4 qux(cfloat4 x, float4 y, float4 z) {
1351+
float a = __builtin_elementwise_fma(x[0],y[0],z[0]);
1352+
return __builtin_elementwise_fma(x,y,z);
1353+
}
1354+
1355+
cfloat4 quux(cfloat4 x, float4 y) {
1356+
float a = __builtin_elementwise_pow(x[0],y[0]);
1357+
return __builtin_elementwise_pow(x,y);
1358+
}
1359+
13431360
void test_builtin_elementwise_ctlz(int i32, int2 v2i32, short i16,
13441361
double f64, double2 v2f64) {
13451362
f64 = __builtin_elementwise_ctlz(f64);

0 commit comments

Comments
 (0)