Commit 54f044eb by Jakub Jelinek Committed by Jakub Jelinek

re PR middle-end/44492 (auto-inc-dec pushes PRE_MODIFY/PRE_INC into inline asm operands)

	PR middle-end/44492
	* recog.h (struct recog_data): Add is_asm field.
	* recog.c (asm_operand_ok, constrain_operands): If neither < nor > is
	present in constraints of inline-asm operand and memory operand
	contains {PRE,POST}_{INC,DEC,MODIFY}, return 0.
	(extract_insn): Initialize recog_data.is_asm.
	* doc/md.texi (Constraints): Document operand side-effect rules.

	* g++.dg/torture/pr44492.C: New test.

From-SVN: r161328
parent c7d42abb
2010-06-24 Jakub Jelinek <jakub@redhat.com>
PR middle-end/44492
* recog.h (struct recog_data): Add is_asm field.
* recog.c (asm_operand_ok, constrain_operands): If neither < nor > is
present in constraints of inline-asm operand and memory operand
contains {PRE,POST}_{INC,DEC,MODIFY}, return 0.
(extract_insn): Initialize recog_data.is_asm.
* doc/md.texi (Constraints): Document operand side-effect rules.
2010-06-24 Andi Kleen <ak@linux.intel.com> 2010-06-24 Andi Kleen <ak@linux.intel.com>
* c-parser.c (c_parser_conditional_expression): * c-parser.c (c_parser_conditional_expression):
......
...@@ -1052,6 +1052,10 @@ an operand may be in a register, and which kinds of register; whether the ...@@ -1052,6 +1052,10 @@ an operand may be in a register, and which kinds of register; whether the
operand can be a memory reference, and which kinds of address; whether the operand can be a memory reference, and which kinds of address; whether the
operand may be an immediate constant, and which possible values it may operand may be an immediate constant, and which possible values it may
have. Constraints can also require two operands to match. have. Constraints can also require two operands to match.
Side-effects aren't allowed in operands of inline @code{asm}, unless
@samp{<} or @samp{>} constraints are used, because there is no guarantee
that the side-effects will happen exactly once in an instruction that can update
the addressing register.
@ifset INTERNALS @ifset INTERNALS
@menu @menu
...@@ -1129,12 +1133,21 @@ would fit the @samp{m} constraint but not the @samp{o} constraint. ...@@ -1129,12 +1133,21 @@ would fit the @samp{m} constraint but not the @samp{o} constraint.
@cindex @samp{<} in constraint @cindex @samp{<} in constraint
@item @samp{<} @item @samp{<}
A memory operand with autodecrement addressing (either predecrement or A memory operand with autodecrement addressing (either predecrement or
postdecrement) is allowed. postdecrement) is allowed. In inline @code{asm} this constraint is only
allowed if the operand is used exactly once in an instruction that can
handle the side-effects. Not using an operand with @samp{<} in constraint
string in the inline @code{asm} pattern at all or using it in multiple
instructions isn't valid, because the side-effects wouldn't be performed
or would be performed more than once. Furthermore, on some targets
the operand with @samp{<} in constraint string must be accompanied by
special instruction suffixes like @code{%U0} instruction suffix on PowerPC
or @code{%P0} on IA-64.
@cindex @samp{>} in constraint @cindex @samp{>} in constraint
@item @samp{>} @item @samp{>}
A memory operand with autoincrement addressing (either preincrement or A memory operand with autoincrement addressing (either preincrement or
postincrement) is allowed. postincrement) is allowed. In inline @code{asm} the same restrictions
as for @samp{<} apply.
@cindex @samp{r} in constraint @cindex @samp{r} in constraint
@cindex registers in constraints @cindex registers in constraints
......
...@@ -1601,6 +1601,9 @@ int ...@@ -1601,6 +1601,9 @@ int
asm_operand_ok (rtx op, const char *constraint, const char **constraints) asm_operand_ok (rtx op, const char *constraint, const char **constraints)
{ {
int result = 0; int result = 0;
#ifdef AUTO_INC_DEC
bool incdec_ok = false;
#endif
/* Use constrain_operands after reload. */ /* Use constrain_operands after reload. */
gcc_assert (!reload_completed); gcc_assert (!reload_completed);
...@@ -1608,7 +1611,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) ...@@ -1608,7 +1611,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
/* Empty constraint string is the same as "X,...,X", i.e. X for as /* Empty constraint string is the same as "X,...,X", i.e. X for as
many alternatives as required to match the other operands. */ many alternatives as required to match the other operands. */
if (*constraint == '\0') if (*constraint == '\0')
return 1; result = 1;
while (*constraint) while (*constraint)
{ {
...@@ -1685,6 +1688,9 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) ...@@ -1685,6 +1688,9 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
|| GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == PRE_DEC
|| GET_CODE (XEXP (op, 0)) == POST_DEC)) || GET_CODE (XEXP (op, 0)) == POST_DEC))
result = 1; result = 1;
#ifdef AUTO_INC_DEC
incdec_ok = true;
#endif
break; break;
case '>': case '>':
...@@ -1693,6 +1699,9 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) ...@@ -1693,6 +1699,9 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
|| GET_CODE (XEXP (op, 0)) == PRE_INC || GET_CODE (XEXP (op, 0)) == PRE_INC
|| GET_CODE (XEXP (op, 0)) == POST_INC)) || GET_CODE (XEXP (op, 0)) == POST_INC))
result = 1; result = 1;
#ifdef AUTO_INC_DEC
incdec_ok = true;
#endif
break; break;
case 'E': case 'E':
...@@ -1814,6 +1823,23 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) ...@@ -1814,6 +1823,23 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
return 0; return 0;
} }
#ifdef AUTO_INC_DEC
/* For operands without < or > constraints reject side-effects. */
if (!incdec_ok && result && MEM_P (op))
switch (GET_CODE (XEXP (op, 0)))
{
case PRE_INC:
case POST_INC:
case PRE_DEC:
case POST_DEC:
case PRE_MODIFY:
case POST_MODIFY:
return 0;
default:
break;
}
#endif
return result; return result;
} }
...@@ -2039,6 +2065,7 @@ extract_insn (rtx insn) ...@@ -2039,6 +2065,7 @@ extract_insn (rtx insn)
recog_data.n_operands = 0; recog_data.n_operands = 0;
recog_data.n_alternatives = 0; recog_data.n_alternatives = 0;
recog_data.n_dups = 0; recog_data.n_dups = 0;
recog_data.is_asm = false;
switch (GET_CODE (body)) switch (GET_CODE (body))
{ {
...@@ -2085,6 +2112,7 @@ extract_insn (rtx insn) ...@@ -2085,6 +2112,7 @@ extract_insn (rtx insn)
while (*p) while (*p)
recog_data.n_alternatives += (*p++ == ','); recog_data.n_alternatives += (*p++ == ',');
} }
recog_data.is_asm = true;
break; break;
} }
fatal_insn_not_found (insn); fatal_insn_not_found (insn);
...@@ -2699,6 +2727,30 @@ constrain_operands (int strict) ...@@ -2699,6 +2727,30 @@ constrain_operands (int strict)
= recog_data.operand[funny_match[funny_match_index].this_op]; = recog_data.operand[funny_match[funny_match_index].this_op];
} }
#ifdef AUTO_INC_DEC
/* For operands without < or > constraints reject side-effects. */
if (recog_data.is_asm)
{
for (opno = 0; opno < recog_data.n_operands; opno++)
if (MEM_P (recog_data.operand[opno]))
switch (GET_CODE (XEXP (recog_data.operand[opno], 0)))
{
case PRE_INC:
case POST_INC:
case PRE_DEC:
case POST_DEC:
case PRE_MODIFY:
case POST_MODIFY:
if (strchr (recog_data.constraints[opno], '<') == NULL
|| strchr (recog_data.constraints[opno], '>')
== NULL)
return 0;
break;
default:
break;
}
}
#endif
return 1; return 1;
} }
} }
......
...@@ -230,6 +230,9 @@ struct recog_data ...@@ -230,6 +230,9 @@ struct recog_data
/* The number of alternatives in the constraints for the insn. */ /* The number of alternatives in the constraints for the insn. */
char n_alternatives; char n_alternatives;
/* True if insn is ASM_OPERANDS. */
bool is_asm;
/* Specifies whether an insn alternative is enabled using the /* Specifies whether an insn alternative is enabled using the
`enabled' attribute in the insn pattern definition. For back `enabled' attribute in the insn pattern definition. For back
ends not using the `enabled' attribute the array fields are ends not using the `enabled' attribute the array fields are
......
2010-06-24 Jakub Jelinek <jakub@redhat.com>
PR middle-end/44492
* g++.dg/torture/pr44492.C: New test.
2010-06-24 Andi Kleen <ak@linux.intel.com> 2010-06-24 Andi Kleen <ak@linux.intel.com>
* c-c++-common/warn-omitted-condop.c: New. * c-c++-common/warn-omitted-condop.c: New.
......
// PR middle-end/44492
// { dg-do run }
struct T { unsigned long p; };
struct S { T a, b, c; unsigned d; };
__attribute__((noinline))
void
bar (const T &x, const T &y)
{
if (x.p != 0x2348 || y.p != 0x2346)
__builtin_abort ();
}
__attribute__((noinline))
void
foo (S &s, T e)
{
unsigned long a = e.p;
unsigned long b = s.b.p;
__asm__ volatile ("" : : "rm" (a), "rm" (b));
bar (e, s.b);
}
int
main ()
{
S s = { { 0x2345 }, { 0x2346 }, { 0x2347 }, 6 };
T t = { 0x2348 };
foo (s, t);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment