https://github.com/byteforge38 created https://github.com/llvm/llvm-project/pull/178421
Update the callback signature for `EvaluateFpBinOpExpr` and `interp__builtin_elementwise_fp_binop` to return `std::optional<APFloat>`, allowing individual callbacks to decide whether to handle special floating-point cases (inf/nan/denormal). Previously, the helper functions had hardcoded validation that forced all callbacks to reject these cases. This blocked intrinsics needing custom validation (e.g., rounding mode checks). Now each callback controls its own validation and returns `std::nullopt` when the fold is invalid. Fixes #178416 >From 920c7758395f166b509eef6015661a818348d394 Mon Sep 17 00:00:00 2001 From: byteforge38 <[email protected]> Date: Wed, 28 Jan 2026 07:45:17 -0600 Subject: [PATCH] [clang][constexpr] Move inf/nan/denormal handling into FP binop callbacks --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 22 +++++++++++++++------- clang/lib/AST/ExprConstant.cpp | 23 ++++++++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 4cf6898df3692..d1f77aef6676c 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -2482,8 +2482,8 @@ static bool interp__builtin_elementwise_int_unaryop( static bool interp__builtin_elementwise_fp_binop( InterpState &S, CodePtr OpPC, const CallExpr *Call, - llvm::function_ref<APFloat(const APFloat &, const APFloat &, - std::optional<APSInt> RoundingMode)> + llvm::function_ref<std::optional<APFloat>(const APFloat &, const APFloat &, + std::optional<APSInt> RoundingMode)> Fn) { assert((Call->getNumArgs() == 2) || (Call->getNumArgs() == 3)); const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>(); @@ -2509,10 +2509,10 @@ static bool interp__builtin_elementwise_fp_binop( using T = PrimConv<PT_Float>::T; APFloat ElemA = APtr.elem<T>(ElemIdx).getAPFloat(); APFloat ElemB = BPtr.elem<T>(ElemIdx).getAPFloat(); - if (ElemA.isNaN() || ElemA.isInfinity() || ElemA.isDenormal() || - ElemB.isNaN() || ElemB.isInfinity() || ElemB.isDenormal()) + std::optional<APFloat> Result = Fn(ElemA, ElemB, RoundingMode); + if (!Result) return false; - Dst.elem<T>(ElemIdx) = static_cast<T>(Fn(ElemA, ElemB, RoundingMode)); + Dst.elem<T>(ElemIdx) = static_cast<T>(*Result); } Dst.initializeAllElements(); @@ -5822,7 +5822,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case clang::X86::BI__builtin_ia32_minph512: return interp__builtin_elementwise_fp_binop( S, OpPC, Call, - [](const APFloat &A, const APFloat &B, std::optional<APSInt>) { + [](const APFloat &A, const APFloat &B, + std::optional<APSInt>) -> std::optional<APFloat> { + if (A.isNaN() || A.isInfinity() || A.isDenormal() || B.isNaN() || + B.isInfinity() || B.isDenormal()) + return std::nullopt; if (A.isZero() && B.isZero()) return B; return llvm::minimum(A, B); @@ -5839,7 +5843,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case clang::X86::BI__builtin_ia32_maxph512: return interp__builtin_elementwise_fp_binop( S, OpPC, Call, - [](const APFloat &A, const APFloat &B, std::optional<APSInt>) { + [](const APFloat &A, const APFloat &B, + std::optional<APSInt>) -> std::optional<APFloat> { + if (A.isNaN() || A.isInfinity() || A.isDenormal() || B.isNaN() || + B.isInfinity() || B.isDenormal()) + return std::nullopt; if (A.isZero() && B.isZero()) return B; return llvm::maximum(A, B); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 857688ed8039d..4a98040112c85 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12281,8 +12281,9 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { }; auto EvaluateFpBinOpExpr = - [&](llvm::function_ref<APFloat(const APFloat &, const APFloat &, - std::optional<APSInt>)> + [&](llvm::function_ref<std::optional<APFloat>(const APFloat &, + const APFloat &, + std::optional<APSInt>)> Fn) { assert(E->getNumArgs() == 2 || E->getNumArgs() == 3); APValue A, B; @@ -12308,10 +12309,10 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { for (unsigned EltNum = 0; EltNum < NumElems; ++EltNum) { const APFloat &EltA = A.getVectorElt(EltNum).getFloat(); const APFloat &EltB = B.getVectorElt(EltNum).getFloat(); - if (EltA.isNaN() || EltA.isInfinity() || EltA.isDenormal() || - EltB.isNaN() || EltB.isInfinity() || EltB.isDenormal()) + std::optional<APFloat> Result = Fn(EltA, EltB, RoundingMode); + if (!Result) return false; - ResultElements.push_back(APValue(Fn(EltA, EltB, RoundingMode))); + ResultElements.push_back(APValue(*Result)); } return Success(APValue(ResultElements.data(), NumElems), E); }; @@ -14389,7 +14390,11 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_minph256: case clang::X86::BI__builtin_ia32_minph512: return EvaluateFpBinOpExpr( - [](const APFloat &A, const APFloat &B, std::optional<APSInt>) { + [](const APFloat &A, const APFloat &B, + std::optional<APSInt>) -> std::optional<APFloat> { + if (A.isNaN() || A.isInfinity() || A.isDenormal() || B.isNaN() || + B.isInfinity() || B.isDenormal()) + return std::nullopt; if (A.isZero() && B.isZero()) return B; return llvm::minimum(A, B); @@ -14405,7 +14410,11 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { case clang::X86::BI__builtin_ia32_maxph256: case clang::X86::BI__builtin_ia32_maxph512: return EvaluateFpBinOpExpr( - [](const APFloat &A, const APFloat &B, std::optional<APSInt>) { + [](const APFloat &A, const APFloat &B, + std::optional<APSInt>) -> std::optional<APFloat> { + if (A.isNaN() || A.isInfinity() || A.isDenormal() || B.isNaN() || + B.isInfinity() || B.isDenormal()) + return std::nullopt; if (A.isZero() && B.isZero()) return B; return llvm::maximum(A, B); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
