This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: alpha himode reload problem
- To: Jim Wilson <wilson at cygnus dot com>
- Subject: Re: alpha himode reload problem
- From: Richard Henderson <rth at cygnus dot com>
- Date: Sun, 26 Oct 1997 16:09:47 -0800
- Cc: Richard Henderson <rth at cygnus dot com>, egcs at cygnus dot com, gcc2 at cygnus dot com
- References: <19971019222634.16858@dot.cygnus.com> <199710230201.TAA16133@cygnus.com>
- Reply-To: Richard Henderson <rth at cygnus dot com>
On Wed, Oct 22, 1997 at 07:01:01PM -0700, Jim Wilson wrote:
> Another way to fix this is to modify expand_asm_operands to fix the MEM
> during RTL generation. This seems more elegant.
Comments on the following? The recog.c changes were necesary to
get combine not to undo our hard work in stmt.c.
r~
Sun Oct 26 15:51:49 1997 Richard Henderson <rth@cygnus.com>
* recog.c (check_asm_operands): Don't allow combinations that reload
will simply have to undo later.
* stmt.c (study_asm_constraint): New function.
(expand_asm_operands): Use it. Force mem operand to reg if constraint
doesn't allow memory.
* tree.h: Prototype expand_asm_operands and study_asm_constraint.
Index: recog.c
===================================================================
RCS file: /cvs/cvsfiles/egcs/gcc/recog.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 recog.c
--- recog.c 1997/08/11 15:57:12 1.1.1.1
+++ recog.c 1997/10/26 23:44:52
@@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "flags.h"
#include "real.h"
+#include "tree.h"
#ifndef STACK_PUSH_CODE
#ifdef STACK_GROWS_DOWNWARD
@@ -110,6 +111,7 @@ check_asm_operands (x)
{
int noperands = asm_noperands (x);
rtx *operands;
+ char **constraints;
int i;
if (noperands < 0)
@@ -118,11 +120,40 @@ check_asm_operands (x)
return 1;
operands = (rtx *) alloca (noperands * sizeof (rtx));
- decode_asm_operands (x, operands, NULL_PTR, NULL_PTR, NULL_PTR);
+ constraints = (char **) alloca (noperands * sizeof (char *));
+ decode_asm_operands (x, operands, NULL_PTR, constraints, NULL_PTR);
for (i = 0; i < noperands; i++)
if (!general_operand (operands[i], VOIDmode))
return 0;
+
+ /* Prevent problems for reload by making sure mem and reg inputs stay
+ mem or reg inputs. */
+ for (i = noperands - ASM_OPERANDS_INPUT_LENGTH (x); i < noperands; ++i)
+ {
+ struct asm_constraint_summary sum;
+ study_asm_constraint (&sum, constraints[i]);
+ switch (GET_CODE (operands[i]))
+ {
+ case MEM:
+ if (! sum.allow_mem)
+ return 0;
+ break;
+ case REG:
+ case SUBREG:
+ if (! sum.allow_reg)
+ return 0;
+ break;
+ case CONST_INT:
+ case CONST_DOUBLE:
+ if (! sum.allow_const)
+ return 0;
+ break;
+
+ default:
+ break; /* ??? or return 0 */
+ }
+ }
return 1;
}
Index: stmt.c
===================================================================
RCS file: /cvs/cvsfiles/egcs/gcc/stmt.c,v
retrieving revision 1.2
diff -u -p -r1.2 stmt.c
--- stmt.c 1997/08/20 19:30:36 1.2
+++ stmt.c 1997/10/26 23:45:24
@@ -1371,6 +1371,63 @@ expand_asm (body)
last_expr_type = 0;
}
+/* Examine an asm constraint string and summarize important aspects. */
+
+void
+study_asm_constraint (sum, str)
+ struct asm_constraint_summary *sum;
+ const char *str;
+{
+ bzero(sum, sizeof(*sum));
+ while (*str)
+ switch (*str++)
+ {
+ case '+':
+ sum->found_plus = 1;
+ break;
+ case '=':
+ sum->found_equal = 1;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ int match = str[-1] - '0' + 1;
+ if (match > sum->found_match)
+ sum->found_match = match;
+ }
+ break;
+
+ case 'm': case 'o': case 'V': case '<': case '>':
+ sum->allow_mem = 1;
+ break;
+
+ case 'i': case 'n': case 's':
+ case 'I': case 'J': case 'K': case 'L': case 'M':
+ case 'N': case 'O': case 'P': case 'E': case 'F':
+ case 'G': case 'H':
+ sum->allow_const = 1;
+ break;
+
+ case 'r': case 'p':
+ default:
+ sum->allow_reg = 1;
+ break;
+
+ case 'g': case 'X':
+ sum->allow_reg = 1;
+ sum->allow_mem = 1;
+ sum->allow_const = 1;
+ break;
+
+ case '?': case '!': case '*': case '%': case '&': case ',':
+#ifdef EXTRA_CONSTRAINT
+ case 'Q': case 'R': case 'S': case 'T': case 'U':
+#endif
+ break;
+ }
+}
+
/* Generate RTL for an asm statement with arguments.
STRING is the instruction template.
OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
@@ -1441,67 +1498,47 @@ expand_asm_operands (string, outputs, in
tree val = TREE_VALUE (tail);
tree type = TREE_TYPE (val);
tree val1;
- int j;
- int found_equal = 0;
- int found_plus = 0;
- int allows_reg = 0;
+ struct asm_constraint_summary sum;
/* If there's an erroneous arg, emit no insn. */
if (TREE_TYPE (val) == error_mark_node)
return;
+ study_asm_constraint (&sum, TREE_STRING_POINTER (TREE_PURPOSE (tail)));
+
/* Make sure constraint has `=' and does not have `+'. Also, see
if it allows any register. Be liberal on the latter test, since
the worst that happens if we get it wrong is we issue an error
message. */
- for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
- switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
- {
- case '+':
- /* Make sure we can specify the matching operand. */
- if (i > 9)
- {
- error ("output operand constraint %d contains `+'", i);
- return;
- }
-
- /* Replace '+' with '='. */
- TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] = '=';
- found_plus = 1;
- break;
-
- case '=':
- found_equal = 1;
- break;
-
- case '?': case '!': case '*': case '%': case '&':
- case 'V': case 'm': case 'o': case '<': case '>':
- case 'E': case 'F': case 'G': case 'H': case 'X':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',':
-#ifdef EXTRA_CONSTRAINT
- case 'Q': case 'R': case 'S': case 'T': case 'U':
-#endif
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- error ("matching constraint not valid in output operand");
- break;
-
- case 'p': case 'g': case 'r':
- default:
- allows_reg = 1;
- break;
- }
+ if (sum.found_plus)
+ {
+ char *p;
- if (! found_equal && ! found_plus)
+ /* Make sure we can specify the matching operand. */
+ if (i > 9)
+ {
+ error ("output operand constraint %d contains `+'", i);
+ return;
+ }
+
+ /* Replace '+' with '='. */
+ p = strchr (TREE_STRING_POINTER (TREE_PURPOSE (tail)), '+');
+ do {
+ *p = '=';
+ p = strchr (p, '=');
+ } while (p);
+ }
+ if (! sum.found_equal && ! sum.found_plus)
{
error ("output operand constraint lacks `='");
return;
}
+ if (sum.found_match)
+ {
+ error ("matching constraint not valid in output operand");
+ return;
+ }
/* If an output operand is not a decl or indirect ref and our constraint
allows a register, make a temporary to act as an intermediate.
@@ -1512,17 +1549,17 @@ expand_asm_operands (string, outputs, in
|| (TREE_CODE_CLASS (TREE_CODE (val)) == 'd'
&& ! (GET_CODE (DECL_RTL (val)) == REG
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
- || ! allows_reg
- || found_plus)
+ || ! sum.allow_reg
+ || sum.found_plus)
{
- if (! allows_reg)
+ if (! sum.allow_reg)
mark_addressable (TREE_VALUE (tail));
output_rtx[i]
= expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode,
EXPAND_MEMORY_USE_WO);
- if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
+ if (! sum.allow_reg && GET_CODE (output_rtx[i]) != MEM)
error ("output number %d not directly addressable", i);
}
else
@@ -1531,7 +1568,7 @@ expand_asm_operands (string, outputs, in
TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
}
- if (found_plus)
+ if (sum.found_plus)
{
inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
inout_opnum[ninout++] = i;
@@ -1561,8 +1598,7 @@ expand_asm_operands (string, outputs, in
i = 0;
for (tail = inputs; tail; tail = TREE_CHAIN (tail))
{
- int j;
- int allows_reg = 0;
+ struct asm_constraint_summary sum;
/* If there's an erroneous arg, emit no insn,
because the ASM_INPUT would get VOIDmode
@@ -1576,47 +1612,31 @@ expand_asm_operands (string, outputs, in
return;
}
- /* Make sure constraint has neither `=' nor `+'. */
+ study_asm_constraint (&sum, TREE_STRING_POINTER (TREE_PURPOSE (tail)));
- for (j = 0; j < TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; j++)
- switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
- {
- case '+': case '=':
- error ("input operand constraint contains `%c'",
- TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]);
- return;
-
- case '?': case '!': case '*': case '%': case '&':
- case 'V': case 'm': case 'o': case '<': case '>':
- case 'E': case 'F': case 'G': case 'H': case 'X':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',':
-#ifdef EXTRA_CONSTRAINT
- case 'Q': case 'R': case 'S': case 'T': case 'U':
-#endif
- break;
+ /* Make sure constraint has neither `=' nor `+'. */
+ if (sum.found_plus || sum.found_equal)
+ {
+ error ("input operand constraint contains `%c'",
+ sum.found_plus ? '+' : '=');
+ return;
+ }
- /* Whether or not a numeric constraint allows a register is
- decided by the matching constraint, and so there is no need
- to do anything special with them. We must handle them in
- the default case, so that we don't unnecessarily force
- operands to memory. */
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]
- >= '0' + noutputs)
- error ("matching constraint references invalid operand number");
-
- /* ... fall through ... */
-
- case 'p': case 'g': case 'r':
- default:
- allows_reg = 1;
- break;
- }
+ /* Whether or not a numeric constraint allows a register is
+ decided by the matching constraint, and so there is no need
+ to do anything special with them. We must handle them in
+ the default case, so that we don't unnecessarily force
+ operands to memory. */
+ if (sum.found_match)
+ {
+ if (sum.found_match - 1 >= noutputs)
+ error ("matching constraint references invalid operand number");
+ /* ??? This is what the old code did. Shall we merge with the
+ real output constraint? */
+ sum.allow_reg = 1;
+ }
- if (! allows_reg)
+ if (! sum.allow_reg)
mark_addressable (TREE_VALUE (tail));
XVECEXP (body, 3, i) /* argvec */
@@ -1625,7 +1645,7 @@ expand_asm_operands (string, outputs, in
&& ! general_operand (XVECEXP (body, 3, i),
TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)))))
{
- if (allows_reg)
+ if (sum.allow_reg)
XVECEXP (body, 3, i)
= force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
XVECEXP (body, 3, i));
@@ -1635,7 +1655,7 @@ expand_asm_operands (string, outputs, in
XVECEXP (body, 3, i));
}
- if (! allows_reg
+ if (! sum.allow_reg
&& (GET_CODE (XVECEXP (body, 3, i)) == REG
|| GET_CODE (XVECEXP (body, 3, i)) == SUBREG
|| GET_CODE (XVECEXP (body, 3, i)) == CONCAT))
@@ -1645,6 +1665,14 @@ expand_asm_operands (string, outputs, in
emit_move_insn (memloc, XVECEXP (body, 3, i));
XVECEXP (body, 3, i) = memloc;
+ }
+
+ if (! sum.allow_mem && sum.allow_reg
+ && GET_CODE (XVECEXP (body, 3, i)) == MEM)
+ {
+ XVECEXP (body, 3, i)
+ = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
+ XVECEXP (body, 3, i));
}
XVECEXP (body, 4, i) /* constraints */
Index: tree.h
===================================================================
RCS file: /cvs/cvsfiles/egcs/gcc/tree.h,v
retrieving revision 1.8
diff -u -p -r1.8 tree.h
--- tree.h 1997/10/15 17:19:40 1.8
+++ tree.h 1997/10/26 23:45:36
@@ -1724,6 +1724,22 @@ extern int pushcase PROTO((tree,
extern int pushcase_range PROTO((tree, tree,
tree (*) (tree, tree),
tree, tree *));
+extern void expand_asm_operands PROTO((tree, tree, tree, tree,
+ int, char *, int));
+
+struct asm_constraint_summary
+{
+ unsigned found_plus : 1;
+ unsigned found_equal : 1;
+ unsigned found_match : 4;
+ unsigned allow_reg : 1;
+ unsigned allow_mem : 1;
+ unsigned allow_const : 1;
+};
+
+extern void study_asm_constraint PROTO((struct asm_constraint_summary *,
+ const char *));
+
/* In fold-const.c */