Skip to content

Commit be94ac2

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 378c6fb commit be94ac2

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
@@ -12425,7 +12425,8 @@ def err_builtin_invalid_arg_type: Error <
1242512425
"a vector of integers|"
1242612426
"an unsigned integer|"
1242712427
"an 'int'|"
12428-
"a vector of floating points}1 (was %2)">;
12428+
"a vector of floating points|"
12429+
"an integer or vector of integers}1 (was %2)">;
1242912430

1243012431
def err_builtin_matrix_disabled: Error<
1243112432
"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
@@ -2330,9 +2330,18 @@ class Sema final : public SemaBase {
23302330
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
23312331
const FunctionProtoType *Proto);
23322332

2333+
enum class EltwiseBuiltinArgTyRestriction {
2334+
None,
2335+
FloatTy,
2336+
IntegerTy,
2337+
SignedIntOrFloatTy,
2338+
};
2339+
23332340
/// \param FPOnly restricts the arguments to floating-point types.
2334-
std::optional<QualType> BuiltinVectorMath(CallExpr *TheCall,
2335-
bool FPOnly = false);
2341+
std::optional<QualType>
2342+
BuiltinVectorMath(CallExpr *TheCall,
2343+
EltwiseBuiltinArgTyRestriction ArgTyRestr =
2344+
EltwiseBuiltinArgTyRestriction::None);
23362345
bool BuiltinVectorToScalarMath(CallExpr *TheCall);
23372346

23382347
void checkLifetimeCaptureBy(FunctionDecl *FDecl, bool IsMemberFunction,
@@ -2417,9 +2426,13 @@ class Sema final : public SemaBase {
24172426
bool *ICContext = nullptr,
24182427
bool IsListInit = false);
24192428

2420-
bool BuiltinElementwiseTernaryMath(CallExpr *TheCall,
2421-
bool CheckForFloatArgs = true);
2422-
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall);
2429+
bool
2430+
BuiltinElementwiseTernaryMath(CallExpr *TheCall,
2431+
EltwiseBuiltinArgTyRestriction ArgTyRestr =
2432+
EltwiseBuiltinArgTyRestriction::FloatTy);
2433+
bool PrepareBuiltinElementwiseMathOneArgCall(
2434+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr =
2435+
EltwiseBuiltinArgTyRestriction::None);
24232436

24242437
private:
24252438
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
@@ -2528,7 +2541,9 @@ class Sema final : public SemaBase {
25282541
AtomicExpr::AtomicOp Op);
25292542

25302543
/// \param FPOnly restricts the arguments to floating-point types.
2531-
bool BuiltinElementwiseMath(CallExpr *TheCall, bool FPOnly = false);
2544+
bool BuiltinElementwiseMath(CallExpr *TheCall,
2545+
EltwiseBuiltinArgTyRestriction ArgTyRestr =
2546+
EltwiseBuiltinArgTyRestriction::None);
25322547
bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall);
25332548

25342549
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

@@ -14666,7 +14635,8 @@ static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
1466614635
return S.UsualUnaryFPConversions(Res.get());
1466714636
}
1466814637

14669-
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
14638+
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
14639+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1467014640
if (checkArgCount(TheCall, 1))
1467114641
return true;
1467214642

@@ -14677,15 +14647,17 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
1467714647
TheCall->setArg(0, A.get());
1467814648
QualType TyA = A.get()->getType();
1467914649

14680-
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
14650+
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
14651+
ArgTyRestr, 1))
1468114652
return true;
1468214653

1468314654
TheCall->setType(TyA);
1468414655
return false;
1468514656
}
1468614657

14687-
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall, bool FPOnly) {
14688-
if (auto Res = BuiltinVectorMath(TheCall, FPOnly); Res.has_value()) {
14658+
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall,
14659+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
14660+
if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) {
1468914661
TheCall->setType(*Res);
1469014662
return false;
1469114663
}
@@ -14718,8 +14690,9 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
1471814690
return false;
1471914691
}
1472014692

14721-
std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
14722-
bool FPOnly) {
14693+
std::optional<QualType>
14694+
Sema::BuiltinVectorMath(CallExpr *TheCall,
14695+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1472314696
if (checkArgCount(TheCall, 2))
1472414697
return std::nullopt;
1472514698

@@ -14740,26 +14713,21 @@ std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
1474014713
QualType TyA = Args[0]->getType();
1474114714
QualType TyB = Args[1]->getType();
1474214715

14716+
if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
14717+
return std::nullopt;
14718+
1474314719
if (TyA.getCanonicalType() != TyB.getCanonicalType()) {
1474414720
Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
1474514721
return std::nullopt;
1474614722
}
1474714723

14748-
if (FPOnly) {
14749-
if (checkFPMathBuiltinElementType(*this, LocA, TyA, 1))
14750-
return std::nullopt;
14751-
} else {
14752-
if (checkMathBuiltinElementType(*this, LocA, TyA, 1))
14753-
return std::nullopt;
14754-
}
14755-
1475614724
TheCall->setArg(0, Args[0]);
1475714725
TheCall->setArg(1, Args[1]);
1475814726
return TyA;
1475914727
}
1476014728

14761-
bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
14762-
bool CheckForFloatArgs) {
14729+
bool Sema::BuiltinElementwiseTernaryMath(
14730+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1476314731
if (checkArgCount(TheCall, 3))
1476414732
return true;
1476514733

@@ -14779,20 +14747,11 @@ bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
1477914747
Args[I] = Converted.get();
1478014748
}
1478114749

14782-
if (CheckForFloatArgs) {
14783-
int ArgOrdinal = 1;
14784-
for (Expr *Arg : Args) {
14785-
if (checkFPMathBuiltinElementType(*this, Arg->getBeginLoc(),
14786-
Arg->getType(), ArgOrdinal++))
14787-
return true;
14788-
}
14789-
} else {
14790-
int ArgOrdinal = 1;
14791-
for (Expr *Arg : Args) {
14792-
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
14793-
ArgOrdinal++))
14794-
return true;
14795-
}
14750+
int ArgOrdinal = 1;
14751+
for (Expr *Arg : Args) {
14752+
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
14753+
ArgTyRestr, ArgOrdinal++))
14754+
return true;
1479614755
}
1479714756

1479814757
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
@@ -2266,8 +2266,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
22662266
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
22672267
return true;
22682268
if (SemaRef.BuiltinElementwiseTernaryMath(
2269-
TheCall, /*CheckForFloatArgs*/
2270-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2269+
TheCall, /*ArgTyRestr*/
2270+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2271+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2272+
: Sema::EltwiseBuiltinArgTyRestriction::None))
22712273
return true;
22722274
break;
22732275
}
@@ -2400,8 +2402,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
24002402
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
24012403
return true;
24022404
if (SemaRef.BuiltinElementwiseTernaryMath(
2403-
TheCall, /*CheckForFloatArgs*/
2404-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2405+
TheCall, /*ArgTyRestr*/
2406+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2407+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2408+
: Sema::EltwiseBuiltinArgTyRestriction::None))
24052409
return true;
24062410
break;
24072411
}

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)