diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 71c692e91a0..8cbf7c69eaf 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2015-04-17 Jakub Jelinek + + PR target/65689 + * genpreds.c (struct constraint_data): Add maybe_allows_reg and + maybe_allows_mem bitfields. + (maybe_allows_none_start, maybe_allows_none_end, + maybe_allows_reg_start, maybe_allows_reg_end, maybe_allows_mem_start, + maybe_allows_mem_end): New variables. + (compute_maybe_allows): New function. + (add_constraint): Use it to initialize maybe_allows_reg and + maybe_allows_mem fields. + (choose_enum_order): Sort the non-is_register/is_const_int/is_memory/ + is_address constraints such that those that allow neither mem nor + reg come first, then those that only allow reg but not mem, then + those that only allow mem but not reg, then the rest. + (write_allows_reg_mem_function): New function. + (write_tm_preds_h): Call it. + * stmt.c (parse_output_constraint, parse_input_constraint): Use + the generated insn_extra_constraint_allows_reg_mem function + instead of always setting *allows_reg = true; *allows_mem = true; + for unknown extra constraints. + 2015-04-17 H.J. Lu PR target/65780 diff --git a/gcc/genpreds.c b/gcc/genpreds.c index 1eb3368cf64..1dcb76936eb 100644 --- a/gcc/genpreds.c +++ b/gcc/genpreds.c @@ -640,12 +640,14 @@ struct constraint_data const char *regclass; /* for register constraints */ rtx exp; /* for other constraints */ unsigned int lineno; /* line of definition */ - unsigned int is_register : 1; - unsigned int is_const_int : 1; - unsigned int is_const_dbl : 1; - unsigned int is_extra : 1; - unsigned int is_memory : 1; - unsigned int is_address : 1; + unsigned int is_register : 1; + unsigned int is_const_int : 1; + unsigned int is_const_dbl : 1; + unsigned int is_extra : 1; + unsigned int is_memory : 1; + unsigned int is_address : 1; + unsigned int maybe_allows_reg : 1; + unsigned int maybe_allows_mem : 1; }; /* Overview of all constraints beginning with a given letter. */ @@ -691,6 +693,9 @@ static unsigned int satisfied_start; static unsigned int const_int_start, const_int_end; static unsigned int memory_start, memory_end; static unsigned int address_start, address_end; +static unsigned int maybe_allows_none_start, maybe_allows_none_end; +static unsigned int maybe_allows_reg_start, maybe_allows_reg_end; +static unsigned int maybe_allows_mem_start, maybe_allows_mem_end; /* Convert NAME, which contains angle brackets and/or underscores, to a string that can be used as part of a C identifier. The string @@ -711,6 +716,34 @@ mangle (const char *name) return XOBFINISH (rtl_obstack, const char *); } +/* Return a bitmask, bit 1 if EXP maybe allows a REG/SUBREG, 2 if EXP + maybe allows a MEM. Bits should be clear only when we are sure it + will not allow a REG/SUBREG or a MEM. */ +static int +compute_maybe_allows (rtx exp) +{ + switch (GET_CODE (exp)) + { + case IF_THEN_ELSE: + /* Conservative answer is like IOR, of the THEN and ELSE branches. */ + return compute_maybe_allows (XEXP (exp, 1)) + | compute_maybe_allows (XEXP (exp, 2)); + case AND: + return compute_maybe_allows (XEXP (exp, 0)) + & compute_maybe_allows (XEXP (exp, 1)); + case IOR: + return compute_maybe_allows (XEXP (exp, 0)) + | compute_maybe_allows (XEXP (exp, 1)); + case MATCH_CODE: + if (*XSTR (exp, 1) == '\0') + return (strstr (XSTR (exp, 0), "reg") != NULL ? 1 : 0) + | (strstr (XSTR (exp, 0), "mem") != NULL ? 2 : 0); + /* FALLTHRU */ + default: + return 3; + } +} + /* Add one constraint, of any sort, to the tables. NAME is its name; REGCLASS is the register class, if any; EXP is the expression to test, if any; IS_MEMORY and IS_ADDRESS indicate memory and address @@ -866,6 +899,11 @@ add_constraint (const char *name, const char *regclass, c->is_extra = !(regclass || is_const_int || is_const_dbl); c->is_memory = is_memory; c->is_address = is_address; + int maybe_allows = 3; + if (exp) + maybe_allows = compute_maybe_allows (exp); + c->maybe_allows_reg = (maybe_allows & 1) != 0; + c->maybe_allows_mem = (maybe_allows & 2) != 0; c->next_this_letter = *slot; *slot = c; @@ -940,8 +978,30 @@ choose_enum_order (void) enum_order[next++] = c; address_end = next; + maybe_allows_none_start = next; FOR_ALL_CONSTRAINTS (c) - if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address) + if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address + && !c->maybe_allows_reg && !c->maybe_allows_mem) + enum_order[next++] = c; + maybe_allows_none_end = next; + + maybe_allows_reg_start = next; + FOR_ALL_CONSTRAINTS (c) + if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address + && c->maybe_allows_reg && !c->maybe_allows_mem) + enum_order[next++] = c; + maybe_allows_reg_end = next; + + maybe_allows_mem_start = next; + FOR_ALL_CONSTRAINTS (c) + if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address + && !c->maybe_allows_reg && c->maybe_allows_mem) + enum_order[next++] = c; + maybe_allows_mem_end = next; + + FOR_ALL_CONSTRAINTS (c) + if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address + && c->maybe_allows_reg && c->maybe_allows_mem) enum_order[next++] = c; gcc_assert (next == num_constraints); } @@ -1229,6 +1289,41 @@ write_range_function (const char *name, unsigned int start, unsigned int end) "}\n\n", name); } +/* Write a definition for insn_extra_constraint_allows_reg_mem function. */ +static void +write_allows_reg_mem_function (void) +{ + printf ("static inline void\n" + "insn_extra_constraint_allows_reg_mem (enum constraint_num c,\n" + "\t\t\t\t bool *allows_reg, bool *allows_mem)\n" + "{\n"); + if (maybe_allows_none_start != maybe_allows_none_end) + printf (" if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n" + " return;\n", + enum_order[maybe_allows_none_start]->c_name, + enum_order[maybe_allows_none_end - 1]->c_name); + if (maybe_allows_reg_start != maybe_allows_reg_end) + printf (" if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n" + " {\n" + " *allows_reg = true;\n" + " return;\n" + " }\n", + enum_order[maybe_allows_reg_start]->c_name, + enum_order[maybe_allows_reg_end - 1]->c_name); + if (maybe_allows_mem_start != maybe_allows_mem_end) + printf (" if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n" + " {\n" + " *allows_mem = true;\n" + " return;\n" + " }\n", + enum_order[maybe_allows_mem_start]->c_name, + enum_order[maybe_allows_mem_end - 1]->c_name); + printf (" (void) c;\n" + " *allows_reg = true;\n" + " *allows_mem = true;\n" + "}\n\n"); +} + /* VEC is a list of key/value pairs, with the keys being lower bounds of a range. Output a decision tree that handles the keys covered by [VEC[START], VEC[END]), returning FALLBACK for keys lower then VEC[START]'s. @@ -1326,6 +1421,7 @@ write_tm_preds_h (void) memory_start, memory_end); write_range_function ("insn_extra_address_constraint", address_start, address_end); + write_allows_reg_mem_function (); if (constraint_max_namelen > 1) { diff --git a/gcc/stmt.c b/gcc/stmt.c index 45dc45fd049..6c62a129601 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -342,13 +342,7 @@ parse_output_constraint (const char **constraint_p, int operand_num, else if (insn_extra_memory_constraint (cn)) *allows_mem = true; else - { - /* Otherwise we can't assume anything about the nature of - the constraint except that it isn't purely registers. - Treat it like "g" and hope for the best. */ - *allows_reg = true; - *allows_mem = true; - } + insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem); break; } @@ -465,13 +459,7 @@ parse_input_constraint (const char **constraint_p, int input_num, else if (insn_extra_memory_constraint (cn)) *allows_mem = true; else - { - /* Otherwise we can't assume anything about the nature of - the constraint except that it isn't purely registers. - Treat it like "g" and hope for the best. */ - *allows_reg = true; - *allows_mem = true; - } + insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem); break; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c6bd2eda4b6..cec5fa10bfe 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-04-17 Jakub Jelinek + + PR target/65689 + * gcc.target/aarch64/c-output-template-4.c: New test. + 2015-04-17 H.J. Lu PR target/65780 diff --git a/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c b/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c new file mode 100644 index 00000000000..c5a93915af1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +void +test (void) +{ + __asm__ ("@ %c0" : : "S" (&test + 4)); +} + +/* { dg-final { scan-assembler "@ test\\+4" } } */