2010-06-24 Jakub Jelinek 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. --- gcc/doc/md.texi (revision 161327) +++ gcc/doc/md.texi (revision 161328) @@ -1052,6 +1052,10 @@ an operand may be in a register, and whi 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 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 @menu @@ -1129,12 +1133,21 @@ would fit the @samp{m} constraint but no @cindex @samp{<} in constraint @item @samp{<} 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 @item @samp{>} 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 registers in constraints --- gcc/recog.c (revision 161327) +++ gcc/recog.c (revision 161328) @@ -1601,6 +1601,9 @@ int asm_operand_ok (rtx op, const char *constraint, const char **constraints) { int result = 0; +#ifdef AUTO_INC_DEC + bool incdec_ok = false; +#endif /* Use constrain_operands after reload. */ gcc_assert (!reload_completed); @@ -1608,7 +1611,7 @@ asm_operand_ok (rtx op, const char *cons /* Empty constraint string is the same as "X,...,X", i.e. X for as many alternatives as required to match the other operands. */ if (*constraint == '\0') - return 1; + result = 1; while (*constraint) { @@ -1685,6 +1688,9 @@ asm_operand_ok (rtx op, const char *cons || GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == POST_DEC)) result = 1; +#ifdef AUTO_INC_DEC + incdec_ok = true; +#endif break; case '>': @@ -1693,6 +1699,9 @@ asm_operand_ok (rtx op, const char *cons || GET_CODE (XEXP (op, 0)) == PRE_INC || GET_CODE (XEXP (op, 0)) == POST_INC)) result = 1; +#ifdef AUTO_INC_DEC + incdec_ok = true; +#endif break; case 'E': @@ -1814,6 +1823,23 @@ asm_operand_ok (rtx op, const char *cons 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; } @@ -2039,6 +2065,7 @@ extract_insn (rtx insn) recog_data.n_operands = 0; recog_data.n_alternatives = 0; recog_data.n_dups = 0; + recog_data.is_asm = false; switch (GET_CODE (body)) { @@ -2085,6 +2112,7 @@ extract_insn (rtx insn) while (*p) recog_data.n_alternatives += (*p++ == ','); } + recog_data.is_asm = true; break; } fatal_insn_not_found (insn); @@ -2699,6 +2727,30 @@ constrain_operands (int strict) = 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; } } --- gcc/recog.h (revision 161327) +++ gcc/recog.h (revision 161328) @@ -230,6 +230,9 @@ struct recog_data /* The number of alternatives in the constraints for the insn. */ char n_alternatives; + /* True if insn is ASM_OPERANDS. */ + bool is_asm; + /* Specifies whether an insn alternative is enabled using the `enabled' attribute in the insn pattern definition. For back ends not using the `enabled' attribute the array fields are --- gcc/testsuite/g++.dg/torture/pr44492.C (revision 0) +++ gcc/testsuite/g++.dg/torture/pr44492.C (revision 161328) @@ -0,0 +1,31 @@ +// 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); +}