Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ Improvements to Clang's diagnostics
- Fixed a bug where the source location was missing when diagnosing ill-formed
placeholder constraints.

- The two-element, unary mask variant of ``__builtin_shufflevector`` is now
properly being rejected when used at compile-time. It was not implemented
and caused assertion failures before (#GH158471).

Improvements to Clang's time-trace
----------------------------------

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3986,6 +3986,10 @@ bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) {

template <class Emitter>
bool Compiler<Emitter>::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
// FIXME: Unary shuffle with mask not currently supported.
if (E->getNumSubExprs() == 2)
return this->emitInvalid(E);

assert(Initializing);
assert(E->getNumSubExprs() > 2);

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12160,6 +12160,9 @@ static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E,
}

bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
// FIXME: Unary shuffle with mask not currently supported.
if (E->getNumSubExprs() == 2)
return Error(E);
APValue VecVal1;
const Expr *Vec1 = E->getExpr(0);
if (!EvaluateAsRValue(Info, Vec1, VecVal1))
Expand Down
55 changes: 27 additions & 28 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5558,17 +5558,18 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) {
/// BuiltinShuffleVector - Handle __builtin_shufflevector.
// This is declared to take (...), so we have to check everything.
ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 2)
unsigned NumArgs = TheCall->getNumArgs();
if (NumArgs < 2)
return ExprError(Diag(TheCall->getEndLoc(),
diag::err_typecheck_call_too_few_args_at_least)
<< 0 /*function call*/ << 2 << TheCall->getNumArgs()
<< 0 /*function call*/ << 2 << NumArgs
<< /*is non object*/ 0 << TheCall->getSourceRange());

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

if (!TheCall->getArg(0)->isTypeDependent() &&
!TheCall->getArg(1)->isTypeDependent()) {
Expand All @@ -5578,43 +5579,43 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
if (!LHSType->isVectorType() || !RHSType->isVectorType())
return ExprError(
Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_non_vector)
<< TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false
<< TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ false
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));

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

// Check to see if we have a call with 2 vector arguments, the unary shuffle
// with mask. If so, verify that RHS is an integer vector type with the
// same number of elts as lhs.
if (TheCall->getNumArgs() == 2) {
if (NumArgs == 2) {
if (!RHSType->hasIntegerRepresentation() ||
RHSType->castAs<VectorType>()->getNumElements() != numElements)
RHSType->castAs<VectorType>()->getNumElements() != NumElements)
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< /*isMorethantwoArgs*/ false
<< /*isMoreThanTwoArgs*/ false
<< SourceRange(TheCall->getArg(1)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
} else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< /*isMorethantwoArgs*/ false
<< /*isMoreThanTwoArgs*/ false
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
} else if (numElements != numResElements) {
QualType eltType = LHSType->castAs<VectorType>()->getElementType();
resType = resType->isExtVectorType()
? Context.getExtVectorType(eltType, numResElements)
: Context.getVectorType(eltType, numResElements,
} else if (NumElements != NumResElements) {
QualType EltType = LHSType->castAs<VectorType>()->getElementType();
ResType = ResType->isExtVectorType()
? Context.getExtVectorType(EltType, NumResElements)
: Context.getVectorType(EltType, NumResElements,
VectorKind::Generic);
}
}

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

Expand All @@ -5628,23 +5629,21 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
if (Result->isSigned() && Result->isAllOnes())
;
else if (Result->getActiveBits() > 64 ||
Result->getZExtValue() >= numElements * 2)
Result->getZExtValue() >= NumElements * 2)
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_shufflevector_argument_too_large)
<< Arg->getSourceRange());

TheCall->setArg(i, ConstantExpr::Create(Context, Arg, APValue(*Result)));
TheCall->setArg(I, ConstantExpr::Create(Context, Arg, APValue(*Result)));
}

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

return new (Context) ShuffleVectorExpr(Context, exprs, resType,
TheCall->getCallee()->getBeginLoc(),
TheCall->getRParenLoc());
// All moved to Result.
TheCall->shrinkNumArgs(0);
return Result;
}

ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
Expand Down
13 changes: 13 additions & 0 deletions clang/test/Sema/constant-builtins-vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,19 @@ permitted in a constexpr context}}
vector4charConst1,
vector4charConst2, -1, -1, -1, -1);

namespace UnaryShuffleUnsupported {
typedef int vi6 __attribute__((ext_vector_type(2)));
constexpr int foo() { // expected-error {{never produces a constant expression}}
vi6 a = {1,2};
vi6 b = {3,4};
vi6 r = __builtin_shufflevector(a, b); // expected-note 2{{subexpression not valid in a constant expression}}

return r[0] + r[1];
}
static_assert(foo() == 0); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}
}

static_assert(__builtin_reduce_add((vector4char){}) == 0);
static_assert(__builtin_reduce_add((vector4char){1, 2, 3, 4}) == 10);
static_assert(__builtin_reduce_add((vector4short){10, 20, 30, 40}) == 100);
Expand Down
Loading