This is the mail archive of the gcc-patches@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/PATCH] Optimize code based on asserts even in NDEBUG mode


This patch optimizes code in NDEBUG mode based on the conditions
that the program asserts.  This patch, in other words, allows a
function like this

 #include <assert.h>
 #define NDEBUG

 int f(char *x)
 {
   assert (x != NULL);
   return x ? *x : 0;
 }

to be compiled simply as

        movl    4(%esp), %eax
        movsbl  (%eax), %eax
        ret

The trick is to have assert invoke a const/noreturn function (returning
void) in NDEBUG mode, and to remove such invocations in ifcvt.  I see
that this may likely not be the best way, hence the RFC.  To link
this to assert, there will be a GCC-specific assert.h like

#ifndef __GCC_ASSERT_H
#define __GCC_ASSERT_H

#include_next <assert.h>

#if defined __OPTIMIZE__ && defined NDEBUG
#undef assert
extern void __gcc_verify (void) __attribute__ ((__const__, __noreturn__));
#define assert(expr)  ((void) ((expr) ? 0 : (__gcc_verify(), 0)))
#endif
#endif

Is this crap?

Paolo

2004-04-09  Paolo Bonzini  <bonzini@gnu.org>

        * Makefile.in (ifcvt.o): Add tree.h dependency.
        (USER_H): Add assert.h.
        * calls.c (flags_from_decl_or_type): Leave there ECF_CONST
        on a noreturn function.
        (expand_call): Expand a call to a const, noreturn function.
        We need it to propagate known information about assertions.
        * ifcvt.c (noce_process_if_block): Remove a block
        with an unchanging call to a void function, and
        without successors.  Include tree.h.

--- gcc-save/gcc/calls.c 2004-02-06 07:18:11.000000000 +0100
+++ gcc/gcc/calls.c 2004-04-09 03:27:00.000000000 +0200
@@ -729,7 +729,7 @@
  flags |= ECF_LIBCALL_BLOCK;
     }

-  if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
+  if (TREE_READONLY (exp))
     flags |= ECF_CONST;

   if (TREE_THIS_VOLATILE (exp))
@@ -2242,6 +2242,7 @@
      and none of its arguments are volatile, we can avoid expanding the
      call and just evaluate the arguments for side-effects.  */
   if ((flags & (ECF_CONST | ECF_PURE))
+      && !(flags & ECF_NORETURN)
       && (ignore || target == const0_rtx
    || TYPE_MODE (TREE_TYPE (exp)) == VOIDmode))
     {
--- gcc-save/gcc/ifcvt.c 2004-01-31 03:06:47.000000000 +0100
+++ gcc/gcc/ifcvt.c 2004-04-09 05:13:23.000000000 +0200
@@ -23,6 +23,7 @@
 #include "coretypes.h"
 #include "tm.h"

+#include "tree.h"
 #include "rtl.h"
 #include "regs.h"
 #include "function.h"
@@ -1841,8 +1842,33 @@
   if (GET_MODE (XEXP (cond, 0)) == BLKmode)
     return FALSE;

-  /* Look for one of the potential sets.  */
   insn_a = first_active_insn (then_bb);
+
+  /* Look for a const noreturn CALL_INSN, i.e. an assert in NDEBUG mode.  */
+  if (insn_a
+      && !then_bb->succ
+      && !else_bb
+      && GET_CODE (insn_a) == CALL_INSN
+      && CONST_OR_PURE_CALL_P (insn_a)
+      && GET_CODE (NEXT_INSN (insn_a)) == BARRIER
+      && GET_CODE (XEXP (XEXP (PATTERN (insn_a), 0), 0)) == SYMBOL_REF)
+    {
+      /* Extract the FUNCTION_DECL.  From it, extract is type and then
+         its return type.  If it is void, remove the whole if block --
+         information about the assertion has already been propagated.  */
+      tree decl = X0TREE (XEXP (XEXP (PATTERN (insn_a), 0), 0), 2);
+      if (decl
+          && DECL_P (decl)
+          && TYPE_MODE (TREE_TYPE (TREE_TYPE (decl))) == VOIDmode)
+        {
+          delete_insn (jump);
+          delete_insn (insn_a);
+          merge_if_block (ce_info);
+          return TRUE;
+        }
+    }
+
+  /* Look for one of the potential sets.  */
   if (! insn_a
       || insn_a != last_active_insn (then_bb, FALSE)
       || (set_a = single_set (insn_a)) == NULL_RTX)
--- gcc-save/gcc/Makefile.in 2004-02-08 00:45:21.000000000 +0100
+++ gcc/gcc/Makefile.in 2004-04-09 05:37:57.000000000 +0200
@@ -282,6 +282,7 @@
   $(srcdir)/ginclude/stdarg.h \
   $(srcdir)/ginclude/stdbool.h \
   $(srcdir)/ginclude/stddef.h \
+  $(srcdir)/ginclude/assert.h \
   $(srcdir)/ginclude/varargs.h \
   $(srcdir)/unwind.h \
   $(EXTRA_HEADERS)
@@ -1840,7 +1841,7 @@
 ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(REGS_H) toplev.h flags.h insn-config.h function.h $(RECOG_H) $(TARGET_H)
\
    $(BASIC_BLOCK_H) $(EXPR_H) output.h except.h $(TM_P_H) real.h $(OPTABS_H)
\
-   cfgloop.h
+   cfgloop.h $(TREE_H)
 params.o : params.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(PARAMS_H)
toplev.h
 hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(HOOKS_H)
 pretty-print.o: $(CONFIG_H) $(SYSTEM_H) pretty-print.c $(PRETTY_PRINT_H)



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