Skip to content

Commit 3cf5fb6

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 6a2ce34 commit 3cf5fb6

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
@@ -12403,7 +12403,8 @@ def err_builtin_invalid_arg_type: Error <
1240312403
"a vector of integers|"
1240412404
"an unsigned integer|"
1240512405
"an 'int'|"
12406-
"a vector of floating points}1 (was %2)">;
12406+
"a vector of floating points|"
12407+
"an integer or vector of integers}1 (was %2)">;
1240712408

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

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

23392348
void checkLifetimeCaptureBy(FunctionDecl *FDecl, bool IsMemberFunction,
@@ -2418,9 +2427,13 @@ class Sema final : public SemaBase {
24182427
bool *ICContext = nullptr,
24192428
bool IsListInit = false);
24202429

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

24252438
private:
24262439
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
@@ -2529,7 +2542,9 @@ class Sema final : public SemaBase {
25292542
AtomicExpr::AtomicOp Op);
25302543

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

25352550
bool BuiltinNonDeterministicValue(CallExpr *TheCall);

clang/lib/Sema/SemaChecking.cpp

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

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

19932007
return false;
@@ -2694,23 +2708,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
26942708

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

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

27552751
// These builtins restrict the element type to floating point
27562752
// types only, and take in two arguments.
27572753
case Builtin::BI__builtin_elementwise_minimum:
27582754
case Builtin::BI__builtin_elementwise_maximum:
27592755
case Builtin::BI__builtin_elementwise_atan2:
27602756
case Builtin::BI__builtin_elementwise_fmod:
2761-
case Builtin::BI__builtin_elementwise_pow: {
2762-
if (BuiltinElementwiseMath(TheCall, /*FPOnly=*/true))
2757+
case Builtin::BI__builtin_elementwise_pow:
2758+
if (BuiltinElementwiseMath(TheCall,
2759+
EltwiseBuiltinArgTyRestriction::FloatTy))
27632760
return ExprError();
27642761
break;
2765-
}
2766-
27672762
// These builtins restrict the element type to integer
27682763
// types only.
27692764
case Builtin::BI__builtin_elementwise_add_sat:
2770-
case Builtin::BI__builtin_elementwise_sub_sat: {
2771-
if (BuiltinElementwiseMath(TheCall))
2772-
return ExprError();
2773-
2774-
const Expr *Arg = TheCall->getArg(0);
2775-
QualType ArgTy = Arg->getType();
2776-
QualType EltTy = ArgTy;
2777-
2778-
if (auto *VecTy = EltTy->getAs<VectorType>())
2779-
EltTy = VecTy->getElementType();
2780-
2781-
if (!EltTy->isIntegerType()) {
2782-
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2783-
<< 1 << /* integer ty */ 6 << ArgTy;
2765+
case Builtin::BI__builtin_elementwise_sub_sat:
2766+
if (BuiltinElementwiseMath(TheCall,
2767+
EltwiseBuiltinArgTyRestriction::IntegerTy))
27842768
return ExprError();
2785-
}
27862769
break;
2787-
}
2788-
27892770
case Builtin::BI__builtin_elementwise_min:
27902771
case Builtin::BI__builtin_elementwise_max:
27912772
if (BuiltinElementwiseMath(TheCall))
27922773
return ExprError();
27932774
break;
27942775
case Builtin::BI__builtin_elementwise_popcount:
2795-
case Builtin::BI__builtin_elementwise_bitreverse: {
2796-
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
2797-
return ExprError();
2798-
2799-
const Expr *Arg = TheCall->getArg(0);
2800-
QualType ArgTy = Arg->getType();
2801-
QualType EltTy = ArgTy;
2802-
2803-
if (auto *VecTy = EltTy->getAs<VectorType>())
2804-
EltTy = VecTy->getElementType();
2805-
2806-
if (!EltTy->isIntegerType()) {
2807-
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2808-
<< 1 << /* integer ty */ 6 << ArgTy;
2776+
case Builtin::BI__builtin_elementwise_bitreverse:
2777+
if (PrepareBuiltinElementwiseMathOneArgCall(
2778+
TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
28092779
return ExprError();
2810-
}
28112780
break;
2812-
}
2813-
28142781
case Builtin::BI__builtin_elementwise_copysign: {
28152782
if (checkArgCount(TheCall, 2))
28162783
return ExprError();
@@ -2822,10 +2789,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
28222789

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

@@ -14661,7 +14630,8 @@ static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
1466114630
return S.UsualUnaryFPConversions(Res.get());
1466214631
}
1466314632

14664-
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
14633+
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
14634+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1466514635
if (checkArgCount(TheCall, 1))
1466614636
return true;
1466714637

@@ -14672,15 +14642,17 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
1467214642
TheCall->setArg(0, A.get());
1467314643
QualType TyA = A.get()->getType();
1467414644

14675-
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
14645+
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
14646+
ArgTyRestr, 1))
1467614647
return true;
1467714648

1467814649
TheCall->setType(TyA);
1467914650
return false;
1468014651
}
1468114652

14682-
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall, bool FPOnly) {
14683-
if (auto Res = BuiltinVectorMath(TheCall, FPOnly); Res.has_value()) {
14653+
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall,
14654+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
14655+
if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) {
1468414656
TheCall->setType(*Res);
1468514657
return false;
1468614658
}
@@ -14713,8 +14685,9 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
1471314685
return false;
1471414686
}
1471514687

14716-
std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
14717-
bool FPOnly) {
14688+
std::optional<QualType>
14689+
Sema::BuiltinVectorMath(CallExpr *TheCall,
14690+
EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1471814691
if (checkArgCount(TheCall, 2))
1471914692
return std::nullopt;
1472014693

@@ -14735,26 +14708,21 @@ std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
1473514708
QualType TyA = Args[0]->getType();
1473614709
QualType TyB = Args[1]->getType();
1473714710

14711+
if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
14712+
return std::nullopt;
14713+
1473814714
if (TyA.getCanonicalType() != TyB.getCanonicalType()) {
1473914715
Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
1474014716
return std::nullopt;
1474114717
}
1474214718

14743-
if (FPOnly) {
14744-
if (checkFPMathBuiltinElementType(*this, LocA, TyA, 1))
14745-
return std::nullopt;
14746-
} else {
14747-
if (checkMathBuiltinElementType(*this, LocA, TyA, 1))
14748-
return std::nullopt;
14749-
}
14750-
1475114719
TheCall->setArg(0, Args[0]);
1475214720
TheCall->setArg(1, Args[1]);
1475314721
return TyA;
1475414722
}
1475514723

14756-
bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
14757-
bool CheckForFloatArgs) {
14724+
bool Sema::BuiltinElementwiseTernaryMath(
14725+
CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
1475814726
if (checkArgCount(TheCall, 3))
1475914727
return true;
1476014728

@@ -14774,20 +14742,11 @@ bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
1477414742
Args[I] = Converted.get();
1477514743
}
1477614744

14777-
if (CheckForFloatArgs) {
14778-
int ArgOrdinal = 1;
14779-
for (Expr *Arg : Args) {
14780-
if (checkFPMathBuiltinElementType(*this, Arg->getBeginLoc(),
14781-
Arg->getType(), ArgOrdinal++))
14782-
return true;
14783-
}
14784-
} else {
14785-
int ArgOrdinal = 1;
14786-
for (Expr *Arg : Args) {
14787-
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
14788-
ArgOrdinal++))
14789-
return true;
14790-
}
14745+
int ArgOrdinal = 1;
14746+
for (Expr *Arg : Args) {
14747+
if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
14748+
ArgTyRestr, ArgOrdinal++))
14749+
return true;
1479114750
}
1479214751

1479314752
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
@@ -2259,8 +2259,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
22592259
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
22602260
return true;
22612261
if (SemaRef.BuiltinElementwiseTernaryMath(
2262-
TheCall, /*CheckForFloatArgs*/
2263-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2262+
TheCall, /*ArgTyRestr*/
2263+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2264+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2265+
: Sema::EltwiseBuiltinArgTyRestriction::None))
22642266
return true;
22652267
break;
22662268
}
@@ -2393,8 +2395,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
23932395
if (CheckVectorElementCallArgs(&SemaRef, TheCall))
23942396
return true;
23952397
if (SemaRef.BuiltinElementwiseTernaryMath(
2396-
TheCall, /*CheckForFloatArgs*/
2397-
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2398+
TheCall, /*ArgTyRestr*/
2399+
TheCall->getArg(0)->getType()->hasFloatingRepresentation()
2400+
? Sema::EltwiseBuiltinArgTyRestriction::FloatTy
2401+
: Sema::EltwiseBuiltinArgTyRestriction::None))
23982402
return true;
23992403
break;
24002404
}

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)