summaryrefslogtreecommitdiff
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorShawn K <kimshawn02@icloud.com>2025-10-13 03:01:35 -0700
committerGitHub <noreply@github.com>2025-10-13 10:01:35 +0000
commite3f22d9ee4d743a43db8f4de5ba1d57d3dee67b1 (patch)
treef7203f69ac34f564656579e70786f1ea2049c808 /clang/lib/AST/ExprConstant.cpp
parent648b3aab478840cd72913d23cbbb425dc890f86a (diff)
[X86][Clang] VectorExprEvaluator::VisitCallExpr / InterpretBuiltin - add SSE/AVX VPTEST/VTESTPD/VTESTPS intrinsics to be used in constexpr (#160428)
Fix #158653 Add handling for: ``` ptestz128 / ptestz256 → (a & b) == 0. ptestc128 / ptestc256 → (~a & b) == 0 ptestnzc128 / ptestnzc256 → (a & b) != 0 AND (~a & b) != 0. vtestzps / vtestzps256 → (S(a) & S(b)) == 0. vtestcps / vtestcps256 → (~S(a) & S(b)) == 0. vtestnzcps / vtestnzcps256 → (S(a) & S(b)) != 0 AND (~S(a) & S(b)) != 0. vtestzpd / vtestzpd256 → (S(a) & S(b)) == 0. vtestcpd / vtestcpd256 → (~S(a) & S(b)) == 0. vtestnzcpd / vtestnzcpd256 → (S(a) & S(b)) != 0 AND (~S(a) & S(b)) != 0. ``` Add corresponding test cases for: ``` int _mm_test_all_ones (__m128i a) int _mm_test_all_zeros (__m128i mask, __m128i a) int _mm_test_mix_ones_zeros (__m128i mask, __m128i a) int _mm_testc_pd (__m128d a, __m128d b) int _mm256_testc_pd (__m256d a, __m256d b) int _mm_testc_ps (__m128 a, __m128 b) int _mm256_testc_ps (__m256 a, __m256 b) int _mm_testc_si128 (__m128i a, __m128i b) int _mm256_testc_si256 (__m256i a, __m256i b) int _mm_testnzc_pd (__m128d a, __m128d b) int _mm256_testnzc_pd (__m256d a, __m256d b) int _mm_testnzc_ps (__m128 a, __m128 b) int _mm256_testnzc_ps (__m256 a, __m256 b) int _mm_testnzc_si128 (__m128i a, __m128i b) int _mm256_testnzc_si256 (__m256i a, __m256i b) int _mm_testz_pd (__m128d a, __m128d b) int _mm256_testz_pd (__m256d a, __m256d b) int _mm_testz_ps (__m128 a, __m128 b) int _mm256_testz_ps (__m256 a, __m256 b) int _mm_testz_si128 (__m128i a, __m128i b) int _mm256_testz_si256 (__m256i a, __m256i b) ```
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp63
1 files changed, 62 insertions, 1 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 35a866ea5010..a3037c3f8433 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13905,6 +13905,40 @@ static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
+ auto EvalTestOp = [&](llvm::function_ref<bool(const APInt &, const APInt &)>
+ Fn) {
+ APValue SourceLHS, SourceRHS;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
+ return false;
+
+ unsigned SourceLen = SourceLHS.getVectorLength();
+ const VectorType *VT = E->getArg(0)->getType()->castAs<VectorType>();
+ QualType ElemQT = VT->getElementType();
+ unsigned LaneWidth = Info.Ctx.getTypeSize(ElemQT);
+
+ APInt AWide(LaneWidth * SourceLen, 0);
+ APInt BWide(LaneWidth * SourceLen, 0);
+
+ for (unsigned I = 0; I != SourceLen; ++I) {
+ APInt ALane;
+ APInt BLane;
+ if (ElemQT->isIntegerType()) { // Get value.
+ ALane = SourceLHS.getVectorElt(I).getInt();
+ BLane = SourceRHS.getVectorElt(I).getInt();
+ } else if (ElemQT->isFloatingType()) { // Get only sign bit.
+ ALane =
+ SourceLHS.getVectorElt(I).getFloat().bitcastToAPInt().isNegative();
+ BLane =
+ SourceRHS.getVectorElt(I).getFloat().bitcastToAPInt().isNegative();
+ } else { // Must be integer or floating type.
+ return false;
+ }
+ AWide.insertBits(ALane, I * LaneWidth);
+ BWide.insertBits(BLane, I * LaneWidth);
+ }
+ return Success(Fn(AWide, BWide), E);
+ };
auto HandleMaskBinOp =
[&](llvm::function_ref<APSInt(const APSInt &, const APSInt &)> Fn)
@@ -15018,7 +15052,34 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
Result.setBitVal(P++, Val[I]);
return Success(Result, E);
}
-
+ case X86::BI__builtin_ia32_ptestz128:
+ case X86::BI__builtin_ia32_ptestz256:
+ case X86::BI__builtin_ia32_vtestzps:
+ case X86::BI__builtin_ia32_vtestzps256:
+ case X86::BI__builtin_ia32_vtestzpd:
+ case X86::BI__builtin_ia32_vtestzpd256: {
+ return EvalTestOp(
+ [](const APInt &A, const APInt &B) { return (A & B) == 0; });
+ }
+ case X86::BI__builtin_ia32_ptestc128:
+ case X86::BI__builtin_ia32_ptestc256:
+ case X86::BI__builtin_ia32_vtestcps:
+ case X86::BI__builtin_ia32_vtestcps256:
+ case X86::BI__builtin_ia32_vtestcpd:
+ case X86::BI__builtin_ia32_vtestcpd256: {
+ return EvalTestOp(
+ [](const APInt &A, const APInt &B) { return (~A & B) == 0; });
+ }
+ case X86::BI__builtin_ia32_ptestnzc128:
+ case X86::BI__builtin_ia32_ptestnzc256:
+ case X86::BI__builtin_ia32_vtestnzcps:
+ case X86::BI__builtin_ia32_vtestnzcps256:
+ case X86::BI__builtin_ia32_vtestnzcpd:
+ case X86::BI__builtin_ia32_vtestnzcpd256: {
+ return EvalTestOp([](const APInt &A, const APInt &B) {
+ return ((A & B) != 0) && ((~A & B) != 0);
+ });
+ }
case X86::BI__builtin_ia32_kandqi:
case X86::BI__builtin_ia32_kandhi:
case X86::BI__builtin_ia32_kandsi: