summaryrefslogtreecommitdiff
path: root/gcc/config/epiphany
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-26 18:39:06 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-26 18:39:06 +0000
commit21543d4cd558cada630271a0cf3075ad7ce94cbf (patch)
tree08bdb3f3e0a9d0f71e72bb56d9ddb7b916e7dfeb /gcc/config/epiphany
parented0bc1ffb674fe93d0df68654b5bb76869f0bc8c (diff)
downloadgcc-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.md5
-rw-r--r--gcc/config/epiphany/epiphany.c209
-rw-r--r--gcc/config/epiphany/epiphany.h8
-rw-r--r--gcc/config/epiphany/epiphany.md173
-rw-r--r--gcc/config/epiphany/predicates.md2
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