aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <bonzini@gnu.org>2007-07-05 20:04:36 +0000
committerPaolo Bonzini <bonzini@gcc.gnu.org>2007-07-05 20:04:36 +0000
commitd8d72314c4667d88f62059c0964ea37756676f29 (patch)
treed66aee4fdb3f5db795e8193be9208dcc7e69501e
parent2ab16fe0d1c891de826310f2c0a48641a1de65f4 (diff)
downloadgcc-d8d72314c4667d88f62059c0964ea37756676f29.zip
gcc-d8d72314c4667d88f62059c0964ea37756676f29.tar.gz
gcc-d8d72314c4667d88f62059c0964ea37756676f29.tar.bz2
function.c (match_asm_constraints_1, [...]): New.
2007-07-05 Paolo Bonzini <bonzini@gnu.org> * function.c (match_asm_constraints_1, rest_of_match_asm_constraints, pass_match_asm_constraints): New. * passes.c (init_optimization_passes): Add new pass. * stmt.c (expand_asm_operands): Set cfun->has_asm_statement. * function.h (struct function): Add has_asm_statement bit. (current_function_has_asm_statement): New. * tree-pass.h (pass_match_asm_constraints): New. From-SVN: r126385
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/function.c137
-rw-r--r--gcc/function.h4
-rw-r--r--gcc/passes.c1
-rw-r--r--gcc/stmt.c1
-rw-r--r--gcc/testsuite/gcc.target/i386/pr21291.c2
-rw-r--r--gcc/tree-pass.h1
7 files changed, 155 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a8ff7c0..30e5648 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2007-07-05 Paolo Bonzini <bonzini@gnu.org>
+
+ * function.c (match_asm_constraints_1, rest_of_match_asm_constraints,
+ pass_match_asm_constraints): New.
+ * passes.c (init_optimization_passes): Add new pass.
+ * stmt.c (expand_asm_operands): Set cfun->has_asm_statement.
+ * function.h (struct function): Add has_asm_statement bit.
+ (current_function_has_asm_statement): New.
+ * tree-pass.h (pass_match_asm_constraints): New.
+
2007-07-05 Richard Sandiford <rsandifo@nildram.co.uk>
* config/mips/mips.c (mips_file_start): Avoid declaration
diff --git a/gcc/function.c b/gcc/function.c
index 10fe7fe..a01bd93 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -5504,6 +5504,143 @@ struct tree_opt_pass pass_thread_prologue_and_epilogue =
TODO_ggc_collect, /* todo_flags_finish */
'w' /* letter */
};
+
+
+/* This mini-pass fixes fall-out from SSA in asm statements that have
+ in-out constraints. Say you start with
+
+ orig = inout;
+ asm ("": "+mr" (inout));
+ use (orig);
+
+ which is transformed very early to use explicit output and match operands:
+
+ orig = inout;
+ asm ("": "=mr" (inout) : "0" (inout));
+ use (orig);
+
+ Or, after SSA and copyprop,
+
+ asm ("": "=mr" (inout_2) : "0" (inout_1));
+ use (inout_1);
+
+ Clearly inout_2 and inout_1 can't be coalesced easily anymore, as
+ they represent two separate values, so they will get different pseudo
+ registers during expansion. Then, since the two operands need to match
+ per the constraints, but use different pseudo registers, reload can
+ only register a reload for these operands. But reloads can only be
+ satisfied by hardregs, not by memory, so we need a register for this
+ reload, just because we are presented with non-matching operands.
+ So, even though we allow memory for this operand, no memory can be
+ used for it, just because the two operands don't match. This can
+ cause reload failures on register-starved targets.
+
+ So it's a symptom of reload not being able to use memory for reloads
+ or, alternatively it's also a symptom of both operands not coming into
+ reload as matching (in which case the pseudo could go to memory just
+ fine, as the alternative allows it, and no reload would be necessary).
+ We fix the latter problem here, by transforming
+
+ asm ("": "=mr" (inout_2) : "0" (inout_1));
+
+ back to
+
+ inout_2 = inout_1;
+ asm ("": "=mr" (inout_2) : "0" (inout_2)); */
+
+static void
+match_asm_constraints_1 (rtx insn, rtx *p_sets, int noutputs)
+{
+ int i;
+ bool changed = false;
+ rtx op = SET_SRC (p_sets[0]);
+ int ninputs = ASM_OPERANDS_INPUT_LENGTH (op);
+ rtvec inputs = ASM_OPERANDS_INPUT_VEC (op);
+
+ for (i = 0; i < ninputs; i++)
+ {
+ rtx input, output, insns;
+ const char *constraint = ASM_OPERANDS_INPUT_CONSTRAINT (op, i);
+ char *end;
+ int match;
+
+ match = strtoul (constraint, &end, 10);
+ if (end == constraint)
+ continue;
+
+ gcc_assert (match < noutputs);
+ output = SET_DEST (p_sets[match]);
+ input = RTVEC_ELT (inputs, i);
+ if (rtx_equal_p (output, input)
+ || (GET_MODE (input) != VOIDmode
+ && GET_MODE (input) != GET_MODE (output)))
+ continue;
+
+ start_sequence ();
+ emit_move_insn (copy_rtx (output), input);
+ RTVEC_ELT (inputs, i) = copy_rtx (output);
+ insns = get_insns ();
+ end_sequence ();
+
+ emit_insn_before (insns, insn);
+ changed = true;
+ }
+
+ if (changed)
+ df_insn_rescan (insn);
+}
+
+static unsigned
+rest_of_match_asm_constraints (void)
+{
+ basic_block bb;
+ rtx insn, pat, *p_sets;
+ int noutputs;
+
+ if (!cfun->has_asm_statement)
+ return 0;
+
+ df_set_flags (DF_DEFER_INSN_RESCAN);
+ FOR_EACH_BB (bb)
+ {
+ FOR_BB_INSNS (bb, insn)
+ {
+ if (!INSN_P (insn))
+ continue;
+
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) == PARALLEL)
+ p_sets = &XVECEXP (pat, 0, 0), noutputs = XVECLEN (pat, 0);
+ else if (GET_CODE (pat) == SET)
+ p_sets = &PATTERN (insn), noutputs = 1;
+ else
+ continue;
+
+ if (GET_CODE (*p_sets) == SET
+ && GET_CODE (SET_SRC (*p_sets)) == ASM_OPERANDS)
+ match_asm_constraints_1 (insn, p_sets, noutputs);
+ }
+ }
+
+ return TODO_df_finish;
+}
+
+struct tree_opt_pass pass_match_asm_constraints =
+{
+ "asmcons", /* name */
+ NULL, /* gate */
+ rest_of_match_asm_constraints, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};
#include "gt-function.h"
diff --git a/gcc/function.h b/gcc/function.h
index bc3378b..0353983 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -414,6 +414,9 @@ struct function GTY(())
/* Nonzero if function being compiled has nonlocal gotos to parent
function. */
unsigned int has_nonlocal_goto : 1;
+
+ /* Nonzero if function being compiled has an asm statement. */
+ unsigned int has_asm_statement : 1;
/* Nonzero if the current function is a thunk, i.e., a lightweight
function implemented by the output_mi_thunk hook) that just
@@ -517,6 +520,7 @@ extern int trampolines_created;
#define current_function_has_nonlocal_label (cfun->has_nonlocal_label)
#define current_function_calls_unwind_init (cfun->calls_unwind_init)
#define current_function_has_nonlocal_goto (cfun->has_nonlocal_goto)
+#define current_function_has_asm_statement (cfun->has_asm_statement)
#define return_label (cfun->x_return_label)
#define naked_return_label (cfun->x_naked_return_label)
diff --git a/gcc/passes.c b/gcc/passes.c
index c954847..48ea68e 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -740,6 +740,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_stack_ptr_mod);
NEXT_PASS (pass_mode_switching);
NEXT_PASS (pass_see);
+ NEXT_PASS (pass_match_asm_constraints);
NEXT_PASS (pass_sms);
NEXT_PASS (pass_sched);
NEXT_PASS (pass_subregs_of_mode_init);
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 11cae96..2194a56 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -1078,6 +1078,7 @@ expand_asm_operands (tree string, tree outputs, tree inputs,
if (real_output_rtx[i])
emit_move_insn (real_output_rtx[i], output_rtx[i]);
+ cfun->has_asm_statement = 1;
free_temp_slots ();
}
diff --git a/gcc/testsuite/gcc.target/i386/pr21291.c b/gcc/testsuite/gcc.target/i386/pr21291.c
index f7348bd..b597509 100644
--- a/gcc/testsuite/gcc.target/i386/pr21291.c
+++ b/gcc/testsuite/gcc.target/i386/pr21291.c
@@ -3,7 +3,7 @@
6 registers that must not conflict. Add to that the PIC register,
the frame pointer, and the stack pointer, and we've run out of
registers on 32-bit targets. */
-/* { dg-do compile { target { { ! ilp32 } || nonpic } } } */
+/* { dg-do compile } */
/* { dg-options "-O" } */
typedef unsigned long bngdigit;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 333ec41..8838127 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -390,6 +390,7 @@ extern struct tree_opt_pass pass_initialize_regs;
extern struct tree_opt_pass pass_combine;
extern struct tree_opt_pass pass_if_after_combine;
extern struct tree_opt_pass pass_partition_blocks;
+extern struct tree_opt_pass pass_match_asm_constraints;
extern struct tree_opt_pass pass_regmove;
extern struct tree_opt_pass pass_split_all_insns;
extern struct tree_opt_pass pass_lower_subreg2;