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

Reply via email to