[clang] [clang][ExprConst] Reject unary vector shuffles (PR #158589)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 15 04:31:02 PDT 2025
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/158589 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/158589
>From 1ee924c160f8b369b82fe4baf05a7428c8a10586 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 15 Sep 2025 11:25:28 +0200
Subject: [PATCH 1/3] [clang][ExprConst] Reject unary vector shuffles
This is not implemented at compile time and asserts later in codegen, so
reject it here.
---
clang/lib/AST/ByteCode/Compiler.cpp | 4 ++
clang/lib/AST/ExprConstant.cpp | 3 ++
clang/lib/Sema/SemaChecking.cpp | 43 ++++++++++----------
clang/test/Sema/constant-builtins-vector.cpp | 13 ++++++
4 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 78b74acc3789d..99f4bfbea973d 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -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);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 820b053057067..f80691f57e602 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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))
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 077f4311ed729..446d3ceb1b45e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5558,7 +5558,8 @@ 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()
@@ -5567,8 +5568,8 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
// 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()) {
@@ -5582,39 +5583,39 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
<< 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 = TheCall->getNumArgs() - 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 (!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) {
+ } else if (NumElements != NumResElements) {
QualType eltType = LHSType->castAs<VectorType>()->getElementType();
- resType = resType->isExtVectorType()
- ? Context.getExtVectorType(eltType, numResElements)
- : Context.getVectorType(eltType, numResElements,
+ 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;
@@ -5628,21 +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);
+ SmallVector<Expr *> Exprs;
+ for (unsigned I = 0; I != NumArgs; I++) {
+ Exprs.push_back(TheCall->getArg(I));
+ TheCall->setArg(I, nullptr);
}
- return new (Context) ShuffleVectorExpr(Context, exprs, resType,
+ return new (Context) ShuffleVectorExpr(Context, Exprs, ResType,
TheCall->getCallee()->getBeginLoc(),
TheCall->getRParenLoc());
}
diff --git a/clang/test/Sema/constant-builtins-vector.cpp b/clang/test/Sema/constant-builtins-vector.cpp
index 714a7fb753214..455284ef65e9b 100644
--- a/clang/test/Sema/constant-builtins-vector.cpp
+++ b/clang/test/Sema/constant-builtins-vector.cpp
@@ -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);
>From cef3544a5b8dba143e17d1e9b8b089e8337dae80 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 15 Sep 2025 12:40:16 +0200
Subject: [PATCH 2/3] A few more things
---
clang/lib/Sema/SemaChecking.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 446d3ceb1b45e..923d8b0d0832c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5562,7 +5562,7 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
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:
@@ -5579,17 +5579,17 @@ 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;
+ 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)
return ExprError(Diag(TheCall->getBeginLoc(),
@@ -5606,10 +5606,10 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
} else if (NumElements != NumResElements) {
- QualType eltType = LHSType->castAs<VectorType>()->getElementType();
+ QualType EltType = LHSType->castAs<VectorType>()->getElementType();
ResType = ResType->isExtVectorType()
- ? Context.getExtVectorType(eltType, NumResElements)
- : Context.getVectorType(eltType, NumResElements,
+ ? Context.getExtVectorType(EltType, NumResElements)
+ : Context.getVectorType(EltType, NumResElements,
VectorKind::Generic);
}
}
>From 6066f474467fbc4bdf20f1946535022fd9c002dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 15 Sep 2025 13:30:33 +0200
Subject: [PATCH 3/3] Spare the last SmallVector
---
clang/lib/Sema/SemaChecking.cpp | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 923d8b0d0832c..f62c82e3d214f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5637,15 +5637,13 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
TheCall->setArg(I, ConstantExpr::Create(Context, Arg, APValue(*Result)));
}
- SmallVector<Expr *> Exprs;
- for (unsigned I = 0; I != NumArgs; 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,
More information about the cfe-commits
mailing list