https://github.com/RKSimon created https://github.com/llvm/llvm-project/pull/157137
Create a EvaluateBinOpExpr helper that each related group of elementwise binop builtins can use with their own custom callback, to help reduce the amount of duplication and avoid too much code bloat as more builtins are added. This also handles builtins which have a elementwise LHS operand and a scalar RHS operand. Similar to #155891 which did the same thing for the new ByteCode eval. >From 32f6bdf7e206a09515ce6ee7c06a85ecee5fdaa3 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim <llvm-...@redking.me.uk> Date: Fri, 5 Sep 2025 17:28:21 +0100 Subject: [PATCH] [clang] VectorExprEvaluator::VisitCallExpr - use APSInt callback instead of repeated switch statement Create a EvaluateBinOpExpr helper that each related group of elementwise binop builtins can use with their own custom callback, to help reduce the amount of duplication and avoid too much code bloat as more builtins are added. This also handles builtins which have a elementwise LHS operand and a scalar RHS operand. Similar to #155891 which did the same thing for the new ByteCode eval. --- clang/lib/AST/ExprConstant.cpp | 281 ++++++++++----------------------- 1 file changed, 86 insertions(+), 195 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 100e944f9b48c..0060e80e8e309 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11623,6 +11623,38 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); + auto EvaluateBinOpExpr = + [&](llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) { + APValue SourceLHS, SourceRHS; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || + !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) + return false; + + auto *DestTy = E->getType()->castAs<VectorType>(); + QualType DestEltTy = DestTy->getElementType(); + bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + if (SourceRHS.isInt()) { + const APSInt &RHS = SourceRHS.getInt(); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); + ResultElements.push_back( + APValue(APSInt(Fn(LHS, RHS), DestUnsigned))); + } + } else { + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); + const APSInt &RHS = SourceRHS.getVectorElt(EltNum).getInt(); + ResultElements.push_back( + APValue(APSInt(Fn(LHS, RHS), DestUnsigned))); + } + } + return Success(APValue(ResultElements.data(), SourceLen), E); + }; + switch (E->getBuiltinCallee()) { default: return false; @@ -11679,27 +11711,30 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { } case Builtin::BI__builtin_elementwise_add_sat: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + return LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS); + }); + case Builtin::BI__builtin_elementwise_sub_sat: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); + }); + case clang::X86::BI__builtin_ia32_pmulhuw128: case clang::X86::BI__builtin_ia32_pmulhuw256: case clang::X86::BI__builtin_ia32_pmulhuw512: + return EvaluateBinOpExpr(llvm::APIntOps::mulhu); + case clang::X86::BI__builtin_ia32_pmulhw128: case clang::X86::BI__builtin_ia32_pmulhw256: case clang::X86::BI__builtin_ia32_pmulhw512: + return EvaluateBinOpExpr(llvm::APIntOps::mulhs); + case clang::X86::BI__builtin_ia32_psllv2di: case clang::X86::BI__builtin_ia32_psllv4di: case clang::X86::BI__builtin_ia32_psllv4si: case clang::X86::BI__builtin_ia32_psllv8si: case clang::X86::BI__builtin_ia32_psllv16si: - case clang::X86::BI__builtin_ia32_psrav4si: - case clang::X86::BI__builtin_ia32_psrav8si: - case clang::X86::BI__builtin_ia32_psrav16si: - case clang::X86::BI__builtin_ia32_psrlv2di: - case clang::X86::BI__builtin_ia32_psrlv4di: - case clang::X86::BI__builtin_ia32_psrlv4si: - case clang::X86::BI__builtin_ia32_psrlv8si: - case clang::X86::BI__builtin_ia32_psrlv16si: - case clang::X86::BI__builtin_ia32_psllwi128: case clang::X86::BI__builtin_ia32_pslldi128: case clang::X86::BI__builtin_ia32_psllqi128: @@ -11709,17 +11744,16 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_psllwi512: case clang::X86::BI__builtin_ia32_pslldi512: case clang::X86::BI__builtin_ia32_psllqi512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return APInt::getZero(LHS.getBitWidth()); + } + return LHS.shl(RHS.getZExtValue()); + }); - case clang::X86::BI__builtin_ia32_psrlwi128: - case clang::X86::BI__builtin_ia32_psrldi128: - case clang::X86::BI__builtin_ia32_psrlqi128: - case clang::X86::BI__builtin_ia32_psrlwi256: - case clang::X86::BI__builtin_ia32_psrldi256: - case clang::X86::BI__builtin_ia32_psrlqi256: - case clang::X86::BI__builtin_ia32_psrlwi512: - case clang::X86::BI__builtin_ia32_psrldi512: - case clang::X86::BI__builtin_ia32_psrlqi512: - + case clang::X86::BI__builtin_ia32_psrav4si: + case clang::X86::BI__builtin_ia32_psrav8si: + case clang::X86::BI__builtin_ia32_psrav16si: case clang::X86::BI__builtin_ia32_psrawi128: case clang::X86::BI__builtin_ia32_psradi128: case clang::X86::BI__builtin_ia32_psraqi128: @@ -11728,145 +11762,35 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_psraqi256: case clang::X86::BI__builtin_ia32_psrawi512: case clang::X86::BI__builtin_ia32_psradi512: - case clang::X86::BI__builtin_ia32_psraqi512: { - - APValue SourceLHS, SourceRHS; - if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || - !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) - return false; - - QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); - bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); - unsigned SourceLen = SourceLHS.getVectorLength(); - SmallVector<APValue, 4> ResultElements; - ResultElements.reserve(SourceLen); - - for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { - APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); - - if (SourceRHS.isInt()) { - const unsigned LaneBitWidth = LHS.getBitWidth(); - const unsigned ShiftAmount = SourceRHS.getInt().getZExtValue(); - - switch (E->getBuiltinCallee()) { - case clang::X86::BI__builtin_ia32_psllwi128: - case clang::X86::BI__builtin_ia32_psllwi256: - case clang::X86::BI__builtin_ia32_psllwi512: - case clang::X86::BI__builtin_ia32_pslldi128: - case clang::X86::BI__builtin_ia32_pslldi256: - case clang::X86::BI__builtin_ia32_pslldi512: - case clang::X86::BI__builtin_ia32_psllqi128: - case clang::X86::BI__builtin_ia32_psllqi256: - case clang::X86::BI__builtin_ia32_psllqi512: - if (ShiftAmount >= LaneBitWidth) { - ResultElements.push_back( - APValue(APSInt(APInt::getZero(LaneBitWidth), DestUnsigned))); - } else { - ResultElements.push_back( - APValue(APSInt(LHS.shl(ShiftAmount), DestUnsigned))); - } - break; - case clang::X86::BI__builtin_ia32_psrlwi128: - case clang::X86::BI__builtin_ia32_psrlwi256: - case clang::X86::BI__builtin_ia32_psrlwi512: - case clang::X86::BI__builtin_ia32_psrldi128: - case clang::X86::BI__builtin_ia32_psrldi256: - case clang::X86::BI__builtin_ia32_psrldi512: - case clang::X86::BI__builtin_ia32_psrlqi128: - case clang::X86::BI__builtin_ia32_psrlqi256: - case clang::X86::BI__builtin_ia32_psrlqi512: - if (ShiftAmount >= LaneBitWidth) { - ResultElements.push_back( - APValue(APSInt(APInt::getZero(LaneBitWidth), DestUnsigned))); - } else { - ResultElements.push_back( - APValue(APSInt(LHS.lshr(ShiftAmount), DestUnsigned))); - } - break; - case clang::X86::BI__builtin_ia32_psrawi128: - case clang::X86::BI__builtin_ia32_psrawi256: - case clang::X86::BI__builtin_ia32_psrawi512: - case clang::X86::BI__builtin_ia32_psradi128: - case clang::X86::BI__builtin_ia32_psradi256: - case clang::X86::BI__builtin_ia32_psradi512: - case clang::X86::BI__builtin_ia32_psraqi128: - case clang::X86::BI__builtin_ia32_psraqi256: - case clang::X86::BI__builtin_ia32_psraqi512: - ResultElements.push_back( - APValue(APSInt(LHS.ashr(std::min(ShiftAmount, LaneBitWidth - 1)), - DestUnsigned))); - break; - default: - llvm_unreachable("Unexpected builtin callee"); - } - continue; + case clang::X86::BI__builtin_ia32_psraqi512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return LHS.ashr(LHS.getBitWidth() - 1); } - APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt(); - switch (E->getBuiltinCallee()) { - case Builtin::BI__builtin_elementwise_add_sat: - ResultElements.push_back(APValue( - APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS), - DestUnsigned))); - break; - case Builtin::BI__builtin_elementwise_sub_sat: - ResultElements.push_back(APValue( - APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS), - DestUnsigned))); - break; - case clang::X86::BI__builtin_ia32_pmulhuw128: - case clang::X86::BI__builtin_ia32_pmulhuw256: - case clang::X86::BI__builtin_ia32_pmulhuw512: - ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhu(LHS, RHS), - /*isUnsigned=*/true))); - break; - case clang::X86::BI__builtin_ia32_pmulhw128: - case clang::X86::BI__builtin_ia32_pmulhw256: - case clang::X86::BI__builtin_ia32_pmulhw512: - ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS), - /*isUnsigned=*/false))); - break; - case clang::X86::BI__builtin_ia32_psllv2di: - case clang::X86::BI__builtin_ia32_psllv4di: - case clang::X86::BI__builtin_ia32_psllv4si: - case clang::X86::BI__builtin_ia32_psllv8si: - case clang::X86::BI__builtin_ia32_psllv16si: - if (RHS.uge(RHS.getBitWidth())) { - ResultElements.push_back( - APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned))); - break; - } - ResultElements.push_back( - APValue(APSInt(LHS.shl(RHS.getZExtValue()), DestUnsigned))); - break; - case clang::X86::BI__builtin_ia32_psrav4si: - case clang::X86::BI__builtin_ia32_psrav8si: - case clang::X86::BI__builtin_ia32_psrav16si: - if (RHS.uge(RHS.getBitWidth())) { - ResultElements.push_back( - APValue(APSInt(LHS.ashr(RHS.getBitWidth() - 1), DestUnsigned))); - break; - } - ResultElements.push_back( - APValue(APSInt(LHS.ashr(RHS.getZExtValue()), DestUnsigned))); - break; - case clang::X86::BI__builtin_ia32_psrlv2di: - case clang::X86::BI__builtin_ia32_psrlv4di: - case clang::X86::BI__builtin_ia32_psrlv4si: - case clang::X86::BI__builtin_ia32_psrlv8si: - case clang::X86::BI__builtin_ia32_psrlv16si: - if (RHS.uge(RHS.getBitWidth())) { - ResultElements.push_back( - APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned))); - break; - } - ResultElements.push_back( - APValue(APSInt(LHS.lshr(RHS.getZExtValue()), DestUnsigned))); - break; + return LHS.ashr(RHS.getZExtValue()); + }); + + case clang::X86::BI__builtin_ia32_psrlv2di: + case clang::X86::BI__builtin_ia32_psrlv4di: + case clang::X86::BI__builtin_ia32_psrlv4si: + case clang::X86::BI__builtin_ia32_psrlv8si: + case clang::X86::BI__builtin_ia32_psrlv16si: + case clang::X86::BI__builtin_ia32_psrlwi128: + case clang::X86::BI__builtin_ia32_psrldi128: + case clang::X86::BI__builtin_ia32_psrlqi128: + case clang::X86::BI__builtin_ia32_psrlwi256: + case clang::X86::BI__builtin_ia32_psrldi256: + case clang::X86::BI__builtin_ia32_psrlqi256: + case clang::X86::BI__builtin_ia32_psrlwi512: + case clang::X86::BI__builtin_ia32_psrldi512: + case clang::X86::BI__builtin_ia32_psrlqi512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return APInt::getZero(LHS.getBitWidth()); } - } + return LHS.lshr(RHS.getZExtValue()); + }); - return Success(APValue(ResultElements.data(), ResultElements.size()), E); - } case clang::X86::BI__builtin_ia32_pmuldq128: case clang::X86::BI__builtin_ia32_pmuldq256: case clang::X86::BI__builtin_ia32_pmuldq512: @@ -11904,6 +11828,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + case clang::X86::BI__builtin_ia32_vprotbi: case clang::X86::BI__builtin_ia32_vprotdi: case clang::X86::BI__builtin_ia32_vprotqi: @@ -11913,53 +11838,19 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_prold512: case clang::X86::BI__builtin_ia32_prolq128: case clang::X86::BI__builtin_ia32_prolq256: - case clang::X86::BI__builtin_ia32_prolq512: { - APValue SourceLHS, SourceRHS; - if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || - !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) - return false; - - QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); - bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); - unsigned SourceLen = SourceLHS.getVectorLength(); - SmallVector<APValue, 4> ResultElements; - ResultElements.reserve(SourceLen); - - APSInt RHS = SourceRHS.getInt(); - - for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { - const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); - ResultElements.push_back(APValue(APSInt(LHS.rotl(RHS), DestUnsigned))); - } + case clang::X86::BI__builtin_ia32_prolq512: + return EvaluateBinOpExpr( + [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotl(RHS); }); - return Success(APValue(ResultElements.data(), ResultElements.size()), E); - } case clang::X86::BI__builtin_ia32_prord128: case clang::X86::BI__builtin_ia32_prord256: case clang::X86::BI__builtin_ia32_prord512: case clang::X86::BI__builtin_ia32_prorq128: case clang::X86::BI__builtin_ia32_prorq256: - case clang::X86::BI__builtin_ia32_prorq512: { - APValue SourceLHS, SourceRHS; - if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || - !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) - return false; + case clang::X86::BI__builtin_ia32_prorq512: + return EvaluateBinOpExpr( + [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotr(RHS); }); - QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); - bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); - unsigned SourceLen = SourceLHS.getVectorLength(); - SmallVector<APValue, 4> ResultElements; - ResultElements.reserve(SourceLen); - - APSInt RHS = SourceRHS.getInt(); - - for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { - const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); - ResultElements.push_back(APValue(APSInt(LHS.rotr(RHS), DestUnsigned))); - } - - return Success(APValue(ResultElements.data(), ResultElements.size()), E); - } case Builtin::BI__builtin_elementwise_max: case Builtin::BI__builtin_elementwise_min: { APValue SourceLHS, SourceRHS; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits