- 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, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC 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)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "bconfig.h"
#include "system.h"
if (q != p && (ISALNUM (q[-1]) || q[-1] == '_'))
return false;
q += strlen (var);
- if (ISALNUM (q[0] || q[0] == '_'))
+ if (ISALNUM (q[0]) || q[0] == '_')
return false;
}
return true;
}
}
+/* Determine whether the expression EXP is a MATCH_CODE that should
+ be written as a switch statement. */
+static bool
+generate_switch_p (rtx exp)
+{
+ return GET_CODE (exp) == MATCH_CODE
+ && strchr (XSTR (exp, 0), ',');
+}
+
/* 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
switch (GET_CODE (subexp))
{
+ case AND:
+ /* The switch code generation in write_predicate_stmts prefers
+ rtx code tests to be at the top of the expression tree. So
+ push this AND down into the second operand of an existing
+ AND expression. */
+ if (generate_switch_p (XEXP (subexp, 0)))
+ pos = &XEXP (subexp, 1);
+ goto break_loop;
+
case IOR:
{
int test0 = NO_MODE_TEST (XEXP (subexp, 0));
}
}
+/* Write the MATCH_CODE expression EXP as a switch statement. */
+
+static void
+write_match_code_switch (rtx exp)
+{
+ const char *codes = XSTR (exp, 0);
+ const char *path = XSTR (exp, 1);
+ const char *code;
+
+ fputs (" switch (GET_CODE (", stdout);
+ write_extract_subexp (path);
+ fputs ("))\n {\n", stdout);
+
+ while ((code = scan_comma_elt (&codes)) != 0)
+ {
+ fputs (" case ", stdout);
+ while (code < codes)
+ {
+ putchar (TOUPPER (*code));
+ code++;
+ }
+ fputs(":\n", stdout);
+ }
+}
+
+/* Given a predicate expression EXP, write out a sequence of stmts
+ to evaluate it. This is similar to write_predicate_expr but can
+ generate efficient switch statements. */
+
+static void
+write_predicate_stmts (rtx exp)
+{
+ switch (GET_CODE (exp))
+ {
+ case MATCH_CODE:
+ if (generate_switch_p (exp))
+ {
+ write_match_code_switch (exp);
+ puts (" return true;\n"
+ " default:\n"
+ " break;\n"
+ " }\n"
+ " return false;");
+ return;
+ }
+ break;
+
+ case AND:
+ if (generate_switch_p (XEXP (exp, 0)))
+ {
+ write_match_code_switch (XEXP (exp, 0));
+ puts (" break;\n"
+ " default:\n"
+ " return false;\n"
+ " }");
+ exp = XEXP (exp, 1);
+ }
+ break;
+
+ case IOR:
+ if (generate_switch_p (XEXP (exp, 0)))
+ {
+ write_match_code_switch (XEXP (exp, 0));
+ puts (" return true;\n"
+ " default:\n"
+ " break;\n"
+ " }");
+ exp = XEXP (exp, 1);
+ }
+ break;
+
+ case NOT:
+ if (generate_switch_p (XEXP (exp, 0)))
+ {
+ write_match_code_switch (XEXP (exp, 0));
+ puts (" return false;\n"
+ " default:\n"
+ " break;\n"
+ " }\n"
+ " return true;");
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ fputs(" return ",stdout);
+ write_predicate_expr (exp);
+ fputs(";\n", stdout);
+}
+
/* Given a predicate, write out a complete C function to compute it. */
static void
write_one_predicate_function (struct pred_data *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 ",
+ printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n{\n",
p->name);
- write_predicate_expr (p->exp);
- fputs (";\n}\n\n", stdout);
+ write_predicate_stmts (p->exp);
+ fputs ("}\n\n", stdout);
}
\f
/* Constraints fall into two categories: register constraints
for (iter_ = first_constraint; iter_; iter_ = iter_->next_textual)
/* These letters, and all names beginning with them, are reserved for
- generic constraints. */
-static const char generic_constraint_letters[] = "EFVXgimnoprs";
+ generic constraints.
+ The 'm' constraint is not mentioned here since that constraint
+ letter can be overridden by the back end by defining the
+ TARGET_MEM_CONSTRAINT macro. */
+static const char generic_constraint_letters[] = "EFVXginoprs";
/* Machine-independent code expects that constraints with these
(initial) letters will allow only (a subset of all) CONST_INTs. */
}
obstack_1grow (rtl_obstack, '\0');
- return obstack_finish (rtl_obstack);
+ return XOBFINISH (rtl_obstack, const char *);
}
/* Add one constraint, of any sort, to the tables. NAME is its name;
have_error = 1;
return;
}
-
- /* Remove the redundant (and (match_code "const_(int|double)")
- from the expression. */
- exp = XEXP (exp, 1);
}
- c = obstack_alloc (rtl_obstack, sizeof (struct constraint_data));
+ c = XOBNEW (rtl_obstack, struct constraint_data);
c->name = name;
c->c_name = need_mangled_name ? mangle (name) : name;
c->lineno = lineno;
{
struct constraint_data *c;
+ fputs ("#define CONSTRAINT_NUM_DEFINED_P 1\n", stdout);
fputs ("enum constraint_num\n"
"{\n"
" CONSTRAINT__UNKNOWN = 0", stdout);
FOR_ALL_CONSTRAINTS (c)
printf (",\n CONSTRAINT_%s", c->c_name);
- puts ("\n};\n");
+ puts (",\n CONSTRAINT__LIMIT\n};\n");
}
/* Write out a function which looks at a string and determines what
"}\n");
}
-/* Write out the function which computes constraint name lengths from
- their enumerators. */
+/* Write out a function which looks at a string and determines what
+ the constraint name length is. */
static void
write_insn_constraint_len (void)
{
- struct constraint_data *c;
-
- if (constraint_max_namelen == 1)
- return;
+ unsigned int i;
- puts ("size_t\n"
- "insn_constraint_len (enum constraint_num c)\n"
+ puts ("static inline size_t\n"
+ "insn_constraint_len (char fc, const char *str ATTRIBUTE_UNUSED)\n"
"{\n"
- " switch (c)\n"
+ " switch (fc)\n"
" {");
- FOR_ALL_CONSTRAINTS (c)
- if (c->namelen > 1)
- printf (" case CONSTRAINT_%s: return %lu;\n", c->c_name,
- (unsigned long int) c->namelen);
+ for (i = 0; i < ARRAY_SIZE(constraints_by_letter_table); i++)
+ {
+ struct constraint_data *c = constraints_by_letter_table[i];
+
+ if (!c
+ || c->namelen == 1)
+ continue;
+
+ /* Constraints with multiple characters should have the same
+ length. */
+ {
+ struct constraint_data *c2 = c->next_this_letter;
+ size_t len = c->namelen;
+ while (c2)
+ {
+ if (c2->namelen != len)
+ error ("Multi-letter constraints with first letter '%c' "
+ "should have same length", i);
+ c2 = c2->next_this_letter;
+ }
+ }
+
+ printf (" case '%c': return %lu;\n",
+ i, (unsigned long int) c->namelen);
+ }
puts (" default: break;\n"
" }\n"
/* Write out the functions which compute whether a given value matches
a given non-register constraint. */
static void
-write_satisfies_constraint_fns (void)
+write_tm_constrs_h (void)
{
struct constraint_data *c;
- /* A fair number of places include tm_p.h without including rtl.h. */
- puts ("#ifdef GCC_RTL_H\n");
-
+ printf ("\
+/* Generated automatically by the program '%s'\n\
+ from the machine description file '%s'. */\n\n", progname, in_fname);
+
+ puts ("\
+#ifndef GCC_TM_CONSTRS_H\n\
+#define GCC_TM_CONSTRS_H\n");
+
FOR_ALL_CONSTRAINTS (c)
if (!c->is_register)
{
bool needs_rval = needs_variable (c->exp, "rval");
bool needs_mode = (needs_variable (c->exp, "mode")
|| needs_hval || needs_lval || needs_rval);
+ bool needs_op = (needs_variable (c->exp, "op")
+ || needs_ival || needs_mode);
printf ("static inline bool\n"
- "satisfies_constraint_%s (rtx op)\n"
- "{\n", c->c_name);
+ "satisfies_constraint_%s (rtx %s)\n"
+ "{\n", c->c_name,
+ needs_op ? "op" : "ARG_UNUSED (op)");
if (needs_mode)
- puts ("enum machine_mode mode = GET_MODE (op);");
+ puts (" enum machine_mode mode = GET_MODE (op);");
if (needs_ival)
puts (" HOST_WIDE_INT ival = 0;");
if (needs_hval)
puts (" const REAL_VALUE_TYPE *rval = 0;");
if (needs_ival)
- puts (" if (GET_CODE (op) == CONST_INT)\n"
+ puts (" if (CONST_INT_P (op))\n"
" ival = INTVAL (op);");
if (needs_hval)
puts (" if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
if (needs_rval)
puts (" if (GET_CODE (op) == CONST_DOUBLE && mode != VOIDmode)"
" rval = CONST_DOUBLE_REAL_VALUE (op);");
-
- fputs (" return ", stdout);
- write_predicate_expr (c->exp);
- fputs (";\n}\n", stdout);
- }
- puts ("\n#endif /* rtl.h visible */\n");
+ write_predicate_stmts (c->exp);
+ fputs ("}\n", stdout);
+ }
+ puts ("#endif /* tm-constrs.h */");
}
/* Write out the wrapper function, constraint_satisfied_p, that maps
if (c->is_const_int)
{
printf (" case CONSTRAINT_%s:\n return ", c->c_name);
- write_predicate_expr (c->exp);
+ /* c->exp is guaranteed to be (and (match_code "const_int") (...));
+ we know at this point that we have a const_int, so we need not
+ bother with that part of the test. */
+ write_predicate_expr (XEXP (c->exp, 1));
fputs (";\n\n", stdout);
}
puts ("bool\n"
"insn_extra_address_constraint (enum constraint_num c)\n"
"{\n"
- " switch (str[0])\n"
+ " switch (c)\n"
" {");
FOR_ALL_CONSTRAINTS (c)
"extern bool constraint_satisfied_p (rtx, enum constraint_num);\n");
if (constraint_max_namelen > 1)
- puts ("extern size_t insn_constraint_len (enum constraint_num);\n"
- "#define CONSTRAINT_LEN(c_,s_) "
- "insn_constraint_len (lookup_constraint (s_))\n");
+ {
+ write_insn_constraint_len ();
+ puts ("#define CONSTRAINT_LEN(c_,s_) "
+ "insn_constraint_len (c_,s_)\n");
+ }
else
puts ("#define CONSTRAINT_LEN(c_,s_) 1\n");
if (have_register_constraints)
puts ("extern enum reg_class regclass_for_constraint "
"(enum constraint_num);\n"
"#define REG_CLASS_FROM_CONSTRAINT(c_,s_) \\\n"
- " regclass_for_constraint (lookup_constraint (s_))\n");
+ " regclass_for_constraint (lookup_constraint (s_))\n"
+ "#define REG_CLASS_FOR_CONSTRAINT(x_) \\\n"
+ " regclass_for_constraint (x_)\n");
else
- puts ("#define REG_CLASS_FROM_CONSTRAINT(c_,s_) NO_REGS");
+ puts ("#define REG_CLASS_FROM_CONSTRAINT(c_,s_) NO_REGS\n"
+ "#define REG_CLASS_FOR_CONSTRAINT(x_) \\\n"
+ " NO_REGS\n");
if (have_const_int_constraints)
puts ("extern bool insn_const_int_ok_for_constraint "
"(HOST_WIDE_INT, enum constraint_num);\n"
puts ("#define EXTRA_MEMORY_CONSTRAINT(c_,s_) false\n");
if (have_address_constraints)
puts ("extern bool "
- "insn_extra_address_constraint (enum constraint_num)"
+ "insn_extra_address_constraint (enum constraint_num);\n"
"#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) "
"insn_extra_address_constraint (lookup_constraint (s_))\n");
else
puts ("#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) false\n");
-
- if (have_const_int_constraints || have_const_dbl_constraints
- || have_extra_constraints)
- write_satisfies_constraint_fns ();
}
puts ("#endif /* tm-preds.h */");
#include \"resource.h\"\n\
#include \"toplev.h\"\n\
#include \"reload.h\"\n\
-#include \"regs.h\"\n");
+#include \"regs.h\"\n\
+#include \"tm-constrs.h\"\n");
FOR_ALL_PREDICATES (p)
write_one_predicate_function (p);
if (constraint_max_namelen > 0)
{
write_lookup_constraint ();
- write_regclass_for_constraint ();
+ if (have_register_constraints)
+ write_regclass_for_constraint ();
write_constraint_satisfied_p ();
- if (constraint_max_namelen > 1)
- write_insn_constraint_len ();
-
if (have_const_int_constraints)
write_insn_const_int_ok_for_constraint ();
/* Argument parsing. */
static bool gen_header;
+static bool gen_constrs;
+
static bool
parse_option (const char *opt)
{
gen_header = true;
return 1;
}
+ else if (!strcmp (opt, "-c"))
+ {
+ gen_constrs = true;
+ return 1;
+ }
else
return 0;
}
if (gen_header)
write_tm_preds_h ();
+ else if (gen_constrs)
+ write_tm_constrs_h ();
else
write_insn_preds_c ();