X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Frecog.c;h=8f041799e62a65e951b1f79d14641c2833310a00;hb=e9d79eef3ca6f45d535cff1b6579e4d33182eb56;hp=eb456c06f45bf5130427e518b16ecf28ae555680;hpb=991512bce5fa04e1745d1afe188c09b6ccae4d3c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/recog.c b/gcc/recog.c index eb456c06f45..8f041799e62 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" -#include "rtl.h" +#include "rtl-error.h" #include "tm_p.h" #include "insn-config.h" #include "insn-attr.h" @@ -35,7 +35,6 @@ along with GCC; see the file COPYING3. If not see #include "expr.h" #include "function.h" #include "flags.h" -#include "toplev.h" #include "basic-block.h" #include "output.h" #include "reload.h" @@ -119,6 +118,25 @@ init_recog (void) } +/* Return true if labels in asm operands BODY are LABEL_REFs. */ + +static bool +asm_labels_ok (rtx body) +{ + rtx asmop; + int i; + + asmop = extract_asm_operands (body); + if (asmop == NULL_RTX) + return true; + + for (i = 0; i < ASM_OPERANDS_LABEL_LENGTH (asmop); i++) + if (GET_CODE (ASM_OPERANDS_LABEL (asmop, i)) != LABEL_REF) + return false; + + return true; +} + /* Check that X is an insn-body for an `asm' with operands and that the operands mentioned in it are legitimate. */ @@ -130,6 +148,9 @@ check_asm_operands (rtx x) const char **constraints; int i; + if (!asm_labels_ok (x)) + return 0; + /* Post-reload, be more strict with things. */ if (reload_completed) { @@ -278,8 +299,8 @@ canonicalize_change_group (rtx insn, rtx x) /* Oops, the caller has made X no longer canonical. Let's redo the changes in the correct order. */ rtx tem = XEXP (x, 0); - validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1); - validate_change (insn, &XEXP (x, 1), tem, 1); + validate_unshare_change (insn, &XEXP (x, 0), XEXP (x, 1), 1); + validate_unshare_change (insn, &XEXP (x, 1), tem, 1); return true; } else @@ -639,6 +660,8 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object, (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode) - offset); + gcc_assert (GET_MODE_PRECISION (wanted_mode) + == GET_MODE_BITSIZE (wanted_mode)); pos %= GET_MODE_BITSIZE (wanted_mode); newmem = adjust_address_nv (XEXP (x, 0), wanted_mode, offset); @@ -902,10 +925,7 @@ next_insn_tests_no_inequality (rtx insn) it has. The main use of this function is as a predicate in match_operand - expressions in the machine description. - - For an explanation of this function's behavior for registers of - class NO_REGS, see the comment for `register_operand'. */ + expressions in the machine description. */ int general_operand (rtx op, enum machine_mode mode) @@ -931,7 +951,9 @@ general_operand (rtx op, enum machine_mode mode) return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode || mode == VOIDmode) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) - && LEGITIMATE_CONSTANT_P (op)); + && targetm.legitimate_constant_p (mode == VOIDmode + ? GET_MODE (op) + : mode, op)); /* Except for certain constants with VOIDmode, already checked for, OP's mode must match MODE if MODE specifies a mode. */ @@ -973,9 +995,8 @@ general_operand (rtx op, enum machine_mode mode) } if (code == REG) - /* A register whose class is NO_REGS is not a general operand. */ return (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (op)) != NO_REGS); + || in_hard_reg_set_p (operand_reg_set, GET_MODE (op), REGNO (op))); if (code == MEM) { @@ -1008,15 +1029,7 @@ address_operand (rtx op, enum machine_mode mode) If MODE is VOIDmode, accept a register in any mode. The main use of this function is as a predicate in match_operand - expressions in the machine description. - - As a special exception, registers whose class is NO_REGS are - not accepted by `register_operand'. The reason for this change - is to allow the representation of special architecture artifacts - (such as a condition code register) without extending the rtl - definitions. Since registers of class NO_REGS cannot be used - as registers in any case where register classes are examined, - it is most consistent to keep this function from accepting them. */ + expressions in the machine description. */ int register_operand (rtx op, enum machine_mode mode) @@ -1055,11 +1068,10 @@ register_operand (rtx op, enum machine_mode mode) op = sub; } - /* We don't consider registers whose class is NO_REGS - to be a register operand. */ return (REG_P (op) && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); + || in_hard_reg_set_p (operand_reg_set, + GET_MODE (op), REGNO (op)))); } /* Return 1 for a register in Pmode; ignore the tested mode. */ @@ -1108,7 +1120,9 @@ immediate_operand (rtx op, enum machine_mode mode) && (GET_MODE (op) == mode || mode == VOIDmode || GET_MODE (op) == VOIDmode) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) - && LEGITIMATE_CONSTANT_P (op)); + && targetm.legitimate_constant_p (mode == VOIDmode + ? GET_MODE (op) + : mode, op)); } /* Returns 1 if OP is an operand that is a CONST_INT. */ @@ -1158,24 +1172,7 @@ int nonmemory_operand (rtx op, enum machine_mode mode) { if (CONSTANT_P (op)) - { - /* Don't accept CONST_INT or anything similar - if the caller wants something floating. */ - if (GET_MODE (op) == VOIDmode && mode != VOIDmode - && GET_MODE_CLASS (mode) != MODE_INT - && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) - return 0; - - if (CONST_INT_P (op) - && mode != VOIDmode - && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op)) - return 0; - - return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode - || mode == VOIDmode) - && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) - && LEGITIMATE_CONSTANT_P (op)); - } + return immediate_operand (op, mode); if (GET_MODE (op) != mode && mode != VOIDmode) return 0; @@ -1193,11 +1190,10 @@ nonmemory_operand (rtx op, enum machine_mode mode) op = SUBREG_REG (op); } - /* We don't consider registers whose class is NO_REGS - to be a register operand. */ return (REG_P (op) && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); + || in_hard_reg_set_p (operand_reg_set, + GET_MODE (op), REGNO (op)))); } /* Return 1 if OP is a valid operand that stands for pushing a @@ -2271,7 +2267,8 @@ preprocess_constraints (void) case 'p': op_alt[j].is_address = 1; op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl] - [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; + [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH)]; break; case 'g': @@ -2292,8 +2289,8 @@ preprocess_constraints (void) op_alt[j].cl = (reg_class_subunion [(int) op_alt[j].cl] - [(int) base_reg_class (VOIDmode, ADDRESS, - SCRATCH)]); + [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH)]); break; } @@ -2742,7 +2739,7 @@ constrain_operands (int strict) case PRE_MODIFY: case POST_MODIFY: if (strchr (recog_data.constraints[opno], '<') == NULL - || strchr (recog_data.constraints[opno], '>') + && strchr (recog_data.constraints[opno], '>') == NULL) return 0; break; @@ -2768,21 +2765,21 @@ constrain_operands (int strict) return 0; } -/* Return 1 iff OPERAND (assumed to be a REG rtx) +/* Return true iff OPERAND (assumed to be a REG rtx) is a hard reg in class CLASS when its regno is offset by OFFSET and changed to mode MODE. If REG occupies multiple hard regs, all of them must be in CLASS. */ -int -reg_fits_class_p (rtx operand, enum reg_class cl, int offset, +bool +reg_fits_class_p (const_rtx operand, reg_class_t cl, int offset, enum machine_mode mode) { int regno = REGNO (operand); if (cl == NO_REGS) - return 0; + return false; - return (regno < FIRST_PSEUDO_REGISTER + return (HARD_REGISTER_NUM_P (regno) && in_hard_reg_set_p (reg_class_contents[(int) cl], mode, regno + offset)); } @@ -2885,15 +2882,8 @@ split_all_insns (void) } else { - rtx last = split_insn (insn); - if (last) + if (split_insn (insn)) { - /* The split sequence may include barrier, but the - BB boundary we are interested in will be set to - previous one. */ - - while (BARRIER_P (last)) - last = PREV_INSN (last); SET_BIT (blocks, bb->index); changed = true; } @@ -3048,6 +3038,7 @@ peep2_find_free_register (int from, int to, const char *class_str, static int search_ofs; enum reg_class cl; HARD_REG_SET live; + df_ref *def_rec; int i; gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1); @@ -3061,12 +3052,14 @@ peep2_find_free_register (int from, int to, const char *class_str, while (from != to) { - HARD_REG_SET this_live; + gcc_assert (peep2_insn_data[from].insn != NULL_RTX); + + /* Don't use registers set or clobbered by the insn. */ + for (def_rec = DF_INSN_DEFS (peep2_insn_data[from].insn); + *def_rec; def_rec++) + SET_HARD_REG_BIT (live, DF_REF_REGNO (*def_rec)); from = peep2_buf_position (from + 1); - gcc_assert (peep2_insn_data[from].insn != NULL_RTX); - REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before); - IOR_HARD_REG_SET (live, this_live); } cl = (class_str[0] == 'r' ? GENERAL_REGS @@ -3158,22 +3151,105 @@ peep2_reinit_state (regset live) /* While scanning basic block BB, we found a match of length MATCH_LEN, starting at INSN. Perform the replacement, removing the old insns and - replacing them with ATTEMPT. Returns the last insn emitted. */ + replacing them with ATTEMPT. Returns the last insn emitted, or NULL + if the replacement is rejected. */ static rtx peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) { int i; - rtx last, note, before_try, x; + rtx last, eh_note, as_note, before_try, x; + rtx old_insn, new_insn; bool was_call = false; + /* If we are splitting an RTX_FRAME_RELATED_P insn, do not allow it to + match more than one insn, or to be split into more than one insn. */ + old_insn = peep2_insn_data[peep2_current].insn; + if (RTX_FRAME_RELATED_P (old_insn)) + { + bool any_note = false; + rtx note; + + if (match_len != 0) + return NULL; + + /* Look for one "active" insn. I.e. ignore any "clobber" insns that + may be in the stream for the purpose of register allocation. */ + if (active_insn_p (attempt)) + new_insn = attempt; + else + new_insn = next_active_insn (attempt); + if (next_active_insn (new_insn)) + return NULL; + + /* We have a 1-1 replacement. Copy over any frame-related info. */ + RTX_FRAME_RELATED_P (new_insn) = 1; + + /* Allow the backend to fill in a note during the split. */ + for (note = REG_NOTES (new_insn); note ; note = XEXP (note, 1)) + switch (REG_NOTE_KIND (note)) + { + case REG_FRAME_RELATED_EXPR: + case REG_CFA_DEF_CFA: + case REG_CFA_ADJUST_CFA: + case REG_CFA_OFFSET: + case REG_CFA_REGISTER: + case REG_CFA_EXPRESSION: + case REG_CFA_RESTORE: + case REG_CFA_SET_VDRAP: + any_note = true; + break; + default: + break; + } + + /* If the backend didn't supply a note, copy one over. */ + if (!any_note) + for (note = REG_NOTES (old_insn); note ; note = XEXP (note, 1)) + switch (REG_NOTE_KIND (note)) + { + case REG_FRAME_RELATED_EXPR: + case REG_CFA_DEF_CFA: + case REG_CFA_ADJUST_CFA: + case REG_CFA_OFFSET: + case REG_CFA_REGISTER: + case REG_CFA_EXPRESSION: + case REG_CFA_RESTORE: + case REG_CFA_SET_VDRAP: + add_reg_note (new_insn, REG_NOTE_KIND (note), XEXP (note, 0)); + any_note = true; + break; + default: + break; + } + + /* If there still isn't a note, make sure the unwind info sees the + same expression as before the split. */ + if (!any_note) + { + rtx old_set, new_set; + + /* The old insn had better have been simple, or annotated. */ + old_set = single_set (old_insn); + gcc_assert (old_set != NULL); + + new_set = single_set (new_insn); + if (!new_set || !rtx_equal_p (new_set, old_set)) + add_reg_note (new_insn, REG_FRAME_RELATED_EXPR, old_set); + } + + /* Copy prologue/epilogue status. This is required in order to keep + proper placement of EPILOGUE_BEG and the DW_CFA_remember_state. */ + maybe_copy_prologue_epilogue_insn (old_insn, new_insn); + } + /* If we are splitting a CALL_INSN, look for the CALL_INSN in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other cfg-related call notes. */ for (i = 0; i <= match_len; ++i) { int j; - rtx old_insn, new_insn, note; + rtx note; j = peep2_buf_position (peep2_current + i); old_insn = peep2_insn_data[j].insn; @@ -3201,6 +3277,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) { case REG_NORETURN: case REG_SETJMP: + case REG_TM: add_reg_note (new_insn, REG_NOTE_KIND (note), XEXP (note, 0)); break; @@ -3219,9 +3296,21 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) break; } - i = peep2_buf_position (peep2_current + match_len); + /* If we matched any instruction that had a REG_ARGS_SIZE, then + move those notes over to the new sequence. */ + as_note = NULL; + for (i = match_len; i >= 0; --i) + { + int j = peep2_buf_position (peep2_current + i); + old_insn = peep2_insn_data[j].insn; - note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX); + as_note = find_reg_note (old_insn, REG_ARGS_SIZE, NULL); + if (as_note) + break; + } + + i = peep2_buf_position (peep2_current + match_len); + eh_note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX); /* Replace the old sequence with the new. */ last = emit_insn_after_setloc (attempt, @@ -3231,7 +3320,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) delete_insn_chain (insn, peep2_insn_data[i].insn, false); /* Re-insert the EH_REGION notes. */ - if (note || (was_call && nonlocal_goto_handler_labels)) + if (eh_note || (was_call && nonlocal_goto_handler_labels)) { edge eh_edge; edge_iterator ei; @@ -3240,8 +3329,8 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) break; - if (note) - copy_reg_eh_region_note_backward (note, last, before_try); + if (eh_note) + copy_reg_eh_region_note_backward (eh_note, last, before_try); if (eh_edge) for (x = last; x != before_try; x = PREV_INSN (x)) @@ -3274,6 +3363,10 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt) peep2_do_cleanup_cfg |= purge_dead_edges (bb); } + /* Re-insert the ARGS_SIZE notes. */ + if (as_note) + fixup_args_size_notes (before_try, last, INTVAL (XEXP (as_note, 0))); + /* If we generated a jump instruction, it won't have JUMP_LABEL set. Recompute after we're done. */ for (x = last; x != before_try; x = PREV_INSN (x)) @@ -3346,18 +3439,14 @@ peep2_fill_buffer (basic_block bb, rtx insn, regset live) if (peep2_current_count == MAX_INSNS_PER_PEEP2) return false; - /* If an insn has RTX_FRAME_RELATED_P set, peephole substitution would lose - the REG_FRAME_RELATED_EXPR that is attached. */ + /* If an insn has RTX_FRAME_RELATED_P set, do not allow it to be matched with + any other pattern, lest it change the semantics of the frame info. */ if (RTX_FRAME_RELATED_P (insn)) { /* Let the buffer drain first. */ if (peep2_current_count > 0) return false; - /* Step over the insn then return true without adding the insn - to the buffer; this will cause us to process the next - insn. */ - df_simulate_one_insn_forwards (bb, insn, live); - return true; + /* Now the insn will be the only thing in the buffer. */ } pos = peep2_buf_position (peep2_current + peep2_current_count); @@ -3436,16 +3525,17 @@ peephole2_optimize (void) attempt = peephole2_insns (PATTERN (head), head, &match_len); if (attempt != NULL) { - rtx last; - last = peep2_attempt (bb, head, match_len, attempt); - peep2_update_life (bb, match_len, last, PREV_INSN (attempt)); - } - else - { - /* If no match, advance the buffer by one insn. */ - peep2_current = peep2_buf_position (peep2_current + 1); - peep2_current_count--; + rtx last = peep2_attempt (bb, head, match_len, attempt); + if (last) + { + peep2_update_life (bb, match_len, last, PREV_INSN (attempt)); + continue; + } } + + /* No match: advance the buffer by one insn. */ + peep2_current = peep2_buf_position (peep2_current + 1); + peep2_current_count--; } } @@ -3637,7 +3727,7 @@ struct rtl_opt_pass pass_peephole2 = 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_df_finish | TODO_verify_rtl_sharing | - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; @@ -3663,7 +3753,7 @@ struct rtl_opt_pass pass_split_all_insns = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; @@ -3693,7 +3783,7 @@ struct rtl_opt_pass pass_split_after_reload = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; @@ -3737,7 +3827,7 @@ struct rtl_opt_pass pass_split_before_regstack = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; @@ -3775,8 +3865,7 @@ struct rtl_opt_pass pass_split_before_sched2 = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_verify_flow | - TODO_dump_func /* todo_flags_finish */ + TODO_verify_flow /* todo_flags_finish */ } }; @@ -3807,6 +3896,6 @@ struct rtl_opt_pass pass_split_for_shorten_branches = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */ + TODO_verify_rtl_sharing /* todo_flags_finish */ } };