diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f4e5c0f20a5..e1e8fcaef8b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,7 +1,38 @@ +2002-07-29 Zack Weinberg + + * gensupport.c: Include hashtab.h. + (insn_elision, condition_table, hash_c_test, cmp_c_test, + maybe_eval_c_test): New routines and data structures to + support insn elision. + (init_md_reader): Read and initialize the condition_table. + (read_md_rtx): Discard insn patterns whose C test is provably + always false. + * gensupport.h: Declare new functions and data structures. + + * genconditions.c, dummy-conditions.c: New files. + * Makefile.in: Build genconditions; run it to construct + insn-conditions.c; build that and link it into most gen* + programs. + (HOST_SUPPORT, HOST_EARLY_SUPPORT): New variables. + (GEN): Delete, unused. + (STAGESTUFF): Update. + + * gencodes.c: (gen_insn): #define CODE_FOR_xxx equal to + CODE_FOR_nothing for all elided patterns. + (main): Tweaked to support this. + * genflags.c (gen_proto): Emit a static inline generator + function here for all elided patterns, which simply returns + NULL_RTX. + (gen_insn): Do not define HAVE_xxx for elided patterns. + (main): Tweaked to support this. No need to forward-declare + struct rtx_def. + * genrecog.c: Do not bother emitting the C test if it's known + to be true at compile time. + 2002-07-29 Mike Stump - * config.gcc (target_gtfiles): Initialize, as otherwise cross compilers hosted on - powerpc-apple-darwin6.0 won't even build. + * config.gcc (target_gtfiles): Initialize, as otherwise cross + compilers hosted on powerpc-apple-darwin6.0 won't even build. 2002-07-29 Richard Earnshaw diff --git a/gcc/Makefile.in b/gcc/Makefile.in index e256187dd34..3fdd3023e30 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -622,7 +622,9 @@ SYSLIBS = @GNAT_LIBEXC@ HOST_LIBS = $(BUILD_LIBIBERTY) HOST_RTL = $(BUILD_PREFIX)rtl.o read-rtl.o $(BUILD_PREFIX)bitmap.o \ - $(BUILD_PREFIX)ggc-none.o gensupport.o + $(BUILD_PREFIX)ggc-none.o +HOST_SUPPORT = gensupport.o insn-conditions.o +HOST_EARLY_SUPPORT = gensupport.o dummy-conditions.o HOST_PRINT = $(BUILD_PREFIX)print-rtl.o HOST_ERRORS = $(BUILD_PREFIX)errors.o @@ -742,29 +744,20 @@ OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ BACKEND = main.o libbackend.a -# GEN files are listed separately, so they can be built before doing parallel -# makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load -# them before rtl.o is compiled. -GEN= genemit$(build_exeext) genoutput$(build_exeext) genrecog$(build_exeext) \ - genextract$(build_exeext) genflags$(build_exeext) gencodes$(build_exeext) \ - genconfig$(build_exeext) genpeep$(build_exeext) gengenrtl$(build_exeext) \ - gencheck$(build_exeext) genpreds$(build_exeext) genconstants$(build_exeext) \ - gengtype$(build_exeext) - # Files to be copied away after each stage in building. STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \ insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ insn-attr.h insn-attrtab.c insn-opinit.c insn-constants.h tm-preds.h \ - tree-check.h \ + tree-check.h insn-conditions.c \ s-flags s-config s-codes s-mlib s-under s-genrtl s-gtype gtyp-gen.h \ - s-output s-recog s-emit s-extract s-peep s-check \ + s-output s-recog s-emit s-extract s-peep s-check s-conditions \ s-attr s-attrtab s-opinit s-preds s-constants s-crt0 \ genemit$(build_exeext) genoutput$(build_exeext) genrecog$(build_exeext) \ genextract$(build_exeext) genflags$(build_exeext) gencodes$(build_exeext) \ genconfig$(build_exeext) genpeep$(build_exeext) genattrtab$(build_exeext) \ genattr$(build_exeext) genopinit$(build_exeext) gengenrtl$(build_exeext) \ gencheck$(build_exeext) genpreds$(build_exeext) genconstants$(build_exeext) \ - gengtype$(build_exeext) \ + gengtype$(build_exeext) genconditions$(build_exeext) \ genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c \ xgcc$(exeext) cpp$(exeext) cc1$(exeext) $(EXTRA_PASSES) \ $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) cc1obj$(exeext) \ @@ -1698,6 +1691,21 @@ s-config : $(md_file) genconfig$(build_exeext) $(srcdir)/move-if-change $(SHELL) $(srcdir)/move-if-change tmp-config.h insn-config.h $(STAMP) s-config +insn-conditions.c: s-conditions ; @true +s-conditions : $(md_file) genconditions$(build_exeext) $(srcdir)/move-if-change + ./genconditions$(build_exeext) $(md_file) > tmp-conditions.c + $(SHELL) $(srcdir)/move-if-change tmp-conditions.c insn-conditions.c + $(STAMP) s-conditions + +insn-conditions.o : insn-conditions.c $(GCONFIG_H) $(SYSTEM_H) $(RTL_H) \ + $(TM_P_H) $(REGS_H) function.h $(RECOG_H) real.h output.h flags.h \ + hard-reg-set.h resource.h toplev.h reload.h gensupport.h insn-constants.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) insn-conditions.c + +dummy-conditions.o : dummy-conditions.c $(GCONFIG_H) $(SYSTEM_H) gensupport.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/dummy-conditions.c $(OUTPUT_OPTION) + insn-flags.h: s-flags ; @true s-flags : $(md_file) genflags$(build_exeext) $(srcdir)/move-if-change ./genflags$(build_exeext) $(md_file) > tmp-flags.h @@ -1904,88 +1912,109 @@ read-rtl.o: read-rtl.c $(HCONFIG_H) $(SYSTEM_H) $(RTL_H) \ gensupport.o: gensupport.c $(RTL_H) $(OBSTACK_H) $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gensupport.c $(OUTPUT_OPTION) -genconfig$(build_exeext) : genconfig.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genconfig$(build_exeext) : genconfig.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genconfig.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genconfig.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genconfig.o : genconfig.c $(RTL_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genconfig.c $(OUTPUT_OPTION) -genflags$(build_exeext) : genflags.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genflags$(build_exeext) : genflags.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genflags.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genflags.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genflags.o : genflags.c $(RTL_H) $(OBSTACK_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genflags.c $(OUTPUT_OPTION) -gencodes$(build_exeext) : gencodes.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +gencodes$(build_exeext) : gencodes.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - gencodes.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + gencodes.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) gencodes.o : gencodes.c $(RTL_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gencodes.c $(OUTPUT_OPTION) -genconstants$(build_exeext) : genconstants.o $(HOST_RTL) $(HOST_ERRORS) $(HOST_LIBDEPS) +genconstants$(build_exeext) : genconstants.o $(HOST_RTL) $(HOST_EARLY_SUPPORT) \ + $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genconstants.o $(HOST_RTL) $(HOST_ERRORS) $(HOST_LIBS) + genconstants.o $(HOST_EARLY_SUPPORT) $(HOST_RTL) \ + $(HOST_ERRORS) $(HOST_LIBS) genconstants.o : genconstants.c $(RTL_H) $(HCONFIG_H) $(SYSTEM_H) errors.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genconstants.c $(OUTPUT_OPTION) -genemit$(build_exeext) : genemit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genemit$(build_exeext) : genemit.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genemit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genemit.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genemit.o : genemit.c $(RTL_H) $(HCONFIG_H) $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genemit.c $(OUTPUT_OPTION) -genopinit$(build_exeext) : genopinit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genopinit$(build_exeext) : genopinit.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genopinit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genopinit.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genopinit.o : genopinit.c $(RTL_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genopinit.c $(OUTPUT_OPTION) -genrecog$(build_exeext) : genrecog.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genrecog$(build_exeext) : genrecog.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genrecog.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genrecog.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genrecog.o : genrecog.c $(RTL_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genrecog.c $(OUTPUT_OPTION) -genextract$(build_exeext) : genextract.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genextract$(build_exeext) : genextract.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genextract.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genextract.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genextract.o : genextract.c $(RTL_H) $(HCONFIG_H) \ $(SYSTEM_H) insn-config.h errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genextract.c $(OUTPUT_OPTION) -genpeep$(build_exeext) : genpeep.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genpeep$(build_exeext) : genpeep.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genpeep.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genpeep.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genpeep.o : genpeep.c $(RTL_H) $(HCONFIG_H) $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genpeep.c $(OUTPUT_OPTION) -genattr$(build_exeext) : genattr.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genattr$(build_exeext) : genattr.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genattr.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genattr.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genattr.o : genattr.c $(RTL_H) $(HCONFIG_H) $(SYSTEM_H) errors.h gensupport.h $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genattr.c $(OUTPUT_OPTION) genattrtab$(build_exeext) : genattrtab.o genautomata.o \ - $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_VARRAY) $(HOST_LIBDEPS) + $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_VARRAY) \ + $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ genattrtab.o genautomata.o \ - $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_VARRAY) \ - $(HOST_LIBS) -lm + $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) $(HOST_ERRORS) \ + $(HOST_VARRAY) $(HOST_LIBS) -lm genattrtab.o : genattrtab.c $(RTL_H) $(OBSTACK_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h $(GGC_H) gensupport.h genattrtab.h @@ -1995,9 +2024,11 @@ genautomata.o : genautomata.c $(RTL_H) $(OBSTACK_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h varray.h genattrtab.h $(HASHTAB_H) $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genautomata.c $(OUTPUT_OPTION) -genoutput$(build_exeext) : genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) +genoutput$(build_exeext) : genoutput.o $(HOST_RTL) $(HOST_SUPPORT) \ + $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS) $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ - genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS) + genoutput.o $(HOST_RTL) $(HOST_SUPPORT) $(HOST_PRINT) \ + $(HOST_ERRORS) $(HOST_LIBS) genoutput.o : genoutput.c $(RTL_H) $(HCONFIG_H) \ $(SYSTEM_H) errors.h gensupport.h @@ -2052,6 +2083,16 @@ $(srcdir)/gengtype-yacc.c: $(srcdir)/gengtype-yacc.y $(BISON) $(BISONFLAGS) -d -o gengtype-yacc.c gengtype-yacc.y || \ ( rm -f $@ && false ) ) +genconditions$(build_exeext) : genconditions.o $(HOST_EARLY_SUPPORT) \ + $(HOST_RTL) $(HOST_ERRORS) $(HOST_LIBDEPS) + $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \ + genconditions.o $(HOST_EARLY_SUPPORT) $(HOST_RTL) \ + $(HOST_ERRORS) $(HOST_LIBS) + +genconditions.o : genconditions.c $(RTL_H) $(HCONFIG_H) $(SYSTEM_H) errors.h + $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/genconditions.c $(OUTPUT_OPTION) + # # Compile the libraries to be used by gen*. # If we are not cross-building, gen* use the same .o's that cc1 will use, diff --git a/gcc/dummy-conditions.c b/gcc/dummy-conditions.c new file mode 100644 index 00000000000..157f86bd639 --- /dev/null +++ b/gcc/dummy-conditions.c @@ -0,0 +1,34 @@ +/* Support for calculating constant conditions. + Copyright (C) 2002 Free Software Foundation, Inc. + + This file is part of GNU CC. + + GNU CC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU CC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "hconfig.h" +#include "system.h" +#include "gensupport.h" + +/* MD generators that are run before insn-conditions.c exists should + link against this file instead. Currently that is genconditions + and genconstants. */ + +/* Empty conditions table to prevent link errors. */ +const struct c_test insn_conditions[1] = { { 0, 0 } }; +const size_t n_insn_conditions = 0; + +/* Disable insn elision, since it is currently impossible. */ +const int insn_elision_unavailable = 1; diff --git a/gcc/gencodes.c b/gcc/gencodes.c index 0611eecaf03..5a292821c39 100644 --- a/gcc/gencodes.c +++ b/gcc/gencodes.c @@ -28,18 +28,26 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "errors.h" #include "gensupport.h" -static void gen_insn PARAMS ((const char *, int)); +static void gen_insn PARAMS ((rtx, int)); static void -gen_insn (name, code) - const char *name; +gen_insn (insn, code) + rtx insn; int code; { + const char *name = XSTR (insn, 0); + int truth = maybe_eval_c_test (XSTR (insn, 2)); + /* Don't mention instructions whose names are the null string or begin with '*'. They are in the machine description just to be recognized. */ if (name[0] != 0 && name[0] != '*') - printf (" CODE_FOR_%s = %d,\n", name, code); + { + if (truth == 0) + printf ("#define CODE_FOR_%s CODE_FOR_nothing\n", name); + else + printf (" CODE_FOR_%s = %d,\n", name, code); + } } extern int main PARAMS ((int, char **)); @@ -53,6 +61,10 @@ main (argc, argv) progname = "gencodes"; + /* We need to see all the possibilities. Elided insns may have + direct references to CODE_FOR_xxx in C code. */ + insn_elision = 0; + if (argc <= 1) fatal ("no input file name"); @@ -80,10 +92,10 @@ enum insn_code {"); break; if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND) - gen_insn (XSTR (desc, 0), insn_code_number); + gen_insn (desc, insn_code_number); } - puts ("CODE_FOR_nothing\n\ + puts (" CODE_FOR_nothing\n\ };\n\ \n\ #endif /* GCC_INSN_CODES_H */"); diff --git a/gcc/genconditions.c b/gcc/genconditions.c new file mode 100644 index 00000000000..02f80ee478d --- /dev/null +++ b/gcc/genconditions.c @@ -0,0 +1,240 @@ +/* Process machine description and calculate constant conditions. + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + + This file is part of GNU CC. + + GNU CC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU CC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* In a machine description, all of the insn patterns - define_insn, + define_expand, define_split, define_peephole, define_peephole2 - + contain an optional C expression which makes the final decision + about whether or not this pattern is usable. That expression may + turn out to be always false when the compiler is built. If it is, + most of the programs that generate code from the machine + description can simply ignore the entire pattern. */ + +#include "hconfig.h" +#include "system.h" +#include "rtl.h" +#include "errors.h" +#include "hashtab.h" +#include "gensupport.h" + +/* so we can include except.h in the generated file */ +static int saw_eh_return; + +static htab_t condition_table; + +static void add_condition PARAMS ((const char *)); +static void write_header PARAMS ((void)); +static void write_conditions PARAMS ((void)); +static int write_one_condition PARAMS ((PTR *, PTR)); + +extern int main PARAMS ((int, char **)); + +/* Record the C test expression EXPR in the condition_table. + Duplicates clobber previous entries, which leaks memory, but + we don't care for this application. */ + +static void +add_condition (expr) + const char *expr; +{ + struct c_test *test; + + if (expr[0] == 0) + return; + + test = (struct c_test *) xmalloc (sizeof (struct c_test)); + test->expr = expr; + + *(htab_find_slot (condition_table, test, INSERT)) = test; +} + +/* Generate the header for insn-conditions.c. */ + +static void +write_header () +{ + puts ("\ +/* Generated automatically by the program `genconditions' from the target\n\ + machine description file. */\n\ +\n\ +#include \"hconfig.h\"\n\ +#include \"insn-constants.h\"\n"); + + puts ("\ +/* Do not allow checking to confuse the issue. */\n\ +#undef ENABLE_CHECKING\n\ +#undef ENABLE_TREE_CHECKING\n\ +#undef ENABLE_RTL_CHECKING\n\ +#undef ENABLE_RTL_FLAG_CHECKING\n\ +#undef ENABLE_GC_CHECKING\n\ +#undef ENABLE_GC_ALWAYS_COLLECT\n"); + + puts ("\ +#include \"system.h\"\n\ +#include \"rtl.h\"\n\ +#include \"tm_p.h\"\n\ +#include \"function.h\"\n"); + + puts ("\ +/* Fake - insn-config.h doesn't exist yet. */\n\ +#define MAX_RECOG_OPERANDS 10\n\ +#define MAX_DUP_OPERANDS 10\n\ +#define MAX_INSNS_PER_SPLIT 5\n"); + + puts ("\ +#include \"regs.h\"\n\ +#include \"recog.h\"\n\ +#include \"real.h\"\n\ +#include \"output.h\"\n\ +#include \"flags.h\"\n\ +#include \"hard-reg-set.h\"\n\ +#include \"resource.h\"\n\ +#include \"toplev.h\"\n\ +#include \"reload.h\"\n\ +#include \"gensupport.h\"\n"); + + if (saw_eh_return) + puts ("#define HAVE_eh_return 1"); + puts ("#include \"except.h\"\n"); + + puts ("\ +/* Dummy external declarations. */\n\ +extern rtx insn;\n\ +extern rtx ins1;\n\ +extern rtx operands[];\n\ +extern int next_insn_tests_no_inequality PARAMS ((rtx));\n"); + + puts ("\ +/* If we don't have __builtin_constant_p, or it's not acceptable in\n\ + array initializers, fall back to assuming that all conditions\n\ + potentially vary at run time. It works in 3.0.1 and later; 3.0\n\ + only when not optimizing. */\n\ +#if (GCC_VERSION >= 3001) || ((GCC_VERSION == 3000) && !__OPTIMIZE__)\n\ +# define MAYBE_EVAL(expr) (__builtin_constant_p(expr) ? (int) (expr) : -1)\n\ +#else\n\ +# define MAYBE_EVAL(expr) -1\n\ +#endif\n"); +} + +/* Write out one entry in the conditions table, using the data pointed + to by SLOT. Each entry looks like this: + { "! optimize_size && ! TARGET_READ_MODIFY_WRITE", + MAYBE_EVAL (! optimize_size && ! TARGET_READ_MODIFY_WRITE) }, */ + +static int +write_one_condition (slot, dummy) + PTR *slot; + PTR dummy ATTRIBUTE_UNUSED; +{ + const struct c_test *test = * (const struct c_test **) slot; + const char *p; + + fputs (" { \"", stdout); + for (p = test->expr; *p; p++) + { + if (*p == '\n') + fputs ("\\n\\\n", stdout); + else if (*p == '"') + fputs ("\\\"", stdout); + else + putchar (*p); + } + + printf ("\",\n MAYBE_EVAL (%s) },\n", test->expr); + return 1; +} + +/* Write out the complete conditions table, its size, and a flag + indicating that gensupport.c can now do insn elision. */ +static void +write_conditions () +{ + puts ("\ +/* This table lists each condition found in the machine description.\n\ + Each condition is mapped to its truth value (0 or 1), or -1 if that\n\ + cannot be calculated at compile time. */\n\ +\n\ +const struct c_test insn_conditions[] = {"); + + htab_traverse (condition_table, write_one_condition, 0); + + puts ("};\n"); + + printf ("const size_t n_insn_conditions = %lu;\n", + (unsigned long) htab_elements (condition_table)); + puts ("const int insn_elision_unavailable = 0;"); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + rtx desc; + int pattern_lineno; /* not used */ + int code; + + progname = "genconditions"; + + if (argc <= 1) + fatal ("No input file name."); + + if (init_md_reader (argv[1]) != SUCCESS_EXIT_CODE) + return (FATAL_EXIT_CODE); + + condition_table = htab_create (1000, hash_c_test, cmp_c_test, NULL); + + /* Read the machine description. */ + + while (1) + { + desc = read_md_rtx (&pattern_lineno, &code); + if (desc == NULL) + break; + + /* N.B. define_insn_and_split, define_cond_exec are handled + entirely within read_md_rtx; we never see them. */ + switch (GET_CODE (desc)) + { + default: + break; + + case DEFINE_INSN: + case DEFINE_EXPAND: + add_condition (XSTR (desc, 2)); + /* except.h needs to know whether there is an eh_return + pattern in the machine description. */ + if (!strcmp (XSTR (desc, 0), "eh_return")) + saw_eh_return = 1; + break; + + case DEFINE_SPLIT: + case DEFINE_PEEPHOLE: + case DEFINE_PEEPHOLE2: + add_condition (XSTR (desc, 1)); + break; + } + } + + write_header (); + write_conditions (); + + fflush (stdout); + return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); +} diff --git a/gcc/genflags.c b/gcc/genflags.c index 114b98b837e..94806816762 100644 --- a/gcc/genflags.c +++ b/gcc/genflags.c @@ -124,14 +124,18 @@ gen_macro (name, real, expect) printf ("(%c))\n", i + 'A'); } -/* Print out prototype information for a function. */ +/* Print out prototype information for a generator function. If the + insn pattern has been elided, print out a dummy generator that + does nothing. */ static void gen_proto (insn) rtx insn; { int num = num_operands (insn); + int i; const char *name = XSTR (insn, 0); + int truth = maybe_eval_c_test (XSTR (insn, 2)); /* Many md files don't refer to the last two operands passed to the call patterns. This means their generator functions will be two @@ -152,19 +156,41 @@ gen_proto (insn) gen_macro (name, num, 5); } - printf ("extern struct rtx_def *gen_%-*s PARAMS ((", max_id_len, name); + if (truth != 0) + printf ("extern rtx gen_%-*s PARAMS ((", max_id_len, name); + else + printf ("static inline rtx gen_%-*s PARAMS ((", max_id_len, name); if (num == 0) - printf ("void"); + fputs ("void", stdout); else { - while (num-- > 1) - printf ("struct rtx_def *, "); - - printf ("struct rtx_def *"); + for (i = 1; i < num; i++) + fputs ("rtx, ", stdout); + + fputs ("rtx", stdout); } - printf ("));\n"); + puts ("));"); + + /* Some back ends want to take the address of generator functions, + so we cannot simply use #define for these dummy definitions. */ + if (truth == 0) + { + printf ("static inline rtx\ngen_%s", name); + if (num > 0) + { + putchar ('('); + for (i = 0; i < num-1; i++) + printf ("%c, ", 'a' + i); + printf ("%c)\n", 'a' + i); + for (i = 0; i < num; i++) + printf (" rtx %c ATTRIBUTE_UNUSED;\n", 'a' + i); + } + else + puts ("()"); + puts ("{\n return 0;\n}"); + } } @@ -175,6 +201,7 @@ gen_insn (insn) const char *name = XSTR (insn, 0); const char *p; int len; + int truth = maybe_eval_c_test (XSTR (insn, 2)); /* Don't mention instructions whose names are the null string or begin with '*'. They are in the machine description just @@ -187,22 +214,23 @@ gen_insn (insn) if (len > max_id_len) max_id_len = len; - printf ("#define HAVE_%s ", name); - if (strlen (XSTR (insn, 2)) == 0) - printf ("1\n"); + if (truth == 0) + /* emit nothing */; + else if (truth == 1) + printf ("#define HAVE_%s 1\n", name); else { /* Write the macro definition, putting \'s at the end of each line, if more than one. */ - printf ("("); + printf ("#define HAVE_%s (", name); for (p = XSTR (insn, 2); *p; p++) { if (IS_VSPACE (*p)) - printf (" \\\n"); + fputs (" \\\n", stdout); else - printf ("%c", *p); + putchar (*p); } - printf (")\n"); + fputs (")\n", stdout); } obstack_grow (&obstack, &insn, sizeof (rtx)); @@ -223,6 +251,10 @@ main (argc, argv) progname = "genflags"; obstack_init (&obstack); + /* We need to see all the possibilities. Elided insns may have + direct calls to their generators in C code. */ + insn_elision = 0; + if (argc <= 1) fatal ("no input file name"); @@ -252,7 +284,6 @@ main (argc, argv) obstack_grow (&obstack, &dummy, sizeof (rtx)); insns = (rtx *) obstack_finish (&obstack); - printf ("struct rtx_def;\n"); for (insn_ptr = insns; *insn_ptr; insn_ptr++) gen_proto (*insn_ptr); diff --git a/gcc/genrecog.c b/gcc/genrecog.c index 5492fa0807e..7709eb8b6a6 100644 --- a/gcc/genrecog.c +++ b/gcc/genrecog.c @@ -2452,11 +2452,16 @@ make_insn_sequence (insn, type) { rtx x; const char *c_test = XSTR (insn, type == RECOG ? 2 : 1); + int truth = maybe_eval_c_test (c_test); struct decision *last; struct decision_test *test, **place; struct decision_head head; char c_test_pos[2]; + /* We should never see an insn whose C test is false at compile time. */ + if (truth == 0) + abort (); + record_insn_name (next_insn_code, (type == RECOG ? XSTR (insn, 0) : NULL)); c_test_pos[0] = '\0'; @@ -2504,7 +2509,8 @@ make_insn_sequence (insn, type) continue; place = &test->next; - if (c_test[0]) + /* Skip the C test if it's known to be true at compile time. */ + if (truth == -1) { /* Need a new node if we have another test to add. */ if (test->type == DT_accept_op) @@ -2577,7 +2583,9 @@ make_insn_sequence (insn, type) place = &last->tests; } - if (c_test[0]) + /* Skip the C test if it's known to be true at compile + time. */ + if (truth == -1) { test = new_decision_test (DT_c_test, &place); test->u.c_test = c_test; diff --git a/gcc/gensupport.c b/gcc/gensupport.c index 9e3d0bbcb1f..5a9ff21f978 100644 --- a/gcc/gensupport.c +++ b/gcc/gensupport.c @@ -23,12 +23,15 @@ #include "rtl.h" #include "obstack.h" #include "errors.h" +#include "hashtab.h" #include "gensupport.h" /* In case some macros used by files we include need it, define this here. */ int target_flags; +int insn_elision = 1; + static struct obstack obstack; struct obstack *rtl_obstack = &obstack; @@ -39,6 +42,8 @@ static int predicable_default; static const char *predicable_true; static const char *predicable_false; +static htab_t condition_table; + static char *base_dir = NULL; /* We initially queue all patterns, process the define_insn and @@ -950,6 +955,7 @@ init_md_reader (filename) { FILE *input_file; int c; + size_t i; char *lastsl; lastsl = strrchr (filename, '/'); @@ -964,6 +970,14 @@ init_md_reader (filename) return FATAL_EXIT_CODE; } + /* Initialize the table of insn conditions. */ + condition_table = htab_create (n_insn_conditions, + hash_c_test, cmp_c_test, NULL); + + for (i = 0; i < n_insn_conditions; i++) + *(htab_find_slot (condition_table, (PTR) &insn_conditions[i], INSERT)) + = (PTR) &insn_conditions[i]; + obstack_init (rtl_obstack); errors = 0; sequence_num = 0; @@ -1002,6 +1016,8 @@ read_md_rtx (lineno, seqnr) struct queue_elem **queue, *elem; rtx desc; + discard: + /* Read all patterns from a given queue before moving on to the next. */ if (define_attr_queue != NULL) queue = &define_attr_queue; @@ -1021,14 +1037,29 @@ read_md_rtx (lineno, seqnr) free (elem); + /* Discard insn patterns which we know can never match (because + their C test is provably always false). If insn_elision is + false, our caller needs to see all the patterns. Note that the + elided patterns are never counted by the sequence numbering; it + it is the caller's responsibility, when insn_elision is false, not + to use elided pattern numbers for anything. */ switch (GET_CODE (desc)) { case DEFINE_INSN: case DEFINE_EXPAND: + if (maybe_eval_c_test (XSTR (desc, 2)) != 0) + sequence_num++; + else if (insn_elision) + goto discard; + break; + case DEFINE_SPLIT: case DEFINE_PEEPHOLE: case DEFINE_PEEPHOLE2: - sequence_num++; + if (maybe_eval_c_test (XSTR (desc, 1)) != 0) + sequence_num++; + else if (insn_elision) + goto discard; break; default: @@ -1038,6 +1069,73 @@ read_md_rtx (lineno, seqnr) return desc; } +/* Helper functions for insn elision. */ + +/* Compute a hash function of a c_test structure, which is keyed + by its ->expr field. */ +hashval_t +hash_c_test (x) + const PTR x; +{ + const struct c_test *a = (const struct c_test *) x; + const unsigned char *base, *s = (const unsigned char *) a->expr; + hashval_t hash; + unsigned char c; + unsigned int len; + + base = s; + hash = 0; + + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + } + + len = s - base; + hash += len + (len << 17); + hash ^= hash >> 2; + + return hash; +} + +/* Compare two c_test expression structures. */ +int +cmp_c_test (x, y) + const PTR x; + const PTR y; +{ + const struct c_test *a = (const struct c_test *) x; + const struct c_test *b = (const struct c_test *) y; + + return !strcmp (a->expr, b->expr); +} + +/* Given a string representing a C test expression, look it up in the + condition_table and report whether or not its value is known + at compile time. Returns a tristate: 1 for known true, 0 for + known false, -1 for unknown. */ +int +maybe_eval_c_test (expr) + const char *expr; +{ + const struct c_test *test; + struct c_test dummy; + + if (expr[0] == 0) + return 1; + + if (insn_elision_unavailable) + return -1; + + dummy.expr = expr; + test = (const struct c_test *) htab_find (condition_table, &dummy); + if (!test) + abort (); + + return test->value; +} + /* Given a string, return the number of comma-separated elements in it. Return 0 for the null string. */ int diff --git a/gcc/gensupport.h b/gcc/gensupport.h index bac804b22a6..8dbd0b70ea9 100644 --- a/gcc/gensupport.h +++ b/gcc/gensupport.h @@ -18,6 +18,9 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef GCC_GENSUPPORT_H +#define GCC_GENSUPPORT_H + struct obstack; extern struct obstack *rtl_obstack; @@ -28,6 +31,39 @@ extern rtx read_md_rtx PARAMS ((int *, int *)); extern void message_with_line PARAMS ((int, const char *, ...)) ATTRIBUTE_PRINTF_2; +/* Set this to 0 to disable automatic elision of insn patterns which + can never be used in this configuration. See genconditions.c. + Must be set before calling init_md_reader. */ +extern int insn_elision; + +/* If this is 1, the insn elision table doesn't even exist yet; + maybe_eval_c_test will always return -1. This is distinct from + insn_elision because genflags and gencodes need to see all the + patterns, but treat elided patterns differently. */ +extern const int insn_elision_unavailable; + +/* If the C test passed as the argument can be evaluated at compile + time, return its truth value; else return -1. The test must have + appeared somewhere in the machine description when genconditions + was run. */ +extern int maybe_eval_c_test PARAMS ((const char *)); + +/* This table should not be accessed directly; use maybe_eval_c_test. */ +struct c_test +{ + const char *expr; + int value; +}; + +extern const struct c_test insn_conditions[]; +extern const size_t n_insn_conditions; + +#ifdef __HASHTAB_H__ +extern hashval_t hash_c_test PARAMS ((const PTR)); +extern int cmp_c_test PARAMS ((const PTR, const PTR)); +#endif + extern int n_comma_elts PARAMS ((const char *)); extern const char *scan_comma_elt PARAMS ((const char **)); +#endif /* GCC_GENSUPPORT_H */