diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-26 18:39:06 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-26 18:39:06 +0000 |
commit | 21543d4cd558cada630271a0cf3075ad7ce94cbf (patch) | |
tree | 08bdb3f3e0a9d0f71e72bb56d9ddb7b916e7dfeb /gcc/config/epiphany | |
parent | ed0bc1ffb674fe93d0df68654b5bb76869f0bc8c (diff) | |
download | gcc-21543d4cd558cada630271a0cf3075ad7ce94cbf.tar.gz |
2013-06-26 Basile Starynkevitch <basile@starynkevitch.net>
{{merged with trunk [4.9] svn rev. 196654-200426}}
MELT branch merged with trunk rev. 200426 using svnmerge.py
[gcc/]
2013-06-26 Basile Starynkevitch <basile@starynkevitch.net>
{{merge with trunk [4.9] svn rev. 196654-200426}}
* melt-runtime.c (melt_val2passflag): TODO_ggc_collect &
TODO_do_not_ggc_collect are conditionalized.
* melt/generated/warmelt-first+03.cc: Manually remove calls to
MELT_TRACE_EXIT_LOCATION macro.
* melt/generated/warmelt-base+03.cc: Ditto.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@200430 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/epiphany')
-rw-r--r-- | gcc/config/epiphany/constraints.md | 5 | ||||
-rw-r--r-- | gcc/config/epiphany/epiphany.c | 209 | ||||
-rw-r--r-- | gcc/config/epiphany/epiphany.h | 8 | ||||
-rw-r--r-- | gcc/config/epiphany/epiphany.md | 173 | ||||
-rw-r--r-- | gcc/config/epiphany/predicates.md | 2 |
5 files changed, 305 insertions, 92 deletions
diff --git a/gcc/config/epiphany/constraints.md b/gcc/config/epiphany/constraints.md index bd3d935a275..d4d6049fe67 100644 --- a/gcc/config/epiphany/constraints.md +++ b/gcc/config/epiphany/constraints.md @@ -39,6 +39,11 @@ (and (match_code "const_int") (match_test "SIMM11 (ival)"))) +(define_constraint "CnL" + "A negated signed 11-bit constant." + (and (match_code "const_int") + (match_test "SIMM11 (-ival)"))) + (define_constraint "Cm1" "A signed 11-bit constant added to -1" (and (match_code "const_int") diff --git a/gcc/config/epiphany/epiphany.c b/gcc/config/epiphany/epiphany.c index 782dc7b3e75..3b6f63ab975 100644 --- a/gcc/config/epiphany/epiphany.c +++ b/gcc/config/epiphany/epiphany.c @@ -181,6 +181,8 @@ epiphany_init (void) = { &pass_split_all_insns.pass, "mode_sw", 1, PASS_POS_INSERT_AFTER }; + static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; +#define N_ENTITIES ARRAY_SIZE (num_modes) epiphany_init_reg_tables (); @@ -196,6 +198,8 @@ epiphany_init (void) register_pass (&mode_sw3_info); register_pass (&insert_use_info); register_pass (&mode_sw2_info); + /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */ + gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM); #if 1 /* As long as peep2_rescan is not implemented, (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,) @@ -335,7 +339,8 @@ epiphany_select_cc_mode (enum rtx_code op, { if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) { - if (TARGET_SOFT_CMPSF) + if (TARGET_SOFT_CMPSF + || op == ORDERED || op == UNORDERED) { if (op == EQ || op == NE) return CC_FP_EQmode; @@ -537,24 +542,47 @@ gen_compare_reg (enum machine_mode cmode, enum rtx_code code, if (mode == CC_FP_GTEmode && (code == LE || code == LT || code == UNGT || code == UNGE)) { - rtx tmp = x; x = y; y = tmp; - code = swap_condition (code); + if (flag_finite_math_only + && ((REG_P (x) && REGNO (x) == GPR_0) + || (REG_P (y) && REGNO (y) == GPR_1))) + switch (code) + { + case LE: code = UNLE; break; + case LT: code = UNLT; break; + case UNGT: code = GT; break; + case UNGE: code = GE; break; + default: gcc_unreachable (); + } + else + { + rtx tmp = x; x = y; y = tmp; + code = swap_condition (code); + } } cc_reg = gen_rtx_REG (mode, CC_REGNUM); } if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode) /* mov<mode>cc might want to re-emit a comparison during ifcvt. */ - && (!REG_P (x) || REGNO (x) != 0 || !REG_P (y) || REGNO (y) != 1)) + && (!REG_P (x) || REGNO (x) != GPR_0 + || !REG_P (y) || REGNO (y) != GPR_1)) { rtx reg; +#if 0 + /* ??? We should really do the r0/r1 clobber only during rtl expansion, + but just like the flag clobber of movsicc, we have to allow + this for ifcvt to work, on the assumption that we'll only want + to do this if these registers have been used before by the + pre-ifcvt code. */ gcc_assert (currently_expanding_to_rtl); - reg = gen_rtx_REG (in_mode, 0); - gcc_assert (!reg_overlap_mentioned_p (reg, y)); +#endif + reg = gen_rtx_REG (in_mode, GPR_0); + if (reg_overlap_mentioned_p (reg, y)) + return 0; emit_move_insn (reg, x); x = reg; - reg = gen_rtx_REG (in_mode, 1); + reg = gen_rtx_REG (in_mode, GPR_1); emit_move_insn (reg, y); y = reg; } @@ -964,7 +992,6 @@ epiphany_compute_frame_size (int size /* # of var. bytes allocated. */) int first_slot, last_slot, first_slot_offset, last_slot_offset; int first_slot_size; int small_slots = 0; - long lr_slot_offset; var_size = size; args_size = crtl->outgoing_args_size; @@ -1021,7 +1048,7 @@ epiphany_compute_frame_size (int size /* # of var. bytes allocated. */) first_slot = regno; else if (last_slot < 0 && (first_slot ^ regno) != 1 - && (!interrupt_p || regno > GPR_0 + 1)) + && (!interrupt_p || regno > GPR_1)) last_slot = regno; } } @@ -1116,28 +1143,6 @@ epiphany_compute_frame_size (int size /* # of var. bytes allocated. */) } total_size = first_slot_offset + last_slot_offset; - lr_slot_offset - = (frame_pointer_needed ? first_slot_offset : (long) total_size); - if (first_slot != GPR_LR) - { - int stack_offset = epiphany_stack_offset - UNITS_PER_WORD; - - for (regno = 0; ; regno++) - { - if (stack_offset + UNITS_PER_WORD - first_slot_size == 0 - && first_slot >= 0) - { - stack_offset -= first_slot_size; - regno--; - } - else if (regno == GPR_LR) - break; - else if TEST_HARD_REG_BIT (gmask, regno) - stack_offset -= UNITS_PER_WORD; - } - lr_slot_offset += stack_offset; - } - /* Save computed information. */ current_frame_info.total_size = total_size; current_frame_info.pretend_size = pretend_size; @@ -1150,7 +1155,6 @@ epiphany_compute_frame_size (int size /* # of var. bytes allocated. */) current_frame_info.first_slot_offset = first_slot_offset; current_frame_info.first_slot_size = first_slot_size; current_frame_info.last_slot_offset = last_slot_offset; - MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset; current_frame_info.initialized = reload_completed; @@ -1622,6 +1626,28 @@ epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p) mem = skipped_mem; else mem = gen_mem (mode, addr); + + /* If we are loading / storing LR, note the offset that + gen_reload_insi_ra requires. Since GPR_LR is even, + we only need to test n, even if mode is DImode. */ + gcc_assert ((GPR_LR & 1) == 0); + if (n == GPR_LR) + { + long lr_slot_offset = 0; + rtx m_addr = XEXP (mem, 0); + + if (GET_CODE (m_addr) == PLUS) + lr_slot_offset = INTVAL (XEXP (m_addr, 1)); + if (frame_pointer_needed) + lr_slot_offset += (current_frame_info.first_slot_offset + - current_frame_info.total_size); + if (MACHINE_FUNCTION (cfun)->lr_slot_known) + gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset + == lr_slot_offset); + MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset; + MACHINE_FUNCTION (cfun)->lr_slot_known = 1; + } + if (!epilogue_p) frame_move_insn (mem, reg); else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size) @@ -1667,7 +1693,7 @@ epiphany_expand_prologue (void) gen_rtx_REG (DImode, GPR_0)); frame_move_insn (gen_rtx_REG (SImode, GPR_0), gen_rtx_REG (word_mode, STATUS_REGNUM)); - frame_move_insn (gen_rtx_REG (SImode, GPR_0+1), + frame_move_insn (gen_rtx_REG (SImode, GPR_1), gen_rtx_REG (word_mode, IRET_REGNUM)); mem = gen_frame_mem (BLKmode, stack_pointer_rtx); off = GEN_INT (-current_frame_info.first_slot_offset); @@ -1712,18 +1738,28 @@ epiphany_expand_prologue (void) register save. */ if (current_frame_info.last_slot >= 0) { + rtx ip, mem2, insn, note; + gcc_assert (current_frame_info.last_slot != GPR_FP || (!current_frame_info.need_fp && current_frame_info.first_slot < 0)); off = GEN_INT (-current_frame_info.last_slot_offset); mem = gen_frame_mem (BLKmode, gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); - reg = gen_rtx_REG (Pmode, GPR_IP); - frame_move_insn (reg, off); - frame_insn (gen_stack_adjust_str - (gen_frame_mem (word_mode, stack_pointer_rtx), - gen_rtx_REG (word_mode, current_frame_info.last_slot), - reg, mem)); + ip = gen_rtx_REG (Pmode, GPR_IP); + frame_move_insn (ip, off); + reg = gen_rtx_REG (word_mode, current_frame_info.last_slot), + mem2 = gen_frame_mem (word_mode, stack_pointer_rtx), + insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem)); + /* Instruction scheduling can separate the instruction setting IP from + INSN so that dwarf2out_frame_debug_expr becomes confused what the + temporary register is. Example: _gcov.o */ + note = gen_rtx_SET (VOIDmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); + note = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, gen_rtx_SET (VOIDmode, mem2, reg), + note)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); } /* If there is only one or no register to save, yet we have a large frame, use an add. */ @@ -1741,44 +1777,6 @@ epiphany_expand_prologue (void) } frame_insn (gen_stack_adjust_add (off, mem)); } - - /* Mode switching uses get_hard_reg_initial_val after - emit_initial_value_sets, so we have to fix this up now. */ - save_config = has_hard_reg_initial_val (SImode, CONFIG_REGNUM); - if (save_config) - { - if (REG_P (save_config)) - { - if (REGNO (save_config) >= FIRST_PSEUDO_REGISTER) - gcc_assert (!df_regs_ever_live_p (REGNO (save_config))); - else - frame_move_insn (save_config, - get_hard_reg_initial_reg (save_config)); - } - else - { - rtx save_dst = save_config; - - reg = gen_rtx_REG (SImode, GPR_IP); - gcc_assert (MEM_P (save_dst)); - if (!memory_operand (save_dst, SImode)) - { - rtx addr = XEXP (save_dst, 0); - rtx reg2 = gen_rtx_REG (SImode, GPR_16); - - gcc_assert (GET_CODE (addr) == PLUS); - gcc_assert (XEXP (addr, 0) == hard_frame_pointer_rtx - || XEXP (addr, 0) == stack_pointer_rtx); - emit_move_insn (reg2, XEXP (addr, 1)); - save_dst - = replace_equiv_address (save_dst, - gen_rtx_PLUS (Pmode, XEXP (addr, 0), - reg2)); - } - emit_move_insn (reg, get_hard_reg_initial_reg (save_config)); - emit_move_insn (save_dst, reg); - } - } } void @@ -1843,7 +1841,7 @@ epiphany_expand_epilogue (int sibcall_p) emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM), gen_rtx_REG (SImode, GPR_0)); emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM), - gen_rtx_REG (SImode, GPR_0+1)); + gen_rtx_REG (SImode, GPR_1)); addr = plus_constant (Pmode, stack_pointer_rtx, - (HOST_WIDE_INT) 2 * UNITS_PER_WORD); emit_move_insn (gen_rtx_REG (DImode, GPR_0), @@ -2239,6 +2237,7 @@ epiphany_optimize_mode_switching (int entity) { case EPIPHANY_MSW_ENTITY_AND: case EPIPHANY_MSW_ENTITY_OR: + case EPIPHANY_MSW_ENTITY_CONFIG: return true; case EPIPHANY_MSW_ENTITY_NEAREST: case EPIPHANY_MSW_ENTITY_TRUNC: @@ -2257,7 +2256,8 @@ epiphany_optimize_mode_switching (int entity) int epiphany_mode_priority_to_mode (int entity, unsigned priority) { - if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR) + if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR + || entity== EPIPHANY_MSW_ENTITY_CONFIG) return priority; if (priority > 3) switch (priority) @@ -2309,7 +2309,8 @@ epiphany_mode_needed (int entity, rtx insn) if (recog_memoized (insn) < 0) { if (entity == EPIPHANY_MSW_ENTITY_AND - || entity == EPIPHANY_MSW_ENTITY_OR) + || entity == EPIPHANY_MSW_ENTITY_OR + || entity == EPIPHANY_MSW_ENTITY_CONFIG) return 2; return FP_MODE_NONE; } @@ -2318,9 +2319,24 @@ epiphany_mode_needed (int entity, rtx insn) switch (entity) { case EPIPHANY_MSW_ENTITY_AND: - return mode != FP_MODE_INT ? 1 : 2; + return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2; case EPIPHANY_MSW_ENTITY_OR: return mode == FP_MODE_INT ? 1 : 2; + case EPIPHANY_MSW_ENTITY_CONFIG: + /* We must know/save config before we set it to something else. + Where we need the original value, we are fine with having it + just unchanged from the function start. + Because of the nature of the mode switching optimization, + a restore will be dominated by a clobber. */ + if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER) + return 1; + /* A cpecial case are abnormal edges, which are deemed to clobber + the mode as well. We need to pin this effect on a actually + dominating insn, and one where the frame can be accessed, too, in + case the pseudo used to save CONFIG doesn't get a hard register. */ + if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX)) + return 1; + return 2; case EPIPHANY_MSW_ENTITY_ROUND_KNOWN: if (recog_memoized (insn) == CODE_FOR_set_fp_mode) mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn); @@ -2364,6 +2380,10 @@ epiphany_mode_entry_exit (int entity, bool exit) if (exit) return normal_mode == FP_MODE_INT ? 1 : 2; return 0; + case EPIPHANY_MSW_ENTITY_CONFIG: + if (exit) + return 2; + return normal_mode == FP_MODE_CALLER ? 0 : 1; case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN: if (normal_mode == FP_MODE_ROUND_NEAREST || normal_mode == FP_MODE_ROUND_TRUNC) @@ -2386,10 +2406,22 @@ epiphany_mode_after (int entity, int last_mode, rtx insn) calls. */ if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR) { - if (GET_CODE (insn) == CALL_INSN) + if (CALL_P (insn)) return 0; return last_mode; } + /* If there is an abnormal edge, we don't want the config register to + be 'saved' again at the destination. + The frame pointer adjustment is inside a PARALLEL because of the + flags clobber. */ + if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn) + && GET_CODE (PATTERN (insn)) == PARALLEL + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET + && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx) + { + gcc_assert (cfun->has_nonlocal_label); + return 1; + } if (recog_memoized (insn) < 0) return last_mode; if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN @@ -2443,12 +2475,25 @@ emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED) emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000)); return; } + else if (entity == EPIPHANY_MSW_ENTITY_CONFIG) + { + /* Mode switching optimization is done after emit_initial_value_sets, + so we have to take care of CONFIG_REGNUM here. */ + gcc_assert (mode >= 0 && mode <= 2); + rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM); + if (mode == 1) + emit_insn (gen_save_config (save)); + return; + } fp_mode = (enum attr_fp_mode) mode; src = NULL_RTX; switch (fp_mode) { case FP_MODE_CALLER: + /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later + so that the config save gets inserted before the first use. */ + gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG); src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM); mask = MACHINE_FUNCTION (cfun)->and_mask; break; diff --git a/gcc/config/epiphany/epiphany.h b/gcc/config/epiphany/epiphany.h index 42b16300284..bd84b5c793f 100644 --- a/gcc/config/epiphany/epiphany.h +++ b/gcc/config/epiphany/epiphany.h @@ -450,6 +450,7 @@ typedef struct GTY (()) machine_function unsigned pretend_args_odd : 1; unsigned lr_clobbered : 1; unsigned control_use_inserted : 1; + unsigned lr_slot_known : 1; unsigned sw_entities_processed : 6; long lr_slot_offset; rtx and_mask; @@ -895,7 +896,8 @@ enum epiphany_function_type finally an entity that runs in a second mode switching pass to resolve FP_MODE_ROUND_UNKNOWN. */ #define NUM_MODES_FOR_MODE_SWITCHING \ - { 2, 2, FP_MODE_NONE, FP_MODE_NONE, FP_MODE_NONE, FP_MODE_NONE, FP_MODE_NONE } + { 2, 2, 2, \ + FP_MODE_NONE, FP_MODE_NONE, FP_MODE_NONE, FP_MODE_NONE, FP_MODE_NONE } #define MODE_NEEDED(ENTITY, INSN) epiphany_mode_needed((ENTITY), (INSN)) @@ -917,11 +919,13 @@ enum { EPIPHANY_MSW_ENTITY_AND, EPIPHANY_MSW_ENTITY_OR, + EPIPHANY_MSW_ENTITY_CONFIG, /* 1 means config is known or saved. */ EPIPHANY_MSW_ENTITY_NEAREST, EPIPHANY_MSW_ENTITY_TRUNC, EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN, EPIPHANY_MSW_ENTITY_ROUND_KNOWN, - EPIPHANY_MSW_ENTITY_FPU_OMNIBUS + EPIPHANY_MSW_ENTITY_FPU_OMNIBUS, + EPIPHANY_MSW_ENTITY_NUM }; extern int epiphany_normal_fp_rounding; diff --git a/gcc/config/epiphany/epiphany.md b/gcc/config/epiphany/epiphany.md index 6375d3f8c97..1e2d2ab02ed 100644 --- a/gcc/config/epiphany/epiphany.md +++ b/gcc/config/epiphany/epiphany.md @@ -22,6 +22,7 @@ (define_constants [(GPR_0 0) + (GPR_1 1) (GPR_FP 11) (GPR_IP 12) (GPR_SP 13) @@ -264,6 +265,15 @@ rtx addr = (frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx); + if (!MACHINE_FUNCTION (cfun)->lr_slot_known) + { + start_sequence (); + epiphany_expand_prologue (); + if (!MACHINE_FUNCTION (cfun)->lr_slot_known) + epiphany_expand_epilogue (0); + end_sequence (); + gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_known); + } addr = plus_constant (Pmode, addr, MACHINE_FUNCTION (cfun)->lr_slot_offset); operands[1] = gen_frame_mem (SImode, addr); }) @@ -420,13 +430,19 @@ DONE; }") +; The default case of epiphany_print_operand emits IMMEDIATE_PREFIX +; where appropriate; however, 'n' is processed by output_asm_insn +; which doesn't, so we have to explicitly emit the '# in the +; r/r/CnL output template alternative. (define_insn "addsi3_i" - [(set (match_operand:SI 0 "add_reg_operand" "=r") - (plus:SI (match_operand:SI 1 "add_reg_operand" "%r") - (match_operand:SI 2 "add_operand" "rL"))) + [(set (match_operand:SI 0 "add_reg_operand" "=r,r") + (plus:SI (match_operand:SI 1 "add_reg_operand" "%r,r") + (match_operand:SI 2 "add_operand" "rL,CnL"))) (clobber (reg:CC CC_REGNUM))] "" - "add %0,%1,%2" + "@ + add %0,%1,%2 + sub %0,%1,#%n2" [(set_attr "type" "misc")]) ; We use a clobber of UNKNOWN_REGNUM here so that the peephole optimizers @@ -1432,6 +1448,16 @@ [(set_attr "type" "flow") (set_attr "length" "20,4")]) +(define_insn_and_split "save_config" + [(set (match_operand:SI 0 "gpr_operand" "=r") (reg:SI CONFIG_REGNUM)) + (use (reg:SI FP_NEAREST_REGNUM)) + (use (reg:SI FP_TRUNCATE_REGNUM)) + (use (reg:SI FP_ANYFP_REGNUM))] + "" + "#" + "reload_completed" + [(set (match_dup 0) (reg:SI CONFIG_REGNUM))]) + (define_insn_and_split "set_fp_mode" [(set (reg:SI FP_NEAREST_REGNUM) (match_operand:SI 0 "set_fp_mode_operand" "rCfm")) @@ -1705,6 +1731,132 @@ "sub %0,%1,%2" [(set_attr "type" "compare")]) +(define_code_iterator logical_op + [and ior xor]) + +(define_code_attr op_mnc + [(plus "add") (minus "sub") (and "and") (ior "orr") (xor "eor")]) + +(define_insn "*<op_mnc>_f" + [(set (reg:CC CC_REGNUM) + (compare:CC (logical_op:SI (match_operand:SI 1 "gpr_operand" "%r") + (match_operand:SI 2 "gpr_operand" "r")) + (const_int 0))) + (set (match_operand:SI 0 "gpr_operand" "=r") + (logical_op:SI (match_dup 1) (match_dup 2)))] + "" + "<op_mnc> %0,%1,%2" + [(set_attr "type" "compare")]) + +(define_insn_and_split "*mov_f" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:SI 1 "gpr_operand" "r") (const_int 0))) + (set (match_operand:SI 0 "gpr_operand" "=r") (match_dup 1))] + "" + "#" + "reload_completed" + [(parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (and:SI (match_dup 1) (match_dup 1)) (const_int 0))) + (set (match_operand:SI 0 "gpr_operand" "=r") + (and:SI (match_dup 1) (match_dup 1)))])] + "" + [(set_attr "type" "compare")]) + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "gpr_operand" "=r") + (logical_op:SI (match_operand:SI 1 "gpr_operand" "r") + (match_operand:SI 2 "gpr_operand" "%r"))) + (clobber (reg:CC CC_REGNUM))]) + (parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (and:SI (match_dup 0) (match_dup 0)) (const_int 0))) + (set (match_operand:SI 3 "gpr_operand" "=r") + (and:SI (match_dup 0) (match_dup 0)))])] + "peep2_reg_dead_p (2, operands[0])" + [(parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (logical_op:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 3) (logical_op:SI (match_dup 1) (match_dup 2)))])]) + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "gpr_operand" "=r") + (logical_op:SI (match_operand:SI 1 "gpr_operand" "r") + (match_operand:SI 2 "gpr_operand" "%r"))) + (clobber (reg:CC CC_REGNUM))]) + (parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (and:SI (match_dup 0) (match_dup 0)) (const_int 0))) + (set (match_operand:SI 3 "gpr_operand" "=r") + (and:SI (match_dup 0) (match_dup 0)))])] + "peep2_reg_dead_p (2, operands[3])" + [(parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (logical_op:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) (logical_op:SI (match_dup 1) (match_dup 2)))])]) + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "gpr_operand" "=r") + (logical_op:SI (match_operand:SI 1 "gpr_operand" "r") + (match_operand:SI 2 "gpr_operand" "%r"))) + (clobber (reg:CC CC_REGNUM))]) + (parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (match_dup 0) (const_int 0))) + (clobber (match_operand:SI 3 "gpr_operand" "=r"))])] + "" + [(parallel + [(set (reg:CC CC_REGNUM) + (compare:CC (logical_op:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) (logical_op:SI (match_dup 1) (match_dup 2)))])]) + +(define_expand "cstoresi4" + [(parallel + [(set (reg:CC CC_REGNUM) + (match_operand:SI 1 "comparison_operator")) + (match_operand:SI 2 "" "")]) + (set (match_dup 0) (match_operand:SI 3 "arith_operand" "")) + (set (match_operand:SI 0 "gpr_operand" "=r") + (if_then_else:SI (match_dup 4) (match_dup 5) (match_dup 0)))] + "" +{ + enum rtx_code o2_code = GET_CODE (operands[2]); + enum rtx_code cmp_code = GET_CODE (operands[1]); + + if ((o2_code == AND || o2_code == IOR || o2_code == XOR) + && operands[3] == const0_rtx) + { + operands[2] = copy_rtx(operands[2]); + XEXP (operands[2], 0) = force_reg (SImode, XEXP (operands[2], 0)); + XEXP (operands[2], 1) = force_reg (SImode, XEXP (operands[2], 1)); + } + else + operands[2] = force_reg (SImode, operands[2]); + operands[1] = gen_rtx_COMPARE (CCmode, operands[2], operands[3]); + if (cmp_code != NE) + { + operands[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode)); + operands[3] = const0_rtx; + } + else + { + if (operands[3] != const0_rtx) + operands[2] = gen_rtx_MINUS (SImode, operands[2], operands[3]); + operands[2] = gen_rtx_SET (VOIDmode, operands[0], operands[2]); + operands[3] = operands[0]; + } + operands[4] = gen_rtx_fmt_ee (cmp_code, SImode, + gen_rtx_REG (CCmode, CC_REGNUM), const0_rtx); + operands[5] = force_reg (SImode, GEN_INT (STORE_FLAG_VALUE)); +}) + + ; floating point comparisons (define_insn "*cmpsf_cc_insn" @@ -1747,7 +1899,7 @@ (clobber (reg:SI GPR_IP)) (clobber (reg:SI GPR_16)) (clobber (reg:SI GPR_LR))] - "TARGET_SOFT_CMPSF" + "" "%f0" [(set_attr "type" "sfunc")]) @@ -1811,6 +1963,8 @@ operations - if we get some. */ operands[1] = gen_compare_reg (<MODE>mode, code, cmp_in_mode, cmp_op0, cmp_op1); + if (!operands[1]) + FAIL; } }) @@ -2285,6 +2439,11 @@ [(plus "add") (minus "sub") (mult "mul") (div "div") (and "and") (ior "ior") (xor "xor")]) +; The addsi3 / subsi3 do checks that we don't want when splitting V2SImode +; operations into two SImode operations. +(define_code_attr si_pattern_suffix + [(plus "_i") (minus "_i") (and "") (ior "") (xor "")]) + ; You might think that this would work better as a define_expand, but ; again lower_subreg pessimizes the code if it sees indiviudual operations. ; We need to keep inputs and outputs as register pairs if we want to @@ -2311,8 +2470,8 @@ o1h = copy_to_mode_reg (SImode, o1h); if (reg_overlap_mentioned_p (o0l, o2h)) o2h = copy_to_mode_reg (SImode, o2h); - emit_insn (gen_<insn_opname>si3 (o0l, o1l, o2l)); - emit_insn (gen_<insn_opname>si3 (o0h, o1h, o2h)); + emit_insn (gen_<insn_opname>si3<si_pattern_suffix> (o0l, o1l, o2l)); + emit_insn (gen_<insn_opname>si3<si_pattern_suffix> (o0h, o1h, o2h)); DONE; } [(set_attr "length" "8")]) diff --git a/gcc/config/epiphany/predicates.md b/gcc/config/epiphany/predicates.md index 1ae5824f337..af60d7c73f7 100644 --- a/gcc/config/epiphany/predicates.md +++ b/gcc/config/epiphany/predicates.md @@ -98,7 +98,7 @@ { if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG) return add_reg_operand (op, mode); - return satisfies_constraint_L (op); + return satisfies_constraint_L (op) || satisfies_constraint_CnL (op); }) ;; Ordinary 3rd operand for arithmetic operations |