[clang] [Clang] Add constexpr eval for cmath builtins (PR #194327)

via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 29 09:27:25 PDT 2026


================
@@ -717,6 +717,336 @@ static inline Floating abs(InterpState &S, const Floating &In) {
   return Output;
 }
 
+static bool interp__builtin_ceil(InterpState &S, CodePtr OpPC,
+                                 const InterpFrame *Frame, const CallExpr *Call,
+                                 unsigned BuiltinOp) {
+  const Floating &Val = S.Stk.pop<Floating>();
+  Floating Result = S.allocFloat(Val.getSemantics());
+  APFloat F = Val.getAPFloat();
+
+  llvm::RoundingMode RM;
+  switch (BuiltinOp) {
+  case Builtin::BI__builtin_ceil:
+  case Builtin::BI__builtin_ceilf:
+  case Builtin::BI__builtin_ceill:
+  case Builtin::BI__builtin_ceilf16:
+  case Builtin::BI__builtin_ceilf128:
+    RM = llvm::RoundingMode::TowardPositive;
+    break;
+  case Builtin::BI__builtin_floor:
+  case Builtin::BI__builtin_floorf:
+  case Builtin::BI__builtin_floorl:
+  case Builtin::BI__builtin_floorf16:
+  case Builtin::BI__builtin_floorf128:
+    RM = llvm::RoundingMode::TowardNegative;
+    break;
+  case Builtin::BI__builtin_trunc:
+  case Builtin::BI__builtin_truncf:
+  case Builtin::BI__builtin_truncl:
+  case Builtin::BI__builtin_truncf16:
+  case Builtin::BI__builtin_truncf128:
+    RM = llvm::RoundingMode::TowardZero;
+    break;
+  default:
+    llvm_unreachable("invalid builtin ID");
+  }
+
+  F.roundToIntegral(RM);
+  Result.copy(F);
+  S.Stk.push<Floating>(Result);
+  return true;
+}
+
+static bool interp__builtin_fdim(InterpState &S, CodePtr OpPC,
+                                 const InterpFrame *Frame,
+                                 const CallExpr *Call) {
+  const Floating &RHS = S.Stk.pop<Floating>();
+  const Floating &LHS = S.Stk.pop<Floating>();
+  APFloat L = LHS.getAPFloat();
+  APFloat R = RHS.getAPFloat();
+  APFloat Result(L.getSemantics());
+
+  if (L.compare(R) == APFloat::cmpGreaterThan) {
+    L.subtract(R, APFloat::rmNearestTiesToEven);
+    Result = L;
+  } else if (L.isNaN() || R.isNaN()) {
+    L.add(R, APFloat::rmNearestTiesToEven);
+    Result = L;
+  } else {
+    Result = APFloat::getZero(L.getSemantics());
+  }
+
+  Floating F = S.allocFloat(Result.getSemantics());
+  F.copy(Result);
+  S.Stk.push<Floating>(F);
+  return true;
+}
+
+static bool interp__builtin_fma(InterpState &S, CodePtr OpPC,
+                                const InterpFrame *Frame,
+                                const CallExpr *Call) {
+  const Floating &Z = S.Stk.pop<Floating>();
+  const Floating &Y = S.Stk.pop<Floating>();
+  const Floating &X = S.Stk.pop<Floating>();
+  APFloat Result = X.getAPFloat();
+
+  llvm::RoundingMode RM =
+      getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts()));
+
+  Result.fusedMultiplyAdd(Y.getAPFloat(), Z.getAPFloat(), RM);
+  Floating F = S.allocFloat(Result.getSemantics());
+  F.copy(Result);
+  S.Stk.push<Floating>(F);
+  return true;
+}
+
+static bool interp__builtin_frexp(InterpState &S, CodePtr OpPC,
+                                  const InterpFrame *Frame,
+                                  const CallExpr *Call) {
+  const Pointer &Ptr = S.Stk.pop<Pointer>();
+  const Floating &Val = S.Stk.pop<Floating>();
+
+  int Exp = 0;
+  llvm::RoundingMode RM =
+      getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts()));
+
+  APFloat F = frexp(Val.getAPFloat(), Exp, RM);
+
+  if (!Ptr.isDummy()) {
+    QualType ExpType = Call->getArg(1)->getType()->getPointeeType();
+    PrimType ExpT = *S.getContext().classify(ExpType);
+    assignIntegral(S, Ptr, ExpT, APSInt::get(Exp));
+    Ptr.initialize();
+  }
+
+  Floating Result = S.allocFloat(F.getSemantics());
+  Result.copy(F);
+  S.Stk.push<Floating>(Result);
+  return true;
+}
+
+static bool interp__builtin_modf(InterpState &S, CodePtr OpPC,
+                                 const InterpFrame *Frame,
+                                 const CallExpr *Call) {
+  const Pointer &Ptr = S.Stk.pop<Pointer>();
+  const Floating &Val = S.Stk.pop<Floating>();
+  const APFloat &F = Val.getAPFloat();
+
+  APFloat Integral = F;
+  Integral.roundToIntegral(APFloat::rmTowardZero);
+
+  if (!Ptr.isDummy()) {
+    Ptr.deref<Floating>().copy(Integral);
+    Ptr.initialize();
+  }
+
+  if (F.isInfinity()) {
+    Floating Fraction = S.allocFloat(F.getSemantics());
+    Fraction.copy(APFloat::getZero(F.getSemantics(), F.isNegative()));
+    S.Stk.push<Floating>(Fraction);
+    return true;
+  }
+
+  APFloat Fraction = F;
+  Fraction.subtract(Integral, APFloat::rmNearestTiesToEven);
+
+  Floating Result = S.allocFloat(Fraction.getSemantics());
+  Result.copy(Fraction);
+  S.Stk.push<Floating>(Result);
+  return true;
+}
+
+static bool interp__builtin_fmod(InterpState &S, CodePtr OpPC,
+                                 const InterpFrame *Frame, const CallExpr *Call,
+                                 unsigned BuiltinOp) {
+  const Floating &RHS = S.Stk.pop<Floating>();
+  const Floating &LHS = S.Stk.pop<Floating>();
+  const APFloat &L = LHS.getAPFloat();
+  const APFloat &R = RHS.getAPFloat();
+  APFloat ResF = L;
+
+  if (BuiltinOp == Builtin::BI__builtin_remainder ||
+      BuiltinOp == Builtin::BI__builtin_remainderf ||
+      BuiltinOp == Builtin::BI__builtin_remainderl ||
+      BuiltinOp == Builtin::BI__builtin_remainderf128)
+    ResF.remainder(R);
+  else
+    ResF.mod(R);
+
+  Floating F = S.allocFloat(ResF.getSemantics());
+  F.copy(ResF);
+  S.Stk.push<Floating>(F);
+  return true;
+}
+
+static bool interp__builtin_nextafter(InterpState &S, CodePtr OpPC,
+                                      const InterpFrame *Frame,
+                                      const CallExpr *Call) {
+  const Floating &RHS = S.Stk.pop<Floating>();
+  const Floating &LHS = S.Stk.pop<Floating>();
+  const APFloat &L = LHS.getAPFloat();
+  const APFloat &R = RHS.getAPFloat();
+
+  if (L.isNaN()) {
+    S.Stk.push<Floating>(LHS);
+    return true;
+  }
+
+  if (R.isNaN()) {
+    bool LoseInfo = false;
+    APFloat NaN = R;
+    NaN.convert(L.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo);
+    Floating Result = S.allocFloat(NaN.getSemantics());
+    Result.copy(NaN);
+    S.Stk.push<Floating>(Result);
+    return true;
+  }
+
+  APFloat LCopy = L;
+  bool LoseInfo = false;
+  LCopy.convert(R.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo);
+  APFloat::cmpResult Res = LCopy.compare(R);
+
+  APFloat Next = L;
+  if (Res != APFloat::cmpEqual)
+    Next.next(Res == APFloat::cmpGreaterThan);
+
+  Floating Result = S.allocFloat(Next.getSemantics());
+  Result.copy(Next);
+  S.Stk.push<Floating>(Result);
+  return true;
+}
+
+static bool interp__builtin_scalbn(InterpState &S, CodePtr OpPC,
+                                   const InterpFrame *Frame,
+                                   const CallExpr *Call) {
+  PrimType ExpT = *S.getContext().classify(Call->getArg(1)->getType());
+  APSInt Exp;
+  if (!popToAPSInt(S.Stk, ExpT, Exp))
+    return false;
+  const Floating &Val = S.Stk.pop<Floating>();
+
+  llvm::RoundingMode RM =
+      getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts()));
+
+  Floating Result = S.allocFloat(Val.getSemantics());
+  Result.copy(scalbn(Val.getAPFloat(), (int)Exp.getExtValue(), RM));
+  S.Stk.push<Floating>(Result);
+  return true;
+}
+
+static bool interp__builtin_ilogb(InterpState &S, CodePtr OpPC,
+                                  const InterpFrame *Frame,
+                                  const CallExpr *Call) {
+  const Floating &Val = S.Stk.pop<Floating>();
+  pushInteger(S, ilogb(Val.getAPFloat()), Call->getType());
+  return true;
+}
+
+static bool interp__builtin_remquo(InterpState &S, CodePtr OpPC,
+                                   const InterpFrame *Frame,
+                                   const CallExpr *Call) {
+  const Pointer &Ptr = S.Stk.pop<Pointer>();
+  const Floating &RHS = S.Stk.pop<Floating>();
+  const Floating &LHS = S.Stk.pop<Floating>();
+
+  APFloat Q = LHS.getAPFloat();
+  if (Q.divide(RHS.getAPFloat(), APFloat::rmNearestTiesToEven) &
+      APFloat::opInvalidOp)
+    Q = APFloat::getZero(Q.getSemantics());
+  else
+    Q.roundToIntegral(APFloat::rmNearestTiesToEven);
+
+  if (!Ptr.isDummy()) {
+    QualType QuoType = Call->getArg(2)->getType()->getPointeeType();
+    APSInt QuoInt(S.getASTContext().getTypeSize(QuoType), false);
----------------
Serosh-commits wrote:

done Thanks for the cleanup

https://github.com/llvm/llvm-project/pull/194327


More information about the cfe-commits mailing list