diff options
author | Paolo Bonzini <bonzini@gnu.org> | 2007-07-05 20:04:36 +0000 |
---|---|---|
committer | Paolo Bonzini <bonzini@gnu.org> | 2007-07-05 20:04:36 +0000 |
commit | 6e97b782691db94b4ed4bcae1a9a09a1777a25ef (patch) | |
tree | d66aee4fdb3f5db795e8193be9208dcc7e69501e /gcc/function.c | |
parent | afca5855e2d045e513b2450d165c50761d72ed8e (diff) |
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.
git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@126385 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/function.c')
-rw-r--r-- | gcc/function.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/gcc/function.c b/gcc/function.c index 10fe7febe6c..a01bd9367bb 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" |