+2015-08-24 Richard Sandiford <richard.sandiford@arm.com>
+
+ * genflags.c (gen_macro): Delete.
+ (gen_proto): Don't create GEN.*CALL.* macros.
+ * gensupport.h (get_file_location): Declare.
+ * gensupport.c (rtx_locs): New variable.
+ (read_md_rtx): Record rtx locations.
+ (get_file_location): New function.
+ * target-insns.def (call, call_pop, call_value, call_value_pop)
+ (sibcall, sibcall_value): New patterns.
+ * gentarget-def.c (parse_argument): New function.
+ (def_target_insn): Use it. Handle optional operands. Raise an
+ error if an .md pattern has the wrong number of operands for the
+ pattern name. Remove the names of unused operands from the prototype.
+ * builtins.c (expand_builtin_apply): Use targetm functions
+ instead of HAVE_call_value and GEN_CALL_VALUE.
+ * calls.c (emit_call_1): Likewise. Remove support for sibcall_pop
+ and sibcall_value_pop.
+ * config/aarch64/aarch64.md (untyped_call): Use gen_call instead
+ of GEN_CALL.
+ * config/alpha/alpha.md (untyped_call): Likewise.
+ * config/iq2000/iq2000.md (untyped_call): Likewise.
+ * config/m68k/m68k.md (untyped_call): Likewise.
+ * config/mips/mips.md (untyped_call): Likewise.
+ * config/pa/pa.md (untyped_call): Likewise.
+ * config/rs6000/rs6000.md (untyped_call): Likewise.
+ * config/sparc/sparc.md (untyped_call): Likewise.
+ * config/tilegx/tilegx.md (untyped_call): Likewise.
+ * config/tilepro/tilepro.md (untyped_call): Likewise.
+ * config/visium/visium.md (untyped_call): Likewise.
+ * config/alpha/alpha.c (alpha_emit_xfloating_libcall): Use
+ gen_call_value instead of GEN_CALL_VALUE.
+ * config/arm/arm.md (untyped_call): Likewise.
+ * config/cr16/cr16.c (cr16_function_arg): Remove reference to
+ GEN_CALL.
+
2015-08-24 Richard Sandiford <richard.sandiford@arm.com>
* ifcvt.c (HAVE_incscc, HAVE_decscc, HAVE_cbranchcc4): Delete.
emit_call_insn (targetm.gen_untyped_call (mem, result,
result_vector (1, result)));
}
- else
-#ifdef HAVE_call_value
- if (HAVE_call_value)
+ else if (targetm.have_call_value ())
{
rtx valreg = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
{
- gcc_assert (!valreg); /* HAVE_untyped_call required. */
+ gcc_assert (!valreg); /* have_untyped_call required. */
valreg = gen_rtx_REG (mode, regno);
}
- emit_call_insn (GEN_CALL_VALUE (valreg,
- gen_rtx_MEM (FUNCTION_MODE, function),
- const0_rtx, NULL_RTX, const0_rtx));
+ emit_insn (targetm.gen_call_value (valreg,
+ gen_rtx_MEM (FUNCTION_MODE, function),
+ const0_rtx, NULL_RTX, const0_rtx));
emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
}
else
-#endif
gcc_unreachable ();
/* Find the CALL insn we just emitted, and attach the register usage
cumulative_args_t args_so_far ATTRIBUTE_UNUSED)
{
rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
- rtx call, funmem;
+ rtx call, funmem, pat;
int already_popped = 0;
HOST_WIDE_INT n_popped
= targetm.calls.return_pops_args (fndecl, funtype, stack_size);
else if (fntree)
set_mem_expr (funmem, build_simple_mem_ref (CALL_EXPR_FN (fntree)));
-#if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop)
- if ((ecf_flags & ECF_SIBCALL)
- && HAVE_sibcall_pop && HAVE_sibcall_value_pop
- && (n_popped > 0 || stack_size == 0))
+ if (ecf_flags & ECF_SIBCALL)
{
- rtx n_pop = GEN_INT (n_popped);
- rtx pat;
-
- /* If this subroutine pops its own args, record that in the call insn
- if possible, for the sake of frame pointer elimination. */
-
if (valreg)
- pat = GEN_SIBCALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
- next_arg_reg, n_pop);
+ pat = targetm.gen_sibcall_value (valreg, funmem,
+ rounded_stack_size_rtx,
+ next_arg_reg, NULL_RTX);
else
- pat = GEN_SIBCALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
- n_pop);
-
- emit_call_insn (pat);
- already_popped = 1;
+ pat = targetm.gen_sibcall (funmem, rounded_stack_size_rtx,
+ next_arg_reg, GEN_INT (struct_value_size));
}
- else
-#endif
-
-#if defined (HAVE_call_pop) && defined (HAVE_call_value_pop)
/* If the target has "call" or "call_value" insns, then prefer them
if no arguments are actually popped. If the target does not have
"call" or "call_value" insns, then we must use the popping versions
even if the call has no arguments to pop. */
-#if defined (HAVE_call) && defined (HAVE_call_value)
- if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop
- && n_popped > 0)
-#else
- if (HAVE_call_pop && HAVE_call_value_pop)
-#endif
+ else if (n_popped > 0
+ || !(valreg
+ ? targetm.have_call_value ()
+ : targetm.have_call ()))
{
rtx n_pop = GEN_INT (n_popped);
- rtx pat;
/* If this subroutine pops its own args, record that in the call insn
if possible, for the sake of frame pointer elimination. */
if (valreg)
- pat = GEN_CALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
- next_arg_reg, n_pop);
+ pat = targetm.gen_call_value_pop (valreg, funmem,
+ rounded_stack_size_rtx,
+ next_arg_reg, n_pop);
else
- pat = GEN_CALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
- n_pop);
+ pat = targetm.gen_call_pop (funmem, rounded_stack_size_rtx,
+ next_arg_reg, n_pop);
- emit_call_insn (pat);
already_popped = 1;
}
else
-#endif
-
-#if defined (HAVE_sibcall) && defined (HAVE_sibcall_value)
- if ((ecf_flags & ECF_SIBCALL)
- && HAVE_sibcall && HAVE_sibcall_value)
- {
- if (valreg)
- emit_call_insn (GEN_SIBCALL_VALUE (valreg, funmem,
- rounded_stack_size_rtx,
- next_arg_reg, NULL_RTX));
- else
- emit_call_insn (GEN_SIBCALL (funmem, rounded_stack_size_rtx,
- next_arg_reg,
- GEN_INT (struct_value_size)));
- }
- else
-#endif
-
-#if defined (HAVE_call) && defined (HAVE_call_value)
- if (HAVE_call && HAVE_call_value)
{
if (valreg)
- emit_call_insn (GEN_CALL_VALUE (valreg, funmem, rounded_stack_size_rtx,
- next_arg_reg, NULL_RTX));
+ pat = targetm.gen_call_value (valreg, funmem, rounded_stack_size_rtx,
+ next_arg_reg, NULL_RTX);
else
- emit_call_insn (GEN_CALL (funmem, rounded_stack_size_rtx, next_arg_reg,
- GEN_INT (struct_value_size)));
+ pat = targetm.gen_call (funmem, rounded_stack_size_rtx, next_arg_reg,
+ GEN_INT (struct_value_size));
}
- else
-#endif
- gcc_unreachable ();
+ emit_insn (pat);
/* Find the call we just emitted. */
rtx_call_insn *call_insn = last_call_insn ();
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
}
tmp = gen_rtx_MEM (QImode, func);
- tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx,
+ tmp = emit_call_insn (gen_call_value (reg, tmp, const0_rtx,
const0_rtx, const0_rtx));
CALL_INSN_FUNCTION_USAGE (tmp) = usage;
RTL_CONST_CALL_P (tmp) = 1;
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
size += GET_MODE_SIZE (GET_MODE (src));
}
- emit_call_insn (GEN_CALL_VALUE (par, operands[0], const0_rtx, NULL,
- const0_rtx));
+ emit_call_insn (gen_call_value (par, operands[0], const0_rtx, NULL));
size = 0;
/* function_arg () is called with this type just after all the args have
had their registers assigned. The rtx that function_arg returns from
this type is supposed to pass to 'gen_call' but currently it is not
- implemented (see macro GEN_CALL). */
+ implemented. */
if (type == void_type_node)
return NULL_RTX;
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, const0_rtx, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
/* Pass constm1 to indicate that it may expect a structure value, but
we don't know what size it is. */
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, constm1_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, constm1_rtx));
/* Save the function value registers. */
emit_move_insn (adjust_address (result, DImode, 0), valreg1);
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
{
int i;
- emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
static void max_operand_1 (rtx);
static int num_operands (rtx);
static void gen_proto (rtx);
-static void gen_macro (const char *, int, int);
/* Count the number of match_operand's found. */
return max_opno + 1;
}
-/* Print out a wrapper macro for a function which corrects the number
- of arguments it takes. Any missing arguments are assumed to be at
- the end. */
-static void
-gen_macro (const char *name, int real, int expect)
-{
- int i;
-
- gcc_assert (real <= expect);
- gcc_assert (real);
-
- /* #define GEN_CALL(A, B, C, D) gen_call((A), (B)) */
- fputs ("#define GEN_", stdout);
- for (i = 0; name[i]; i++)
- putchar (TOUPPER (name[i]));
-
- putchar ('(');
- for (i = 0; i < expect - 1; i++)
- printf ("%c, ", i + 'A');
- printf ("%c) gen_%s (", i + 'A', name);
-
- for (i = 0; i < real - 1; i++)
- printf ("(%c), ", i + 'A');
- printf ("(%c))\n", i + 'A');
-}
-
/* Print out prototype information for a generator function. If the
insn pattern has been elided, print out a dummy generator that
does nothing. */
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
- arguments too short. Instead of changing every md file to touch
- those operands, we wrap the prototypes in macros that take the
- correct number of arguments. */
- if (name[0] == 'c' || name[0] == 's')
- {
- if (!strcmp (name, "call")
- || !strcmp (name, "call_pop")
- || !strcmp (name, "sibcall")
- || !strcmp (name, "sibcall_pop"))
- gen_macro (name, num, 4);
- else if (!strcmp (name, "call_value")
- || !strcmp (name, "call_value_pop")
- || !strcmp (name, "sibcall_value")
- || !strcmp (name, "sibcall_value_pop"))
- gen_macro (name, num, 5);
- }
-
if (truth != 0)
printf ("extern rtx gen_%-*s (", max_id_len, name);
else
static struct queue_elem *define_subst_attr_queue;
static struct queue_elem **define_subst_attr_tail = &define_subst_attr_queue;
+/* Mapping from DEFINE_* rtxes to their location in the source file. */
+static hash_map <rtx, file_location> *rtx_locs;
+
static void remove_constraints (rtx);
static int is_predicable (struct queue_elem *);
else
info->index = -1;
+ if (!rtx_locs)
+ rtx_locs = new hash_map <rtx, file_location>;
+ rtx_locs->put (info->def, info->loc);
+
return true;
}
+/* Return the file location of DEFINE_* rtx X, which was previously
+ returned by read_md_rtx. */
+file_location
+get_file_location (rtx x)
+{
+ gcc_assert (rtx_locs);
+ file_location *entry = rtx_locs->get (x);
+ gcc_assert (entry);
+ return *entry;
+}
+
/* Return the number of possible INSN_CODEs. Only meaningful once the
whole file has been processed. */
unsigned int
extern void get_pattern_stats (struct pattern_stats *ranges, rtvec vec);
extern void compute_test_codes (rtx, file_location, char *);
+extern file_location get_file_location (rtx);
extern const char *get_emit_function (rtx);
extern bool needs_barrier_p (rtx);
from the C condition to the function name. */
static hash_map <nofree_string_hash, const char *> *have_funcs;
+/* Return true if the part of the prototype at P is for an argument
+ name. If so, point *END_OUT to the first character after the name.
+ If OPNO_OUT is nonnull, set *OPNO_OUT to the number of the associated
+ operand. If REQUIRED_OUT is nonnull, set *REQUIRED_OUT to whether the
+ .md pattern is required to match the operand. */
+
+static bool
+parse_argument (const char *p, const char **end_out,
+ unsigned int *opno_out = 0,
+ bool *required_out = 0)
+{
+ while (ISSPACE (*p))
+ p++;
+ if (p[0] == 'x' && ISDIGIT (p[1]))
+ {
+ p += 1;
+ if (required_out)
+ *required_out = true;
+ }
+ else if (p[0] == 'o' && p[1] == 'p' && p[2] == 't' && ISDIGIT (p[3]))
+ {
+ p += 3;
+ if (required_out)
+ *required_out = false;
+ }
+ else
+ return false;
+
+ char *endptr;
+ unsigned int opno = strtol (p, &endptr, 10);
+ if (opno_out)
+ *opno_out = opno;
+ *end_out = endptr;
+ return true;
+}
+
+
/* Output hook definitions for pattern NAME, which has target-insns.def
prototype PROTOTYPE. */
char *suffix = XALLOCAVEC (char, strlen (prototype) + 1);
i = 0;
unsigned int opno = 0;
+ unsigned int required_ops = 0;
+ unsigned int this_opno;
+ bool required_p;
for (const char *p = prototype; *p; ++p)
- if (*p == 'x' && ISDIGIT (p[1]))
+ if (parse_argument (p, &p, &this_opno, &required_p))
{
- /* This should be a parameter name of the form "x<OPNO>".
- That doesn't contribute to the suffix, so skip ahead and
- process the following character. */
- char *endptr;
- if ((unsigned int) strtol (p + 1, &endptr, 10) != opno
- || (*endptr != ',' && *endptr != ')'))
+ if (this_opno != opno || (*p != ',' && *p != ')'))
{
error ("invalid prototype for '%s'", name);
exit (FATAL_EXIT_CODE);
}
+ if (required_p && required_ops < opno)
+ {
+ error ("prototype for '%s' has required operands after"
+ " optional operands", name);
+ exit (FATAL_EXIT_CODE);
+ }
opno += 1;
- p = endptr;
+ if (required_p)
+ required_ops = opno;
+ /* Skip over ')'s. */
if (*p == ',')
suffix[i++] = '_';
}
const char *have_name = name;
if (rtx insn = insns->find_with_hash (name, hash))
{
+ pattern_stats stats;
+ get_pattern_stats (&stats, XVEC (insn, 1));
+ unsigned int actual_ops = stats.num_generator_args;
+ if (opno == required_ops && opno != actual_ops)
+ error_at (get_file_location (insn),
+ "'%s' must have %d operands (excluding match_dups)",
+ name, required_ops);
+ else if (actual_ops < required_ops)
+ error_at (get_file_location (insn),
+ "'%s' must have at least %d operands (excluding match_dups)",
+ name, required_ops);
+ else if (actual_ops > opno)
+ error_at (get_file_location (insn),
+ "'%s' must have no more than %d operands"
+ " (excluding match_dups)", name, opno);
+
const char *test = XSTR (insn, 2);
truth = maybe_eval_c_test (test);
gcc_assert (truth != 0);
have_name = entry;
}
printf ("\nstatic rtx_insn *\n");
- printf ("target_gen_%s %s\n", name, prototype);
- printf ("{\n");
+ printf ("target_gen_%s ", name);
+ /* Print the prototype with the argument names after ACTUAL_OPS
+ removed. */
+ const char *p = prototype, *end;
+ while (*p)
+ if (parse_argument (p, &end, &this_opno) && this_opno >= actual_ops)
+ p = end;
+ else
+ fputc (*p++, stdout);
+
+ printf ("\n{\n");
if (truth < 0)
printf (" gcc_checking_assert (targetm.have_%s ());\n", name);
printf (" return insnify (gen_%s (", name);
- for (i = 0; i < opno; ++i)
- printf ("%sx%d", i == 0 ? "" : ", ", i);
+ for (i = 0; i < actual_ops; ++i)
+ printf ("%s%s%d", i == 0 ? "" : ", ",
+ i < required_ops ? "x" : "opt", i);
printf ("));\n");
printf ("}\n");
}
*slot = xstrdup (suffix);
printf ("\nstatic rtx_insn *\n");
printf ("invalid_%s ", suffix);
+ /* Print the prototype with the argument names removed. */
const char *p = prototype;
while (*p)
- {
- if (p[0] == 'x' && ISDIGIT (p[1]))
- {
- char *endptr;
- strtol (p + 1, &endptr, 10);
- p = endptr;
- }
- else
- fputc (*p++, stdout);
- }
+ if (!parse_argument (p, &p))
+ fputc (*p++, stdout);
printf ("\n{\n");
printf (" gcc_unreachable ();\n");
printf ("}\n");
where NAME is the name of the pattern and PROTOTYPE is its C prototype.
The prototype should use parameter names of the form "x0", "x1", etc.
- Patterns that take no operands should have a prototype "(void)".
+ for the operands that the .md pattern is required to have, followed by
+ parameter names of the form "optN" for operands that the .md pattern
+ may choose to ignore. Patterns that never take operands should have
+ a prototype "(void)".
- Instructions should be documented in md.texi rather than here. */
+ Pattern names should be documented in md.texi rather than here. */
DEF_TARGET_INSN (allocate_stack, (rtx x0, rtx x1))
DEF_TARGET_INSN (atomic_test_and_set, (rtx x0, rtx x1, rtx x2))
DEF_TARGET_INSN (builtin_longjmp, (rtx x0))
DEF_TARGET_INSN (builtin_setjmp_receiver, (rtx x0))
DEF_TARGET_INSN (builtin_setjmp_setup, (rtx x0))
DEF_TARGET_INSN (canonicalize_funcptr_for_compare, (rtx x0, rtx x1))
+DEF_TARGET_INSN (call, (rtx x0, rtx opt1, rtx opt2, rtx opt3))
+DEF_TARGET_INSN (call_pop, (rtx x0, rtx opt1, rtx opt2, rtx opt3))
+DEF_TARGET_INSN (call_value, (rtx x0, rtx x1, rtx opt2, rtx opt3, rtx opt4))
+DEF_TARGET_INSN (call_value_pop, (rtx x0, rtx x1, rtx opt2, rtx opt3,
+ rtx opt4))
DEF_TARGET_INSN (casesi, (rtx x0, rtx x1, rtx x2, rtx x3, rtx x4))
DEF_TARGET_INSN (check_stack, (rtx x0))
DEF_TARGET_INSN (clear_cache, (rtx x0, rtx x1))
DEF_TARGET_INSN (save_stack_block, (rtx x0, rtx x1))
DEF_TARGET_INSN (save_stack_function, (rtx x0, rtx x1))
DEF_TARGET_INSN (save_stack_nonlocal, (rtx x0, rtx x1))
+DEF_TARGET_INSN (sibcall, (rtx x0, rtx opt1, rtx opt2, rtx opt3))
DEF_TARGET_INSN (sibcall_epilogue, (void))
+DEF_TARGET_INSN (sibcall_value, (rtx x0, rtx x1, rtx opt2, rtx opt3,
+ rtx opt4))
DEF_TARGET_INSN (simple_return, (void))
DEF_TARGET_INSN (split_stack_prologue, (void))
DEF_TARGET_INSN (split_stack_space_check, (rtx x0, rtx x1))