Skip to content

Commit 5796cb3

Browse files
committed
[clang] Improve diagnostics for vector builtins
Thie commit improves the diagnostics for vector (elementwise) builtins in a couple of ways. It primarily provides more precise type-checking diagnostics for builtins with specific type requirements. Previously many builtins were receiving a catch-all diagnostic suggesting types which aren't valid. It also makes consistent the type-checking behaviour between various binary and ternary builtins. The binary builtins would check for mismatched argument types before specific type requirements, whereas ternary builtins would perform the checks in the reverse order. The binary builtins now behave as the ternary ones do.
1 parent c42952a commit 5796cb3

14 files changed

+169
-187
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12528,7 +12528,8 @@ def err_builtin_invalid_arg_type: Error <
1252812528
"a vector of integers|"
1252912529
"an unsigned integer|"
1253012530
"an 'int'|"
12531-
"a vector of floating points}1 (was %2)">;
12531+
"a vector of floating points|"
12532+
"an integer or vector of integers}1 (was %2)">;
1253212533

1253312534
def err_builtin_matrix_disabled: Error<
1253412535
"matrix types extension is disabled. Pass -fenable-matrix to enable it">;

clang/include/clang/Sema/Sema.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,9 +2353,18 @@ class Sema final : public SemaBase {
23532353
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
23542354
const FunctionProtoType *Proto);
23552355

2356+
enum class EltwiseBuiltinArgTyRestriction {
2357+
None,
2358+
FloatTy,
2359+
IntegerTy,
2360+
SignedIntOrFloatTy,
2361+
};
2362+
23562363
/// \param FPOnly restricts the arguments to floating-point types.
2357-
std::optional<QualType> BuiltinVectorMath(CallExpr *TheCall,
2358-
bool FPOnly = false);
2364+
std::optional<QualType>
2365+
BuiltinVectorMath(CallExpr *TheCall,
2366+
EltwiseBuiltinArgTyRestriction ArgTyRestr =
2367+
EltwiseBuiltinArgTyRestriction::None);
23592368
bool BuiltinVectorToScalarMath(CallExpr *TheCall);
23602369

23612370
void checkLifetimeCaptureBy(FunctionDecl *FDecl, bool IsMemberFunction,
@@ -2459,9 +2468,13 @@ class Sema final : public SemaBase {
24592468
bool *ICContext = nullptr,
24602469
bool IsListInit = false);
24612470

2462-
bool BuiltinElementwiseTernaryMath(CallExpr *TheCall,
2463-
bool CheckForFloatArgs = true);
2464-
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall);
2471+
bool
2472+
BuiltinElementwiseTernaryMath(CallExpr *TheCall,
2473+
EltwiseBuiltinArgTyRestriction ArgTyRestr =
2474+
EltwiseBuiltinArgTyRestriction::FloatTy);
2475+
bool PrepareBuiltinElementwiseMathOneArgCall(
2476+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr =
2477+
EltwiseBuiltinArgTyRestriction::None);
24652478

24662479
private:
24672480
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
@@ -2570,7 +2583,9 @@ class Sema final : public SemaBase {
25702583
AtomicExpr::AtomicOp Op);
25712584

25722585
/// \param FPOnly restricts the arguments to floating-point types.
2573-
bool BuiltinElementwiseMath(CallExpr *TheCall, bool FPOnly = false);
2586+
bool BuiltinElementwiseMath(CallExpr *TheCall,
2587+
EltwiseBuiltinArgTyRestriction ArgTyRestr =
2588+
EltwiseBuiltinArgTyRestriction::None);
25742589
bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall);
25752590

25762591
bool BuiltinNonDeterministicValue(CallExpr *TheCall);

clang/lib/Sema/SemaChecking.cpp

Lines changed: 72 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,26 +1970,40 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
19701970
// Check if \p Ty is a valid type for the elementwise math builtins. If it is
19711971
// not a valid type, emit an error message and return true. Otherwise return
19721972
// false.
1973-
static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
1974-
QualType ArgTy, int ArgIndex) {
1975-
if (!ArgTy->getAs<VectorType>() &&
1976-
!ConstantMatrixType::isValidElementType(ArgTy)) {
1977-
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
1978-
<< ArgIndex << /* vector, integer or float ty*/ 0 << ArgTy;
1979-
}
1980-
1981-
return false;
1982-
}
1983-
1984-
static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
1985-
QualType ArgTy, int ArgIndex) {
1973+
static bool
1974+
checkMathBuiltinElementType(Sema &S, SourceLocation Loc, QualType ArgTy,
1975+
Sema::EltwiseBuiltinArgTyRestriction ArgTyRestr,
1976+
int ArgOrdinal) {
19861977
QualType EltTy = ArgTy;
19871978
if (auto *VecTy = EltTy->getAs<VectorType>())
19881979
EltTy = VecTy->getElementType();
19891980

1990-
if (!EltTy->isRealFloatingType()) {
1991-
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
1992-
<< ArgIndex << /* vector or float ty*/ 5 << ArgTy;
1981+
switch (ArgTyRestr) {
1982+
case Sema::EltwiseBuiltinArgTyRestriction::None:
1983+
if (!ArgTy->getAs<VectorType>() &&
1984+
!ConstantMatrixType::isValidElementType(ArgTy)) {
1985+
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
1986+
<< ArgOrdinal << /* vector, integer or float ty*/ 0 << ArgTy;
1987+
}
1988+
break;
1989+
case Sema::EltwiseBuiltinArgTyRestriction::FloatTy:
1990+
if (!EltTy->isRealFloatingType()) {
1991+
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
1992+
<< ArgOrdinal << /* vector or float ty*/ 5 << ArgTy;
1993+
}
1994+
break;
1995+
case Sema::EltwiseBuiltinArgTyRestriction::IntegerTy:
1996+
if (!EltTy->isIntegerType()) {
1997+
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
1998+
<< ArgOrdinal << /* vector or int ty*/ 10 << ArgTy;
1999+
}
2000+
break;
2001+
case Sema::EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy:
2002+
if (EltTy->isUnsignedIntegerType()) {
2003+
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
2004+
<< 1 << /* signed integer or float ty*/ 3 << ArgTy;
2005+
}
2006+
break;
19932007
}
19942008

19952009
return false;
@@ -2696,23 +2710,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
26962710

26972711
// __builtin_elementwise_abs restricts the element type to signed integers or
26982712
// floating point types only.
2699-
case Builtin::BI__builtin_elementwise_abs: {
2700-
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2713+
case Builtin::BI__builtin_elementwise_abs:
2714+
if (PrepareBuiltinElementwiseMathOneArgCall(
2715+
TheCall, EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy))
27012716
return ExprError();
2702-
2703-
QualType ArgTy = TheCall->getArg(0)->getType();
2704-
QualType EltTy = ArgTy;
2705-
2706-
if (auto *VecTy = EltTy->getAs<VectorType>())
2707-
EltTy = VecTy->getElementType();
2708-
if (EltTy->isUnsignedIntegerType()) {
2709-
Diag(TheCall->getArg(0)->getBeginLoc(),
2710-
diag::err_builtin_invalid_arg_type)
2711-
<< 1 << /* signed integer or float ty*/ 3 << ArgTy;
2712-
return ExprError();
2713-
}
27142717
break;
2715-
}
27162718

27172719
// These builtins restrict the element type to floating point
27182720
// types only.
@@ -2739,81 +2741,46 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
27392741
case Builtin::BI__builtin_elementwise_tan:
27402742
case Builtin::BI__builtin_elementwise_tanh:
27412743
case Builtin::BI__builtin_elementwise_trunc:
2742-
case Builtin::BI__builtin_elementwise_canonicalize: {
2743-
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2744-
return ExprError();
2745-
2746-
QualType ArgTy = TheCall->getArg(0)->getType();
2747-
if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
2748-
ArgTy, 1))
2744+
case Builtin::BI__builtin_elementwise_canonicalize:
2745+
if (PrepareBuiltinElementwiseMathOneArgCall(
2746+
TheCall, EltwiseBuiltinArgTyRestriction::FloatTy))
27492747
return ExprError();
27502748
break;
2751-
}
2752-
case Builtin::BI__builtin_elementwise_fma: {
2749+
case Builtin::BI__builtin_elementwise_fma:
27532750
if (BuiltinElementwiseTernaryMath(TheCall))
27542751
return ExprError();
27552752
break;
2756-
}
27572753

27582754
// These builtins restrict the element type to floating point
27592755
// types only, and take in two arguments.
27602756
case Builtin::BI__builtin_elementwise_minimum:
27612757
case Builtin::BI__builtin_elementwise_maximum:
27622758
case Builtin::BI__builtin_elementwise_atan2:
27632759
case Builtin::BI__builtin_elementwise_fmod:
2764-
case Builtin::BI__builtin_elementwise_pow: {
2765-
if (BuiltinElementwiseMath(TheCall, /*FPOnly=*/true))
2760+
case Builtin::BI__builtin_elementwise_pow:
2761+
if (BuiltinElementwiseMath(TheCall,
2762+
EltwiseBuiltinArgTyRestriction::FloatTy))
27662763
return ExprError();
27672764
break;
2768-
}
2769-
27702765
// These builtins restrict the element type to integer
27712766
// types only.
27722767
case Builtin::BI__builtin_elementwise_add_sat:
2773-
case Builtin::BI__builtin_elementwise_sub_sat: {
2774-
if (BuiltinElementwiseMath(TheCall))
2775-
return ExprError();
2776-
2777-
const Expr *Arg = TheCall->getArg(0);
2778-
QualType ArgTy = Arg->getType();
2779-
QualType EltTy = ArgTy;
2780-
2781-
if (auto *VecTy = EltTy->getAs<VectorType>())
2782-
EltTy = VecTy->getElementType();
2783-
2784-
if (!EltTy->isIntegerType()) {
2785-
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2786-
<< 1 << /* integer ty */ 6 << ArgTy;
2768+
case Builtin::BI__builtin_elementwise_sub_sat:
2769+
if (BuiltinElementwiseMath(TheCall,
2770+
EltwiseBuiltinArgTyRestriction::IntegerTy))
27872771
return ExprError();
2788-
}
27892772
break;
2790-
}
2791-
27922773
case Builtin::BI__builtin_elementwise_min:
27932774
case Builtin::BI__builtin_elementwise_max:
27942775
if (BuiltinElementwiseMath(TheCall))
27952776
return ExprError();
27962777
break;
27972778
case Builtin::BI__builtin_elementwise_popcount:
2798-
case Builtin::BI__builtin_elementwise_bitreverse: {
2799-
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2800-
return ExprError();
2801-
2802-
const Expr *Arg = TheCall->getArg(0);
2803-
QualType ArgTy = Arg->getType();
2804-
QualType EltTy = ArgTy;
2805-
2806-
if (auto *VecTy = EltTy->getAs<VectorType>())
2807-
EltTy = VecTy->getElementType();
2808-
2809-
if (!EltTy->isIntegerType()) {
2810-
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2811-
<< 1 << /* integer ty */ 6 << ArgTy;
2779+
case Builtin::BI__builtin_elementwise_bitreverse:
2780+
if (PrepareBuiltinElementwiseMathOneArgCall(
2781+
TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
28122782
return ExprError();
2813-
}
28142783
break;
2815-
}
2816-
28172784
case Builtin::BI__builtin_elementwise_copysign: {
28182785
if (checkArgCount(TheCall, 2))
28192786
return ExprError();
@@ -2825,10 +2792,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
28252792

28262793
QualType MagnitudeTy = Magnitude.get()->getType();
28272794
QualType SignTy = Sign.get()->getType();
2828-
if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
2829-
MagnitudeTy, 1) ||
2830-
checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(),
2831-
SignTy, 2)) {
2795+
if (checkMathBuiltinElementType(
2796+
*this, TheCall->getArg(0)->getBeginLoc(), MagnitudeTy,
2797+
EltwiseBuiltinArgTyRestriction::FloatTy, 1) ||
2798+
checkMathBuiltinElementType(
2799+
*this, TheCall->getArg(1)->getBeginLoc(), SignTy,
2800+
EltwiseBuiltinArgTyRestriction::FloatTy, 2)) {
28322801
return ExprError();
28332802
}
28342803

@@ -15278,7 +15247,8 @@ static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
1527815247
return S.UsualUnaryFPConversions(Res.get());
1527915248
}
1528015249

15281-
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
15250+
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
15251+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1528215252
if (checkArgCount(TheCall, 1))
1528315253
return true;
1528415254

@@ -15289,15 +15259,17 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
1528915259
TheCall->setArg(0, A.get());
1529015260
QualType TyA = A.get()->getType();
1529115261

15292-
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
15262+
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
15263+
ArgTyRestr, 1))
1529315264
return true;
1529415265

1529515266
TheCall->setType(TyA);
1529615267
return false;
1529715268
}
1529815269

15299-
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall, bool FPOnly) {
15300-
if (auto Res = BuiltinVectorMath(TheCall, FPOnly); Res.has_value()) {
15270+
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall,
15271+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
15272+
if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) {
1530115273
TheCall->setType(*Res);
1530215274
return false;
1530315275
}
@@ -15330,8 +15302,9 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
1533015302
return false;
1533115303
}
1533215304

15333-
std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
15334-
bool FPOnly) {
15305+
std::optional<QualType>
15306+
Sema::BuiltinVectorMath(CallExpr *TheCall,
15307+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1533515308
if (checkArgCount(TheCall, 2))
1533615309
return std::nullopt;
1533715310

@@ -15352,26 +15325,21 @@ std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
1535215325
QualType TyA = Args[0]->getType();
1535315326
QualType TyB = Args[1]->getType();
1535415327

15328+
if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
15329+
return std::nullopt;
15330+
1535515331
if (TyA.getCanonicalType() != TyB.getCanonicalType()) {
1535615332
Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
1535715333
return std::nullopt;
1535815334
}
1535915335

15360-
if (FPOnly) {
15361-
if (checkFPMathBuiltinElementType(*this, LocA, TyA, 1))
15362-
return std::nullopt;
15363-
} else {
15364-
if (checkMathBuiltinElementType(*this, LocA, TyA, 1))
15365-
return std::nullopt;
15366-
}
15367-
1536815336
TheCall->setArg(0, Args[0]);
1536915337
TheCall->setArg(1, Args[1]);
1537015338
return TyA;
1537115339
}
1537215340

15373-
bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
15374-
bool CheckForFloatArgs) {
15341+
bool Sema::BuiltinElementwiseTernaryMath(
15342+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1537515343
if (checkArgCount(TheCall, 3))
1537615344
return true;
1537715345

@@ -15391,20 +15359,11 @@ bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
1539115359
Args[I] = Converted.get();
1539215360
}
1539315361

15394-
if (CheckForFloatArgs) {
15395-
int ArgOrdinal = 1;
15396-
for (Expr *Arg : Args) {
15397-
if (checkFPMathBuiltinElementType(*this, Arg->getBeginLoc(),
15398-
Arg->getType(), ArgOrdinal++))
15399-
return true;
15400-
}
15401-
} else {
15402-
int ArgOrdinal = 1;
15403-
for (Expr *Arg : Args) {
15404-
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
15405-
ArgOrdinal++))
15406-
return true;
15407-
}
15362+
int ArgOrdinal = 1;
15363+
for (Expr *Arg : Args) {
15364+
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
15365+
ArgTyRestr, ArgOrdinal++))
15366+
return true;
1540815367
}
1540915368

1541015369
for (int I = 1; I < 3; ++I) {

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,8 +2421,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
24212421
CheckAllArgsHaveSameType(&SemaRef, TheCall))
24222422
return true;
24232423
if (SemaRef.BuiltinElementwiseTernaryMath(
2424-
TheCall, /*CheckForFloatArgs*/
2425-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2424+
TheCall, /*ArgTyRestr*/
2425+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2426+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2427+
: Sema::EltwiseBuiltinArgTyRestriction::None))
24262428
return true;
24272429
break;
24282430
}
@@ -2555,8 +2557,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
25552557
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
25562558
return true;
25572559
if (SemaRef.BuiltinElementwiseTernaryMath(
2558-
TheCall, /*CheckForFloatArgs*/
2559-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2560+
TheCall, /*ArgTyRestr*/
2561+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2562+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2563+
: Sema::EltwiseBuiltinArgTyRestriction::None))
25602564
return true;
25612565
break;
25622566
}

clang/test/Sema/aarch64-sve-vector-exp-ops.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
svfloat32_t test_exp_vv_i8mf8(svfloat32_t v) {
88

99
return __builtin_elementwise_exp(v);
10-
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
10+
// expected-error@-1 {{1st argument must be a floating point type}}
1111
}
1212

1313
svfloat32_t test_exp2_vv_i8mf8(svfloat32_t v) {
1414

1515
return __builtin_elementwise_exp2(v);
16-
// expected-error@-1 {{1st argument must be a vector, integer or floating point type}}
16+
// expected-error@-1 {{1st argument must be a floating point type}}
1717
}

0 commit comments

Comments
 (0)