Skip to content

Commit 8059ce3

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 1e0e416 commit 8059ce3

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
@@ -12437,7 +12437,8 @@ def err_builtin_invalid_arg_type: Error <
1243712437
"a vector of integers|"
1243812438
"an unsigned integer|"
1243912439
"an 'int'|"
12440-
"a vector of floating points}1 (was %2)">;
12440+
"a vector of floating points|"
12441+
"an integer or vector of integers}1 (was %2)">;
1244112442

1244212443
def err_builtin_matrix_disabled: Error<
1244312444
"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;
@@ -2695,23 +2709,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
26952709

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

27162718
// These builtins restrict the element type to floating point
27172719
// types only.
@@ -2737,81 +2739,46 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
27372739
case Builtin::BI__builtin_elementwise_tan:
27382740
case Builtin::BI__builtin_elementwise_tanh:
27392741
case Builtin::BI__builtin_elementwise_trunc:
2740-
case Builtin::BI__builtin_elementwise_canonicalize: {
2741-
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2742-
return ExprError();
2743-
2744-
QualType ArgTy = TheCall->getArg(0)->getType();
2745-
if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
2746-
ArgTy, 1))
2742+
case Builtin::BI__builtin_elementwise_canonicalize:
2743+
if (PrepareBuiltinElementwiseMathOneArgCall(
2744+
TheCall, EltwiseBuiltinArgTyRestriction::FloatTy))
27472745
return ExprError();
27482746
break;
2749-
}
2750-
case Builtin::BI__builtin_elementwise_fma: {
2747+
case Builtin::BI__builtin_elementwise_fma:
27512748
if (BuiltinElementwiseTernaryMath(TheCall))
27522749
return ExprError();
27532750
break;
2754-
}
27552751

27562752
// These builtins restrict the element type to floating point
27572753
// types only, and take in two arguments.
27582754
case Builtin::BI__builtin_elementwise_minimum:
27592755
case Builtin::BI__builtin_elementwise_maximum:
27602756
case Builtin::BI__builtin_elementwise_atan2:
27612757
case Builtin::BI__builtin_elementwise_fmod:
2762-
case Builtin::BI__builtin_elementwise_pow: {
2763-
if (BuiltinElementwiseMath(TheCall, /*FPOnly=*/true))
2758+
case Builtin::BI__builtin_elementwise_pow:
2759+
if (BuiltinElementwiseMath(TheCall,
2760+
EltwiseBuiltinArgTyRestriction::FloatTy))
27642761
return ExprError();
27652762
break;
2766-
}
2767-
27682763
// These builtins restrict the element type to integer
27692764
// types only.
27702765
case Builtin::BI__builtin_elementwise_add_sat:
2771-
case Builtin::BI__builtin_elementwise_sub_sat: {
2772-
if (BuiltinElementwiseMath(TheCall))
2773-
return ExprError();
2774-
2775-
const Expr *Arg = TheCall->getArg(0);
2776-
QualType ArgTy = Arg->getType();
2777-
QualType EltTy = ArgTy;
2778-
2779-
if (auto *VecTy = EltTy->getAs<VectorType>())
2780-
EltTy = VecTy->getElementType();
2781-
2782-
if (!EltTy->isIntegerType()) {
2783-
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2784-
<< 1 << /* integer ty */ 6 << ArgTy;
2766+
case Builtin::BI__builtin_elementwise_sub_sat:
2767+
if (BuiltinElementwiseMath(TheCall,
2768+
EltwiseBuiltinArgTyRestriction::IntegerTy))
27852769
return ExprError();
2786-
}
27872770
break;
2788-
}
2789-
27902771
case Builtin::BI__builtin_elementwise_min:
27912772
case Builtin::BI__builtin_elementwise_max:
27922773
if (BuiltinElementwiseMath(TheCall))
27932774
return ExprError();
27942775
break;
27952776
case Builtin::BI__builtin_elementwise_popcount:
2796-
case Builtin::BI__builtin_elementwise_bitreverse: {
2797-
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2798-
return ExprError();
2799-
2800-
const Expr *Arg = TheCall->getArg(0);
2801-
QualType ArgTy = Arg->getType();
2802-
QualType EltTy = ArgTy;
2803-
2804-
if (auto *VecTy = EltTy->getAs<VectorType>())
2805-
EltTy = VecTy->getElementType();
2806-
2807-
if (!EltTy->isIntegerType()) {
2808-
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2809-
<< 1 << /* integer ty */ 6 << ArgTy;
2777+
case Builtin::BI__builtin_elementwise_bitreverse:
2778+
if (PrepareBuiltinElementwiseMathOneArgCall(
2779+
TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
28102780
return ExprError();
2811-
}
28122781
break;
2813-
}
2814-
28152782
case Builtin::BI__builtin_elementwise_copysign: {
28162783
if (checkArgCount(TheCall, 2))
28172784
return ExprError();
@@ -2823,10 +2790,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
28232790

28242791
QualType MagnitudeTy = Magnitude.get()->getType();
28252792
QualType SignTy = Sign.get()->getType();
2826-
if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
2827-
MagnitudeTy, 1) ||
2828-
checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(),
2829-
SignTy, 2)) {
2793+
if (checkMathBuiltinElementType(
2794+
*this, TheCall->getArg(0)->getBeginLoc(), MagnitudeTy,
2795+
EltwiseBuiltinArgTyRestriction::FloatTy, 1) ||
2796+
checkMathBuiltinElementType(
2797+
*this, TheCall->getArg(1)->getBeginLoc(), SignTy,
2798+
EltwiseBuiltinArgTyRestriction::FloatTy, 2)) {
28302799
return ExprError();
28312800
}
28322801

@@ -15215,7 +15184,8 @@ static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
1521515184
return S.UsualUnaryFPConversions(Res.get());
1521615185
}
1521715186

15218-
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
15187+
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
15188+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1521915189
if (checkArgCount(TheCall, 1))
1522015190
return true;
1522115191

@@ -15226,15 +15196,17 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
1522615196
TheCall->setArg(0, A.get());
1522715197
QualType TyA = A.get()->getType();
1522815198

15229-
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
15199+
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
15200+
ArgTyRestr, 1))
1523015201
return true;
1523115202

1523215203
TheCall->setType(TyA);
1523315204
return false;
1523415205
}
1523515206

15236-
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall, bool FPOnly) {
15237-
if (auto Res = BuiltinVectorMath(TheCall, FPOnly); Res.has_value()) {
15207+
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall,
15208+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
15209+
if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) {
1523815210
TheCall->setType(*Res);
1523915211
return false;
1524015212
}
@@ -15267,8 +15239,9 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
1526715239
return false;
1526815240
}
1526915241

15270-
std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
15271-
bool FPOnly) {
15242+
std::optional<QualType>
15243+
Sema::BuiltinVectorMath(CallExpr *TheCall,
15244+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1527215245
if (checkArgCount(TheCall, 2))
1527315246
return std::nullopt;
1527415247

@@ -15289,26 +15262,21 @@ std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
1528915262
QualType TyA = Args[0]->getType();
1529015263
QualType TyB = Args[1]->getType();
1529115264

15265+
if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
15266+
return std::nullopt;
15267+
1529215268
if (TyA.getCanonicalType() != TyB.getCanonicalType()) {
1529315269
Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
1529415270
return std::nullopt;
1529515271
}
1529615272

15297-
if (FPOnly) {
15298-
if (checkFPMathBuiltinElementType(*this, LocA, TyA, 1))
15299-
return std::nullopt;
15300-
} else {
15301-
if (checkMathBuiltinElementType(*this, LocA, TyA, 1))
15302-
return std::nullopt;
15303-
}
15304-
1530515273
TheCall->setArg(0, Args[0]);
1530615274
TheCall->setArg(1, Args[1]);
1530715275
return TyA;
1530815276
}
1530915277

15310-
bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
15311-
bool CheckForFloatArgs) {
15278+
bool Sema::BuiltinElementwiseTernaryMath(
15279+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1531215280
if (checkArgCount(TheCall, 3))
1531315281
return true;
1531415282

@@ -15328,20 +15296,11 @@ bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
1532815296
Args[I] = Converted.get();
1532915297
}
1533015298

15331-
if (CheckForFloatArgs) {
15332-
int ArgOrdinal = 1;
15333-
for (Expr *Arg : Args) {
15334-
if (checkFPMathBuiltinElementType(*this, Arg->getBeginLoc(),
15335-
Arg->getType(), ArgOrdinal++))
15336-
return true;
15337-
}
15338-
} else {
15339-
int ArgOrdinal = 1;
15340-
for (Expr *Arg : Args) {
15341-
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
15342-
ArgOrdinal++))
15343-
return true;
15344-
}
15299+
int ArgOrdinal = 1;
15300+
for (Expr *Arg : Args) {
15301+
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
15302+
ArgTyRestr, ArgOrdinal++))
15303+
return true;
1534515304
}
1534615305

1534715306
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
@@ -2289,8 +2289,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
22892289
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
22902290
return true;
22912291
if (SemaRef.BuiltinElementwiseTernaryMath(
2292-
TheCall, /*CheckForFloatArgs*/
2293-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2292+
TheCall, /*ArgTyRestr*/
2293+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2294+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2295+
: Sema::EltwiseBuiltinArgTyRestriction::None))
22942296
return true;
22952297
break;
22962298
}
@@ -2423,8 +2425,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
24232425
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
24242426
return true;
24252427
if (SemaRef.BuiltinElementwiseTernaryMath(
2426-
TheCall, /*CheckForFloatArgs*/
2427-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2428+
TheCall, /*ArgTyRestr*/
2429+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2430+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2431+
: Sema::EltwiseBuiltinArgTyRestriction::None))
24282432
return true;
24292433
break;
24302434
}

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)