X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgenpreds.c;h=874925de998bebea4df423a6d43a13310802929c;hb=7c1ab928ec2df070c5c9a55efe0c276a5e1aa004;hp=f008526b3b0efa9a18ef3264b113a423e9b1d40e;hpb=805e22b2051e9c6a75377ea6599654d7415da483;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/genpreds.c b/gcc/genpreds.c index f008526b3b0..874925de998 100644 --- a/gcc/genpreds.c +++ b/gcc/genpreds.c @@ -1,8 +1,8 @@ /* Generate from machine description: - - some macros CODE_FOR_... giving the insn_code_number value - for each of the defined standard insn names. - Copyright (C) 1987, 1991, 1995, 1998, - 1999, 2000, 2001 Free Software Foundation, Inc. + - prototype declarations for operand predicates (tm-preds.h) + - function definitions of operand predicates, if defined new-style + (insn-preds.c) + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -25,46 +25,473 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "coretypes.h" #include "tm.h" - -#define NO_GENRTL_H #include "rtl.h" +#include "errors.h" +#include "gensupport.h" +#include "obstack.h" + +/* The new way to declare predicates is with (define_predicate) or + (define_special_predicate) expressions in the machine description. + This provides a function body as well as a name. */ +static void +process_define_predicate (rtx defn) +{ + struct pred_data *pred; + if (XEXP (defn, 1) == 0) + { + error ("%s: must give a predicate expression", XSTR (defn, 0)); + return; + } + + pred = xcalloc (sizeof (struct pred_data), 1); + pred->name = XSTR (defn, 0); + pred->exp = XEXP (defn, 1); + pred->c_block = XSTR (defn, 2); + + if (GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE) + pred->special = true; + + add_predicate (pred); +} + +/* Write tm-preds.h. Unfortunately, it is impossible to forward-declare + an enumeration in portable C, so we have to condition all these + prototypes on HAVE_MACHINE_MODES. */ +static void +write_tm_preds_h (void) +{ + struct pred_data *p; + + printf ("\ +/* Generated automatically by the program '%s'\n\ + from the machine description file '%s'. */\n\n", progname, in_fname); + + puts ("\ +#ifndef GCC_TM_PREDS_H\n\ +#define GCC_TM_PREDS_H\n\ +\n\ +#ifdef HAVE_MACHINE_MODES"); + + FOR_ALL_PREDICATES (p) + printf ("extern int %s (rtx, enum machine_mode);\n", p->name); + + puts ("\ +#endif /* HAVE_MACHINE_MODES */\n\ +#endif /* tm-preds.h */"); +} + +/* Given a predicate, if it has an embedded C block, write the block + out as a static inline subroutine, and augment the RTL test with a + match_test that calls that subroutine. For instance, + + (define_predicate "basereg_operand" + (match_operand 0 "register_operand") + { + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return REG_POINTER (op); + }) + + becomes + + static inline int basereg_operand_1(rtx op, enum machine_mode mode) + { + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return REG_POINTER (op); + } + + (define_predicate "basereg_operand" + (and (match_operand 0 "register_operand") + (match_test "basereg_operand_1 (op, mode)"))) + + The only wart is that there's no way to insist on a { } string in + an RTL template, so we have to handle "" strings. */ + + +static void +write_predicate_subfunction (struct pred_data *p) +{ + const char *match_test_str; + rtx match_test_exp, and_exp; + + if (p->c_block[0] == '\0') + return; + + /* Construct the function-call expression. */ + obstack_grow (rtl_obstack, p->name, strlen (p->name)); + obstack_grow (rtl_obstack, "_1 (op, mode)", + sizeof "_1 (op, mode)"); + match_test_str = obstack_finish (rtl_obstack); + + /* Add the function-call expression to the complete expression to be + evaluated. */ + match_test_exp = rtx_alloc (MATCH_TEST); + XSTR (match_test_exp, 0) = match_test_str; + + and_exp = rtx_alloc (AND); + XEXP (and_exp, 0) = p->exp; + XEXP (and_exp, 1) = match_test_exp; + + p->exp = and_exp; + + printf ("static inline int\n" + "%s_1 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n", + p->name); + if (p->c_block[0] == '{') + fputs (p->c_block, stdout); + else + printf ("{\n %s\n}", p->c_block); + fputs ("\n\n", stdout); +} + +/* Given an RTL expression EXP, find all subexpressions which we may + assume to perform mode tests. Normal MATCH_OPERAND does; + MATCH_CODE does if and only if it accepts CONST_INT or + CONST_DOUBLE; and we have to assume that MATCH_TEST does not. + These combine in almost-boolean fashion - the only exception is + that (not X) must be assumed not to perform a mode test, whether or + not X does. + + The mark is the RTL /v flag, which is true for subexpressions which + do *not* perform mode tests. +*/ +#define NO_MODE_TEST(EXP) RTX_FLAG (EXP, volatil) +static void +mark_mode_tests (rtx exp) +{ + switch (GET_CODE (exp)) + { + case MATCH_OPERAND: + { + struct pred_data *p = lookup_predicate (XSTR (exp, 1)); + if (!p) + error ("reference to undefined predicate '%s'", XSTR (exp, 1)); + else if (p->special) + NO_MODE_TEST (exp) = 1; + } + break; + + case MATCH_CODE: + if (!strstr (XSTR (exp, 0), "const_int") + && !strstr (XSTR (exp, 0), "const_double")) + NO_MODE_TEST (exp) = 1; + break; + + case MATCH_TEST: + case NOT: + NO_MODE_TEST (exp) = 1; + break; + + case AND: + mark_mode_tests (XEXP (exp, 0)); + mark_mode_tests (XEXP (exp, 1)); + + NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0)) + && NO_MODE_TEST (XEXP (exp, 1))); + break; + + case IOR: + mark_mode_tests (XEXP (exp, 0)); + mark_mode_tests (XEXP (exp, 1)); + + NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0)) + || NO_MODE_TEST (XEXP (exp, 1))); + break; + + case IF_THEN_ELSE: + /* A ? B : C does a mode test if (one of A and B) does a mode + test, and C does too. */ + mark_mode_tests (XEXP (exp, 0)); + mark_mode_tests (XEXP (exp, 1)); + mark_mode_tests (XEXP (exp, 2)); + + NO_MODE_TEST (exp) = ((NO_MODE_TEST (XEXP (exp, 0)) + && NO_MODE_TEST (XEXP (exp, 1))) + || NO_MODE_TEST (XEXP (exp, 2))); + break; + + default: + error ("'%s' cannot be used in a define_predicate expression", + GET_RTX_NAME (GET_CODE (exp))); + } +} + +/* Given a predicate, work out where in its RTL expression to add + tests for proper modes. Special predicates do not get any such + tests. We try to avoid adding tests when we don't have to; in + particular, other normal predicates can be counted on to do it for + us. */ -static void output_predicate_decls PARAMS ((void)); -extern int main PARAMS ((void)); +static void +add_mode_tests (struct pred_data *p) +{ + rtx match_test_exp, and_exp; + rtx *pos; + + /* Don't touch special predicates. */ + if (p->special) + return; + + mark_mode_tests (p->exp); + + /* If the whole expression already tests the mode, we're done. */ + if (!NO_MODE_TEST (p->exp)) + return; + + match_test_exp = rtx_alloc (MATCH_TEST); + XSTR (match_test_exp, 0) = "mode == VOIDmode || GET_MODE (op) == mode"; + and_exp = rtx_alloc (AND); + XEXP (and_exp, 1) = match_test_exp; + + /* It is always correct to rewrite p->exp as + + (and (...) (match_test "mode == VOIDmode || GET_MODE (op) == mode")) + + but there are a couple forms where we can do better. If the + top-level pattern is an IOR, and one of the two branches does test + the mode, we can wrap just the branch that doesn't. Likewise, if + we have an IF_THEN_ELSE, and one side of it tests the mode, we can + wrap just the side that doesn't. And, of course, we can repeat this + descent as many times as it works. */ + + pos = &p->exp; + for (;;) + { + rtx subexp = *pos; + + switch (GET_CODE (subexp)) + { + case IOR: + { + int test0 = NO_MODE_TEST (XEXP (subexp, 0)); + int test1 = NO_MODE_TEST (XEXP (subexp, 1)); + + gcc_assert (test0 || test1); + + if (test0 && test1) + goto break_loop; + pos = test0 ? &XEXP (subexp, 0) : &XEXP (subexp, 1); + } + break; + + case IF_THEN_ELSE: + { + int test0 = NO_MODE_TEST (XEXP (subexp, 0)); + int test1 = NO_MODE_TEST (XEXP (subexp, 1)); + int test2 = NO_MODE_TEST (XEXP (subexp, 2)); + + gcc_assert ((test0 && test1) || test2); + + if (test0 && test1 && test2) + goto break_loop; + if (test0 && test1) + /* Must put it on the dependent clause, not the + controlling expression, or we change the meaning of + the test. */ + pos = &XEXP (subexp, 1); + else + pos = &XEXP (subexp, 2); + } + break; + + default: + goto break_loop; + } + } + break_loop: + XEXP (and_exp, 0) = *pos; + *pos = and_exp; +} + + +/* CODES is a list of RTX codes. Write out an expression which + determines whether the operand has one of those codes. */ +static void +write_match_code (const char *codes) +{ + const char *code; + + while ((code = scan_comma_elt (&codes)) != 0) + { + fputs ("GET_CODE (op) == ", stdout); + while (code < codes) + { + putchar (TOUPPER (*code)); + code++; + } + + if (*codes == ',') + fputs (" || ", stdout); + } +} + +/* EXP is an RTL (sub)expression for a predicate. Recursively + descend the expression and write out an equivalent C expression. */ +static void +write_predicate_expr (const char *name, rtx exp) +{ + switch (GET_CODE (exp)) + { + case AND: + putchar ('('); + write_predicate_expr (name, XEXP (exp, 0)); + fputs (") && (", stdout); + write_predicate_expr (name, XEXP (exp, 1)); + putchar (')'); + break; + + case IOR: + putchar ('('); + write_predicate_expr (name, XEXP (exp, 0)); + fputs (") || (", stdout); + write_predicate_expr (name, XEXP (exp, 1)); + putchar (')'); + break; + + case NOT: + fputs ("!(", stdout); + write_predicate_expr (name, XEXP (exp, 0)); + putchar (')'); + break; + + case IF_THEN_ELSE: + putchar ('('); + write_predicate_expr (name, XEXP (exp, 0)); + fputs (") ? (", stdout); + write_predicate_expr (name, XEXP (exp, 1)); + fputs (") : (", stdout); + write_predicate_expr (name, XEXP (exp, 2)); + putchar (')'); + break; + case MATCH_OPERAND: + printf ("%s (op, mode)", XSTR (exp, 1)); + break; + + case MATCH_CODE: + write_match_code (XSTR (exp, 0)); + break; + + case MATCH_TEST: + fputs (XSTR (exp, 0), stdout); + break; + + default: + error ("%s: cannot use '%s' in a predicate expression", + name, GET_RTX_NAME (GET_CODE (exp))); + putchar ('0'); + } +} + +/* Given a predicate, write out a complete C function to compute it. */ static void -output_predicate_decls () +write_one_predicate_function (struct pred_data *p) { -#ifdef PREDICATE_CODES - static const struct { - const char *const name; - const RTX_CODE codes[NUM_RTX_CODE]; - } predicate[] = { - PREDICATE_CODES - }; - size_t i; - - puts ("#ifdef RTX_CODE\n"); - for (i = 0; i < ARRAY_SIZE (predicate); i++) - printf ("extern int %s PARAMS ((rtx, enum machine_mode));\n", - predicate[i].name); - puts ("\n#endif /* RTX_CODE */\n"); -#endif + if (!p->exp) + return; + + write_predicate_subfunction (p); + add_mode_tests (p); + + /* A normal predicate can legitimately not look at enum machine_mode + if it accepts only CONST_INTs and/or CONST_DOUBLEs. */ + printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n" + "{\n return ", + p->name); + write_predicate_expr (p->name, p->exp); + fputs (";\n}\n\n", stdout); } +/* Write insn-preds.c. + N.B. the list of headers to include was copied from genrecog; it + may not be ideal. + + FUTURE: Write #line markers referring back to the machine + description. (Can't practically do this now since we don't know + the line number of the C block - just the line number of the enclosing + expression.) */ +static void +write_insn_preds_c (void) +{ + struct pred_data *p; + + printf ("\ +/* Generated automatically by the program '%s'\n\ + from the machine description file '%s'. */\n\n", progname, in_fname); + + puts ("\ +#include \"config.h\"\n\ +#include \"system.h\"\n\ +#include \"coretypes.h\"\n\ +#include \"tm.h\"\n\ +#include \"rtl.h\"\n\ +#include \"tree.h\"\n\ +#include \"tm_p.h\"\n\ +#include \"function.h\"\n\ +#include \"insn-config.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 \"regs.h\"\n"); + + FOR_ALL_PREDICATES (p) + write_one_predicate_function (p); +} + +/* Argument parsing. */ +static bool gen_header; +static bool +parse_option (const char *opt) +{ + if (!strcmp (opt, "-h")) + { + gen_header = true; + return 1; + } + else + return 0; +} + +/* Master control. */ int -main () +main (int argc, char **argv) { - puts ("/* Generated automatically by the program `genpreds'. */\n"); - puts ("#ifndef GCC_TM_PREDS_H"); - puts ("#define GCC_TM_PREDS_H\n"); + rtx defn; + int pattern_lineno, next_insn_code = 0; - output_predicate_decls (); + progname = argv[0]; + if (argc <= 1) + fatal ("no input file name"); + if (init_md_reader_args_cb (argc, argv, parse_option) != SUCCESS_EXIT_CODE) + return FATAL_EXIT_CODE; + + while ((defn = read_md_rtx (&pattern_lineno, &next_insn_code)) != 0) + { + if (GET_CODE (defn) == DEFINE_PREDICATE + || GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE) + process_define_predicate (defn); + } - puts ("#endif /* GCC_TM_PREDS_H */"); + if (gen_header) + write_tm_preds_h (); + else + write_insn_preds_c (); - if (ferror (stdout) || fflush (stdout) || fclose (stdout)) + if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout)) return FATAL_EXIT_CODE; return SUCCESS_EXIT_CODE; } + +/* Dummy for debugging purposes. */ +const char * +get_insn_name (int code ATTRIBUTE_UNUSED) +{ + return 0; +}