Skip to content

Commit 2903df0

Browse files
Squashed commit of the following:
commit 8d41d93 Author: Pol Marcet Sardà <[email protected]> Date: Sat Apr 20 12:19:49 2024 +0200 Address some misc comments; added a diagnostic and expanded macros in testing. commit 9493c0f Author: Pol Marcet Sardà <[email protected]> Date: Sun Mar 31 18:18:45 2024 +0200 Following the review of sethp, I have made the following changes: -- Added diagnostic for the undefined shuffle of -1 -- Validated support for _BitInt -- A bunch of other minnor tweaks here and there commit 8273abc Author: Pol Marcet Sardà <[email protected]> Date: Thu Jan 4 12:31:08 2024 +0100 Fix typo in file name commit ff68f23 Author: Pol Marcet Sardà <[email protected]> Date: Thu Jan 4 11:26:08 2024 +0100 Address suggestions from RKSimon commit c14783d Author: Pol Marcet Sardà <[email protected]> Date: Sat Dec 30 13:59:00 2023 +0100 [clang] Constexpr for __builtin_shufflevector and __builtin_convertvector Summary: This patch adds constexpr support for __builtin_shufflevector and __builtin_convertvector. A small oddity encountered was that the arg to the intrinsics may be an lvalue without any sort of implicit cast of any kind. I solved this through the EvaluateVectorOrLValue function, which treats the lvalue as if it was in an rvalue cast, which gets me the desired vector. Co-Authored-By: Seth Pellegrino <[email protected]>
1 parent df6d2fa commit 2903df0

File tree

6 files changed

+863
-5
lines changed

6 files changed

+863
-5
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2931,7 +2931,7 @@ Query for this feature with ``__has_builtin(__builtin_dump_struct)``
29312931
``__builtin_shufflevector`` is used to express generic vector
29322932
permutation/shuffle/swizzle operations. This builtin is also very important
29332933
for the implementation of various target-specific header files like
2934-
``<xmmintrin.h>``.
2934+
``<xmmintrin.h>``. This builtin can be used within constant expressions.
29352935
29362936
**Syntax**:
29372937
@@ -2958,7 +2958,7 @@ for the implementation of various target-specific header files like
29582958
// Concatenate every other element of 8-element vectors V1 and V2.
29592959
__builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
29602960
2961-
// Shuffle v1 with some elements being undefined
2961+
// Shuffle v1 with some elements being undefined. Not allowed in constexpr.
29622962
__builtin_shufflevector(v1, v1, 3, -1, 1, -1)
29632963
29642964
**Description**:
@@ -2971,6 +2971,7 @@ starting with the first vector, continuing into the second vector. Thus, if
29712971
``vec1`` is a 4-element vector, index 5 would refer to the second element of
29722972
``vec2``. An index of -1 can be used to indicate that the corresponding element
29732973
in the returned vector is a don't care and can be optimized by the backend.
2974+
Values of -1 are not supported in constant expressions.
29742975
29752976
The result of ``__builtin_shufflevector`` is a vector with the same element
29762977
type as ``vec1``/``vec2`` but that has an element count equal to the number of
@@ -2985,7 +2986,8 @@ Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
29852986
29862987
``__builtin_convertvector`` is used to express generic vector
29872988
type-conversion operations. The input vector and the output vector
2988-
type must have the same number of elements.
2989+
type must have the same number of elements. This builtin can be used within
2990+
constant expressions.
29892991
29902992
**Syntax**:
29912993

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ Non-comprehensive list of changes in this release
233233
* ``-fdenormal-fp-math=preserve-sign`` is no longer implied by ``-ffast-math``
234234
on x86 systems.
235235

236+
- Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may
237+
now be used within constant expressions.
238+
236239
New Compiler Flags
237240
------------------
238241
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10330,9 +10330,13 @@ def err_shufflevector_nonconstant_argument : Error<
1033010330
def err_shufflevector_argument_too_large : Error<
1033110331
"index for __builtin_shufflevector must be less than the total number "
1033210332
"of vector elements">;
10333+
def err_shufflevector_minus_one_is_undefined_behavior_constexpr : Error<
10334+
"index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position %0 not permitted in a constexpr context.">;
1033310335

1033410336
def err_convertvector_non_vector : Error<
1033510337
"first argument to __builtin_convertvector must be a vector">;
10338+
def err_convertvector_constexpr_unsupported_vector_cast : Error<
10339+
"unsupported vector cast from %0 to %1 in a constant expression.">;
1033610340
def err_builtin_non_vector_type : Error<
1033710341
"%0 argument to %1 must be of vector type">;
1033810342
def err_convertvector_incompatible_vector : Error<

clang/lib/AST/ExprConstant.cpp

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,7 +2706,11 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
27062706
static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
27072707
QualType SrcType, QualType DestType,
27082708
APFloat &Result) {
2709-
assert(isa<CastExpr>(E) || isa<CompoundAssignOperator>(E));
2709+
assert((isa<CastExpr>(E) || isa<CompoundAssignOperator>(E) ||
2710+
isa<ConvertVectorExpr>(E)) &&
2711+
"HandleFloatToFloatCast has been checked with only CastExpr, "
2712+
"CompoundAssignOperator and ConvertVectorExpr. Please either validate "
2713+
"the new expression or address the root cause of this usage.");
27102714
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
27112715
APFloat::opStatus St;
27122716
APFloat Value = Result;
@@ -10710,8 +10714,11 @@ namespace {
1071010714
bool VisitUnaryImag(const UnaryOperator *E);
1071110715
bool VisitBinaryOperator(const BinaryOperator *E);
1071210716
bool VisitUnaryOperator(const UnaryOperator *E);
10717+
bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
10718+
bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
10719+
1071310720
// FIXME: Missing: conditional operator (for GNU
10714-
// conditional select), shufflevector, ExtVectorElementExpr
10721+
// conditional select), ExtVectorElementExpr
1071510722
};
1071610723
} // end anonymous namespace
1071710724

@@ -10962,6 +10969,122 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
1096210969
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
1096310970
}
1096410971

10972+
static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO,
10973+
const Expr *E, QualType SourceTy,
10974+
QualType DestTy, APValue const &Original,
10975+
APValue &Result) {
10976+
if (SourceTy->isIntegerType()) {
10977+
if (DestTy->isRealFloatingType()) {
10978+
Result = APValue(APFloat(0.0));
10979+
return HandleIntToFloatCast(Info, E, FPO, SourceTy, Original.getInt(),
10980+
DestTy, Result.getFloat());
10981+
}
10982+
if (DestTy->isIntegerType()) {
10983+
Result = APValue(
10984+
HandleIntToIntCast(Info, E, DestTy, SourceTy, Original.getInt()));
10985+
return true;
10986+
}
10987+
} else if (SourceTy->isRealFloatingType()) {
10988+
if (DestTy->isRealFloatingType()) {
10989+
Result = Original;
10990+
return HandleFloatToFloatCast(Info, E, SourceTy, DestTy,
10991+
Result.getFloat());
10992+
}
10993+
if (DestTy->isIntegerType()) {
10994+
Result = APValue(APSInt());
10995+
return HandleFloatToIntCast(Info, E, SourceTy, Original.getFloat(),
10996+
DestTy, Result.getInt());
10997+
}
10998+
}
10999+
11000+
Info.FFDiag(E, diag::err_convertvector_constexpr_unsupported_vector_cast)
11001+
<< SourceTy << DestTy;
11002+
return false;
11003+
}
11004+
11005+
bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
11006+
APValue Source;
11007+
QualType SourceVecType = E->getSrcExpr()->getType();
11008+
if (!EvaluateAsRValue(Info, E->getSrcExpr(), Source))
11009+
return false;
11010+
11011+
QualType DestTy = E->getType()->castAs<VectorType>()->getElementType();
11012+
QualType SourceTy = SourceVecType->castAs<VectorType>()->getElementType();
11013+
11014+
const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
11015+
11016+
auto SourceLen = Source.getVectorLength();
11017+
SmallVector<APValue, 4> ResultElements;
11018+
ResultElements.reserve(SourceLen);
11019+
for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
11020+
APValue Elt;
11021+
if (!handleVectorElementCast(Info, FPO, E, SourceTy, DestTy,
11022+
Source.getVectorElt(EltNum), Elt))
11023+
return false;
11024+
ResultElements.push_back(std::move(Elt));
11025+
}
11026+
11027+
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
11028+
}
11029+
11030+
static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E,
11031+
QualType ElemType, APValue const &VecVal1,
11032+
APValue const &VecVal2, unsigned EltNum,
11033+
APValue &Result) {
11034+
unsigned const TotalElementsInInputVector1 = VecVal1.getVectorLength();
11035+
unsigned const TotalElementsInInputVector2 = VecVal2.getVectorLength();
11036+
11037+
APSInt IndexVal = E->getShuffleMaskIdx(Info.Ctx, EltNum);
11038+
int64_t index = IndexVal.getExtValue();
11039+
// The spec says that -1 should be treated as undef for optimizations,
11040+
// but in constexpr we'd have to produce an APValue::Indeterminate,
11041+
// which is prohibited from being a top-level constant value. Emit a
11042+
// diagnostic instead.
11043+
if (index == -1) {
11044+
Info.FFDiag(
11045+
E, diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
11046+
<< EltNum;
11047+
return false;
11048+
}
11049+
11050+
if (index < 0 ||
11051+
index >= TotalElementsInInputVector1 + TotalElementsInInputVector2)
11052+
llvm_unreachable("Out of bounds shuffle index");
11053+
11054+
if (index >= TotalElementsInInputVector1)
11055+
Result = VecVal2.getVectorElt(index - TotalElementsInInputVector1);
11056+
else
11057+
Result = VecVal1.getVectorElt(index);
11058+
return true;
11059+
}
11060+
11061+
bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
11062+
APValue VecVal1;
11063+
const Expr *Vec1 = E->getExpr(0);
11064+
if (!EvaluateAsRValue(Info, Vec1, VecVal1))
11065+
return false;
11066+
APValue VecVal2;
11067+
const Expr *Vec2 = E->getExpr(1);
11068+
if (!EvaluateAsRValue(Info, Vec2, VecVal2))
11069+
return false;
11070+
11071+
VectorType const *DestVecTy = E->getType()->castAs<VectorType>();
11072+
QualType DestElTy = DestVecTy->getElementType();
11073+
11074+
auto TotalElementsInOutputVector = DestVecTy->getNumElements();
11075+
11076+
SmallVector<APValue, 4> ResultElements;
11077+
ResultElements.reserve(TotalElementsInOutputVector);
11078+
for (unsigned EltNum = 0; EltNum < TotalElementsInOutputVector; ++EltNum) {
11079+
APValue Elt;
11080+
if (!handleVectorShuffle(Info, E, DestElTy, VecVal1, VecVal2, EltNum, Elt))
11081+
return false;
11082+
ResultElements.push_back(std::move(Elt));
11083+
}
11084+
11085+
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
11086+
}
11087+
1096511088
//===----------------------------------------------------------------------===//
1096611089
// Array Evaluation
1096711090
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)