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
This commit is contained in:
parent
2ab16fe0d1
commit
d8d72314c4
7 changed files with 155 additions and 1 deletions
|
@ -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
|
||||
|
|
137
gcc/function.c
137
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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue