This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RFC/PATCH] Optimize code based on asserts even in NDEBUG mode
- From: "Paolo Bonzini" <bonzini at gnu dot org>
- To: <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 9 Apr 2004 11:22:00 +0200
- Subject: [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)