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

Hubert Tong via cfe-commits cfe-commits at lists.llvm.org
Sat May 9 21:50:42 PDT 2026


================
@@ -0,0 +1,309 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify -std=c++20 %s
+// RUN: %clang_cc1 -verify -std=c++20 %s
+
+
+
+static_assert(__builtin_nearbyint(1.1) == 1.0);
+static_assert(__builtin_nearbyint(1.9) == 2.0);
+static_assert(__builtin_nearbyint(-1.1) == -1.0);
+static_assert(__builtin_nearbyint(-1.9) == -2.0);
+
+static_assert(__builtin_nearbyintf(1.1f) == 1.0f);
+static_assert(__builtin_nearbyintl(1.1l) == 1.0l);
+static_assert(__builtin_nearbyintf16(1.1f16) == 1.0f16);
+static_assert(__builtin_nearbyintf128(1.1) == 1.0);
+static_assert(__builtin_isnan(__builtin_nearbyint(__builtin_nan(""))));
+static_assert(__builtin_isinf(__builtin_nearbyint(__builtin_inf())));
+
+// Test ties to even (default rounding mode)
+static_assert(__builtin_nearbyint(1.5) == 2.0);
+static_assert(__builtin_nearbyint(2.5) == 2.0);
+
+// rint tests
+static_assert(__builtin_rint(1.1) == 1.0);
+static_assert(__builtin_rint(1.9) == 2.0);
+static_assert(__builtin_rintf(1.1f) == 1.0f);
+static_assert(__builtin_rintl(1.1l) == 1.0l);
+static_assert(__builtin_rintf16(1.1f16) == 1.0f16);
+static_assert(__builtin_rintf128(1.1) == 1.0);
+static_assert(__builtin_isnan(__builtin_rint(__builtin_nan(""))));
+static_assert(__builtin_isinf(__builtin_rint(__builtin_inf())));
+
+// lrint tests
+static_assert(__builtin_lrint(1.1) == 1);
+static_assert(__builtin_lrint(1.9) == 2);
+static_assert(__builtin_lrintf(1.1f) == 1);
+static_assert(__builtin_lrintl(1.1l) == 1);
+static_assert(__builtin_lrintf128(1.1) == 1);
+
+// llrint tests
+static_assert(__builtin_llrint(1.1) == 1LL);
+static_assert(__builtin_llrint(1.9) == 2LL);
+static_assert(__builtin_llrintf(1.1f) == 1LL);
+static_assert(__builtin_llrintl(1.1l) == 1LL);
+static_assert(__builtin_llrintf128(1.1) == 1LL);
+
+// round tests
+static_assert(__builtin_round(1.1) == 1.0);
+static_assert(__builtin_round(1.5) == 2.0);
+static_assert(__builtin_round(1.9) == 2.0);
+static_assert(__builtin_round(-1.5) == -2.0);
+static_assert(__builtin_roundf16(1.5f16) == 2.0f16);
+static_assert(__builtin_roundf128(1.5) == 2.0);
+static_assert(__builtin_isnan(__builtin_round(__builtin_nan(""))));
+static_assert(__builtin_isinf(__builtin_round(__builtin_inf())));
+
+// lround tests
+static_assert(__builtin_lround(1.1) == 1);
+static_assert(__builtin_lround(1.5) == 2);
+static_assert(__builtin_lround(-1.5) == -2);
+static_assert(__builtin_lroundf128(1.5) == 2);
+
+// llround tests
+static_assert(__builtin_llround(1.1) == 1LL);
+static_assert(__builtin_llround(1.5) == 2LL);
+static_assert(__builtin_llround(-1.5) == -2LL);
+static_assert(__builtin_llroundf128(1.5) == 2LL);
+
+// ceil tests
+static_assert(__builtin_ceil(1.1) == 2.0);
+static_assert(__builtin_ceil(-1.1) == -1.0);
+static_assert(__builtin_ceilf(1.1f) == 2.0f);
+static_assert(__builtin_ceilf16(1.1f16) == 2.0f16);
+static_assert(__builtin_ceilf128(1.1) == 2.0);
+static_assert(__builtin_isnan(__builtin_ceil(__builtin_nan(""))));
+static_assert(__builtin_isinf(__builtin_ceil(__builtin_inf())));
+
+// floor tests
+static_assert(__builtin_floor(1.1) == 1.0);
+static_assert(__builtin_floor(-1.1) == -2.0);
+static_assert(__builtin_floorf(1.1f) == 1.0f);
+static_assert(__builtin_floorf16(1.1f16) == 1.0f16);
+static_assert(__builtin_floorf128(1.1) == 1.0);
+static_assert(__builtin_isnan(__builtin_floor(__builtin_nan(""))));
+static_assert(__builtin_isinf(__builtin_floor(__builtin_inf())));
+
+// trunc tests
+static_assert(__builtin_trunc(1.1) == 1.0);
+static_assert(__builtin_trunc(-1.1) == -1.0);
+static_assert(__builtin_truncf(1.1f) == 1.0f);
+static_assert(__builtin_truncf16(1.1f16) == 1.0f16);
+static_assert(__builtin_truncf128(1.1) == 1.0);
+static_assert(__builtin_isnan(__builtin_trunc(__builtin_nan(""))));
+static_assert(__builtin_isinf(__builtin_trunc(__builtin_inf())));
+
+// roundeven tests
+static_assert(__builtin_roundeven(1.5) == 2.0);
+static_assert(__builtin_roundeven(2.5) == 2.0);
+static_assert(__builtin_roundeven(-1.5) == -2.0);
+static_assert(__builtin_roundeven(-2.5) == -2.0);
+static_assert(__builtin_roundevenf(1.5f) == 2.0f);
+static_assert(__builtin_roundevenl(1.5l) == 2.0l);
+static_assert(__builtin_roundevenf128(1.5) == 2.0);
+static_assert(__builtin_roundeven(0.5) == 0.0);
+static_assert(__builtin_roundeven(-0.5) == -0.0);
+static_assert(__builtin_isnan(__builtin_roundeven(__builtin_nan(""))));
+static_assert(__builtin_isinf(__builtin_roundeven(__builtin_inf())));
+
+// fdim tests
----------------
hubert-reinterpretcast wrote:

Note considerations for `FENV_ACCESS`, etc. discussed in https://github.com/llvm/llvm-project/pull/158048#issuecomment-3313760151.

In particular, the `-Wsometimes-uninitialized` warning should trigger on:
```cpp
#pragma STDC FENV_ACCESS ON
int main(void) {
  int i;
  if (__builtin_fdim(__DBL_EPSILON__ / 2., -1.) == 1.) {
    i = 42;
  }
  return i;
}
```

With this PR, it currently triggers except when `-fexperimental-new-constant-interpreter` is used.

I think a codegen test with `FENV_ACCESS ON` and expecting (for all of the functions with any rounding-mode dependence) that folding does not occur (at least for values where the rounded result is inexact) is needed. The test can optionally expect folding for functions that have no rounding-mode dependence.

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


More information about the cfe-commits mailing list