aboutsummaryrefslogtreecommitdiff
path: root/gcc/function.c
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2007-09-28 13:31:50 +0000
committerMichael Matz <matz@gcc.gnu.org>2007-09-28 13:31:50 +0000
commit53220215a8926ffe3aef50e7a79f8e3bb15859f3 (patch)
tree4b854e7c1b701afce564e0ce3d39398bcbd379fa /gcc/function.c
parentbd69daef031ae2afefc43f72e5050e006dc142fe (diff)
downloadgcc-53220215a8926ffe3aef50e7a79f8e3bb15859f3.zip
gcc-53220215a8926ffe3aef50e7a79f8e3bb15859f3.tar.gz
gcc-53220215a8926ffe3aef50e7a79f8e3bb15859f3.tar.bz2
re PR rtl-optimization/33552 (wrong code for multiple output asm, wrong df?)
PR rtl-optimization/33552 * function.c (match_asm_constraints_1): Check for overlap in inputs and replace all occurences. From-SVN: r128864
Diffstat (limited to 'gcc/function.c')
-rw-r--r--gcc/function.c51
1 files changed, 46 insertions, 5 deletions
diff --git a/gcc/function.c b/gcc/function.c
index 5f2dd48..c373684 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -5663,7 +5663,7 @@ match_asm_constraints_1 (rtx insn, rtx *p_sets, int noutputs)
rtx input, output, insns;
const char *constraint = ASM_OPERANDS_INPUT_CONSTRAINT (op, i);
char *end;
- int match;
+ int match, j;
match = strtoul (constraint, &end, 10);
if (end == constraint)
@@ -5672,18 +5672,59 @@ match_asm_constraints_1 (rtx insn, rtx *p_sets, int noutputs)
gcc_assert (match < noutputs);
output = SET_DEST (p_sets[match]);
input = RTVEC_ELT (inputs, i);
- if (rtx_equal_p (output, input)
+ /* Only do the transformation for pseudos. */
+ if (! REG_P (output)
+ || rtx_equal_p (output, input)
|| (GET_MODE (input) != VOIDmode
&& GET_MODE (input) != GET_MODE (output)))
continue;
+ /* We can't do anything if the output is also used as input,
+ as we're going to overwrite it. */
+ for (j = 0; j < ninputs; j++)
+ if (reg_overlap_mentioned_p (output, RTVEC_ELT (inputs, j)))
+ break;
+ if (j != ninputs)
+ continue;
+
start_sequence ();
- emit_move_insn (copy_rtx (output), input);
- RTVEC_ELT (inputs, i) = copy_rtx (output);
+ emit_move_insn (output, input);
insns = get_insns ();
end_sequence ();
-
emit_insn_before (insns, insn);
+
+ /* Now replace all mentions of the input with output. We can't
+ just replace the occurence in inputs[i], as the register might
+ also be used in some other input (or even in an address of an
+ output), which would mean possibly increasing the number of
+ inputs by one (namely 'output' in addition), which might pose
+ a too complicated problem for reload to solve. E.g. this situation:
+
+ asm ("" : "=r" (output), "=m" (input) : "0" (input))
+
+ Here 'input' is used in two occurences as input (once for the
+ input operand, once for the address in the second output operand).
+ If we would replace only the occurence of the input operand (to
+ make the matching) we would be left with this:
+
+ output = input
+ asm ("" : "=r" (output), "=m" (input) : "0" (output))
+
+ Now we suddenly have two different input values (containing the same
+ value, but different pseudos) where we formerly had only one.
+ With more complicated asms this might lead to reload failures
+ which wouldn't have happen without this pass. So, iterate over
+ all operands and replace all occurences of the register used. */
+ for (j = 0; j < noutputs; j++)
+ if (!rtx_equal_p (SET_DEST (p_sets[j]), output)
+ && reg_overlap_mentioned_p (input, SET_DEST (p_sets[j])))
+ SET_DEST (p_sets[j]) = replace_rtx (SET_DEST (p_sets[j]),
+ input, output);
+ for (j = 0; j < ninputs; j++)
+ if (reg_overlap_mentioned_p (input, RTVEC_ELT (inputs, j)))
+ RTVEC_ELT (inputs, j) = replace_rtx (RTVEC_ELT (inputs, j),
+ input, output);
+
changed = true;
}