This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] Have assert macros


Hi,
I did some measurements to determine how much leaving in our self checking
mechanism of the form
    if (expr)
      abort()
was costing us in compilation speed.  I built 4 --disable-checking
compilers, with the following tweaks
0) baseline
1) #define abort to no-op, thus allowing the optimizer can remove the
controlling expression
2) #define abort to no-op and g++'s my_friendly_assert to no-op
3) Leave abort alone, but #define my_friendly_assert to
   __builtin_constant_p (expr) && !expr ? abort() :  0
  thus removing the runtime-checked asserts but leaving in the compile
time checked asserts.

The results I got for cc1plus on an i686-pc-linux-gnu system were (for the
two sets of flags)
    -g -O0      -g -O2          textsize
#0   2.75      2.81            4,582,627
#1   2.79(+1.5%)  2.77(-1.5%)    4,488,595(-2.0%)
#2   2.74(-0.5%)  2.79(-0.8%)    4,468,467(-2.5%)
#3   2.71(-1.5%)  2.74(-2.5%)    4,565,603(-0.5%)

As you can see, all but unoptimzed #1 is an improvement. Why is that one
worse?  One thing noticable about #1 is that I had many 'foo might be used
uninitialized' warnings during bootstrap.  These all come from code like
    switch (expr)
    {
      case ...
     case ...
     default: abort ();
    }
Thus, turning abort into a nop, alters cfg, such that I suspect other
value propagation-like optimizations are disabled.

you'll notice that #3 gave a 1.5% speed improvement with a 0.5% code size
reduction.  #2 gives a 2.5% code size reduction, showing how much code
could potentially be removed. If the static code size is an indication
of potential speed savings, then perhaps up to 7.5% speed improvement
would be achievable by removing the correct set of aborts (). (I suspect
this is over optimistic, but maybe 5% is acheivable.)

Thus I propose adding two macros,
    gcc_assert (EXPR)
    gcc_unreachable ()

The former would be used (with suitable condition inverstion) in place of
    if (expr)
       abort ()
It would also replace the overly cute 'my_friendly_assert'. The latter
would be used in place of
    switch (expr) {
       default: abort ();
    }
and similar situations.  gcc_assert(0) would never be used for this
purpose.

In addition, an --enable-assert configure option would be added, that would
normally be enabled, but could be explicitly disabled to remove the
gcc_assert bodies.  (This might be spelt --enable-checking=assert.) What
the default release compiler does is undecided. Even if they were to be
left in, we could certainly employ __builtin_expect to tell the compiler
what we think will happen.

The assert macro would make some hypothetical __builtin_presume intrinsic
immediately useful.  Indeed, if such a builtin already existed, I beleive
the argument for gcc_assert would be much stronger.  However, one of the
two has to be done first, and I'd like it to be gcc_assert.

The danger of disabling these assertions is that we turn ICES into
wrong-code bugs.  How many assertions will catch bugs that, if uncaught,
do not turn into segmentation faults or other fatal errors?

Conversly, having a gcc_assert macro, might well encourage more self
checking use in development compilers, and thus flush out bugs more
quickly.  I know Mark and I have been fairly liberal with using
my_friendly_assert within the C++ front end -- their use has
caught many broken preconditions.  There are current uses of
#if ENABLE_CHECKING to control some simple aborts.  Implementing gcc_assert
could remove some (many? most?) of them

I recall some opposition of the syntax from a previous time this was raised
wrt my_friendly_assert.  Support for the
    if (expr)
      abort ();
syntax was voiced.  I am at a loss to understand that, finding
    gcc_assert (!expr);
to be much more understandable.  Certainly there are cases of
    if (expr1)
      ...
    else if (expr2)
      abort ()
    else if (expr3)
      ...
where a gcc_unreachable use might well make sense.

Opinions on this proposal?

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]