Skip to content

Commit c8b5b6e

Browse files
authored
[clang][ExprConst] Reject unary vector shuffles (#158589)
This is not implemented at compile time and asserts in assertion builds, so reject it here. Fixed the coding style in `BuiltinShuffleVector` at the same time. Fixes #158471
1 parent ea9acc9 commit c8b5b6e

File tree

5 files changed

+51
-28
lines changed

5 files changed

+51
-28
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ Improvements to Clang's diagnostics
291291
- Fixed a bug where the source location was missing when diagnosing ill-formed
292292
placeholder constraints.
293293

294+
- The two-element, unary mask variant of ``__builtin_shufflevector`` is now
295+
properly being rejected when used at compile-time. It was not implemented
296+
and caused assertion failures before (#GH158471).
297+
294298
Improvements to Clang's time-trace
295299
----------------------------------
296300

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3986,6 +3986,10 @@ bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
39863986

39873987
template <class Emitter>
39883988
bool Compiler<Emitter>::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
3989+
// FIXME: Unary shuffle with mask not currently supported.
3990+
if (E->getNumSubExprs() == 2)
3991+
return this->emitInvalid(E);
3992+
39893993
assert(Initializing);
39903994
assert(E->getNumSubExprs() > 2);
39913995

clang/lib/AST/ExprConstant.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12187,6 +12187,9 @@ static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E,
1218712187
}
1218812188

1218912189
bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
12190+
// FIXME: Unary shuffle with mask not currently supported.
12191+
if (E->getNumSubExprs() == 2)
12192+
return Error(E);
1219012193
APValue VecVal1;
1219112194
const Expr *Vec1 = E->getExpr(0);
1219212195
if (!EvaluateAsRValue(Info, Vec1, VecVal1))

clang/lib/Sema/SemaChecking.cpp

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5558,17 +5558,18 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) {
55585558
/// BuiltinShuffleVector - Handle __builtin_shufflevector.
55595559
// This is declared to take (...), so we have to check everything.
55605560
ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
5561-
if (TheCall->getNumArgs() < 2)
5561+
unsigned NumArgs = TheCall->getNumArgs();
5562+
if (NumArgs < 2)
55625563
return ExprError(Diag(TheCall->getEndLoc(),
55635564
diag::err_typecheck_call_too_few_args_at_least)
5564-
<< 0 /*function call*/ << 2 << TheCall->getNumArgs()
5565+
<< 0 /*function call*/ << 2 << NumArgs
55655566
<< /*is non object*/ 0 << TheCall->getSourceRange());
55665567

55675568
// Determine which of the following types of shufflevector we're checking:
55685569
// 1) unary, vector mask: (lhs, mask)
55695570
// 2) binary, scalar mask: (lhs, rhs, index, ..., index)
5570-
QualType resType = TheCall->getArg(0)->getType();
5571-
unsigned numElements = 0;
5571+
QualType ResType = TheCall->getArg(0)->getType();
5572+
unsigned NumElements = 0;
55725573

55735574
if (!TheCall->getArg(0)->isTypeDependent() &&
55745575
!TheCall->getArg(1)->isTypeDependent()) {
@@ -5578,43 +5579,43 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
55785579
if (!LHSType->isVectorType() || !RHSType->isVectorType())
55795580
return ExprError(
55805581
Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_non_vector)
5581-
<< TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false
5582+
<< TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ false
55825583
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
55835584
TheCall->getArg(1)->getEndLoc()));
55845585

5585-
numElements = LHSType->castAs<VectorType>()->getNumElements();
5586-
unsigned numResElements = TheCall->getNumArgs() - 2;
5586+
NumElements = LHSType->castAs<VectorType>()->getNumElements();
5587+
unsigned NumResElements = NumArgs - 2;
55875588

55885589
// Check to see if we have a call with 2 vector arguments, the unary shuffle
55895590
// with mask. If so, verify that RHS is an integer vector type with the
55905591
// same number of elts as lhs.
5591-
if (TheCall->getNumArgs() == 2) {
5592+
if (NumArgs == 2) {
55925593
if (!RHSType->hasIntegerRepresentation() ||
5593-
RHSType->castAs<VectorType>()->getNumElements() != numElements)
5594+
RHSType->castAs<VectorType>()->getNumElements() != NumElements)
55945595
return ExprError(Diag(TheCall->getBeginLoc(),
55955596
diag::err_vec_builtin_incompatible_vector)
55965597
<< TheCall->getDirectCallee()
5597-
<< /*isMorethantwoArgs*/ false
5598+
<< /*isMoreThanTwoArgs*/ false
55985599
<< SourceRange(TheCall->getArg(1)->getBeginLoc(),
55995600
TheCall->getArg(1)->getEndLoc()));
56005601
} else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
56015602
return ExprError(Diag(TheCall->getBeginLoc(),
56025603
diag::err_vec_builtin_incompatible_vector)
56035604
<< TheCall->getDirectCallee()
5604-
<< /*isMorethantwoArgs*/ false
5605+
<< /*isMoreThanTwoArgs*/ false
56055606
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
56065607
TheCall->getArg(1)->getEndLoc()));
5607-
} else if (numElements != numResElements) {
5608-
QualType eltType = LHSType->castAs<VectorType>()->getElementType();
5609-
resType = resType->isExtVectorType()
5610-
? Context.getExtVectorType(eltType, numResElements)
5611-
: Context.getVectorType(eltType, numResElements,
5608+
} else if (NumElements != NumResElements) {
5609+
QualType EltType = LHSType->castAs<VectorType>()->getElementType();
5610+
ResType = ResType->isExtVectorType()
5611+
? Context.getExtVectorType(EltType, NumResElements)
5612+
: Context.getVectorType(EltType, NumResElements,
56125613
VectorKind::Generic);
56135614
}
56145615
}
56155616

5616-
for (unsigned i = 2; i < TheCall->getNumArgs(); i++) {
5617-
Expr *Arg = TheCall->getArg(i);
5617+
for (unsigned I = 2; I != NumArgs; ++I) {
5618+
Expr *Arg = TheCall->getArg(I);
56185619
if (Arg->isTypeDependent() || Arg->isValueDependent())
56195620
continue;
56205621

@@ -5628,23 +5629,21 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
56285629
if (Result->isSigned() && Result->isAllOnes())
56295630
;
56305631
else if (Result->getActiveBits() > 64 ||
5631-
Result->getZExtValue() >= numElements * 2)
5632+
Result->getZExtValue() >= NumElements * 2)
56325633
return ExprError(Diag(TheCall->getBeginLoc(),
56335634
diag::err_shufflevector_argument_too_large)
56345635
<< Arg->getSourceRange());
56355636

5636-
TheCall->setArg(i, ConstantExpr::Create(Context, Arg, APValue(*Result)));
5637+
TheCall->setArg(I, ConstantExpr::Create(Context, Arg, APValue(*Result)));
56375638
}
56385639

5639-
SmallVector<Expr *> exprs;
5640-
for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) {
5641-
exprs.push_back(TheCall->getArg(i));
5642-
TheCall->setArg(i, nullptr);
5643-
}
5640+
auto *Result = new (Context) ShuffleVectorExpr(
5641+
Context, ArrayRef(TheCall->getArgs(), NumArgs), ResType,
5642+
TheCall->getCallee()->getBeginLoc(), TheCall->getRParenLoc());
56445643

5645-
return new (Context) ShuffleVectorExpr(Context, exprs, resType,
5646-
TheCall->getCallee()->getBeginLoc(),
5647-
TheCall->getRParenLoc());
5644+
// All moved to Result.
5645+
TheCall->shrinkNumArgs(0);
5646+
return Result;
56485647
}
56495648

56505649
ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,

clang/test/Sema/constant-builtins-vector.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,19 @@ permitted in a constexpr context}}
731731
vector4charConst1,
732732
vector4charConst2, -1, -1, -1, -1);
733733

734+
namespace UnaryShuffleUnsupported {
735+
typedef int vi6 __attribute__((ext_vector_type(2)));
736+
constexpr int foo() { // expected-error {{never produces a constant expression}}
737+
vi6 a = {1,2};
738+
vi6 b = {3,4};
739+
vi6 r = __builtin_shufflevector(a, b); // expected-note 2{{subexpression not valid in a constant expression}}
740+
741+
return r[0] + r[1];
742+
}
743+
static_assert(foo() == 0); // expected-error {{not an integral constant expression}} \
744+
// expected-note {{in call to}}
745+
}
746+
734747
static_assert(__builtin_reduce_add((vector4char){}) == 0);
735748
static_assert(__builtin_reduce_add((vector4char){1, 2, 3, 4}) == 10);
736749
static_assert(__builtin_reduce_add((vector4short){10, 20, 30, 40}) == 100);

0 commit comments

Comments
 (0)