https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115639

            Bug ID: 115639
           Summary: Large variations in compilation times involving
                    static_assert
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: pkeir at outlook dot com
  Target Milestone: ---

I often want to be sure that an expression is evaluated at compile time, while
also checking that it produces the expected value. With a `constexpr` function
called `big_calc`, expected to return zero, I might either use:

static_assert(0==big_calc());    // (1)

...or:

constexpr int ret = big_calc();  // (2)
static_assert(0==ret);

Surprisingly, the first of these (1) takes around 76% longer than the second
(2) to compile.

constexpr int big_calc()
{
  long i = 1, count = 0, n = (1<<22);

  for (; i < n; i++)
    count = count + i;

  bool b = count == (i * (i - 1)) / 2;

  return 0;
}

This is true even when `big_calc` involves more calculations. I am using Ubuntu
24.04 with an Intel i9-13900K, and g++ (GCC) 15.0.0 20240623 (experimental).
With `n` of `big_calc` set at `(1<<22)` (as above) average compilation times
are 6.5 secs. for approach (1); and 3.7 secs. for approach (2).

With `n` of `big_calc` set at `(1<<24)` average compilation times are 28.3
secs. for approach (1); and 16.2 secs. for approach (2).

time /opt/gcc-latest/bin/g++ -std=c++20
performance-bug-double-constant-eval.cpp -fconstexpr-ops-limit=$((2**31-1))
-fconstexpr-loop-limit=$((2**31-1))

Other approaches to invoke `big_calc` (e.g. SFINAE/Concepts class/function
templates) are also slow; and have the performance profile of method (1).

Perhaps the constant expression is being evaluated twice.

It does look odd that the `big_calc` function returns zero. This was reduced
from a larger problem. Curiously, if `big_calc` instead returns a boolean (i.e.
`b`), and the `0==` part of each constant expression is removed, the issue
disappears.

This is reminiscent of a recently resolved Clang issue
(https://github.com/llvm/llvm-project/issues/92924), though with 2 notable
differences: firstly, with GCC the problem only arises when the `big_calc`
function is actually invoked; and secondly, the `-Wno-invalid-constexpr` flag
makes no difference to the performance with GCC.

Reply via email to