Always enable LRA on RX targets.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113948
The previous fix did not adequately address the LRA infinite loop issue.
It was discovered that the infinite loop was caused by the definition of
the register class.
The stack frame manipulation was not compatible with LRA register spills,
so that part has also been corrected.
v3 changes.
- A complete solution to the LRA infinite loop.
- I reverted the memory access cost adjustment because it no longer made sense.
- revert adc and sbb.
ChangeLog:
* gcc/config/rx/predicates.md (rx_double_src_operand): New.
(rx_double_dest_operand): New.
* gcc/config/rx/rx-protos.h (rx_split_double_move): New helper proto.
(rx_relax_double_operands): Likewise.
* gcc/config/rx/rx.cc (rx_legitimize_address): Add expand complex case
(rx_gen_move_template): Fix operation size in unsigned extend.
(rx_gen_move_template): Remove DImode and DFmode.
(rx_get_stack_layout): Fix for frame size calculation.
(rx_initial_elimination_offset): The calculation method has been
changed to one that supports LRA.
(rx_enable_lra): Remove.
(rx_hard_regno_nregs): Rewrite.
(rx_hard_regno_mode_ok): Add ATTRIBUTE_UNUSED.
(rx_modes_tieable_p): Add int case.
(rx_get_subword): New. Double word move helper.
(rx_split_double_move): Likewise.
(rx_relax_double_operands): Likewise.
(TARGET_LRA_P): Remove.
* gcc/config/rx/rx.h (reg_class): Add CC for all regsisters.
(CLASS_MAX_NREGS): Remove.
* gcc/config/rx/rx.md (mov<register_modes:mode>):
Replace copy_to_mode_reg to force_reg.
(movdi): Limit the arguments to make register allocation easier.
(movdf): Likewise.
(movdi_internal): New.
(movdf_internal): New.
(addsi3_pid): New. Handling UNSPEC_PID_ADDR.
(adddi3): New. simplify implementation.
(subdi3): Likewise.
(addsi3_lra): New. alternative addptrsi3.
(ashlsi3_lra): likewise.
* gcc/config/rx/rx.opt (mlra): Remove.
Signed-off-by: Yoshinori Sato <[email protected]>
---
gcc/config/rx/predicates.md | 14 ++
gcc/config/rx/rx-protos.h | 2 +
gcc/config/rx/rx.cc | 190 ++++++++++++++++++--------
gcc/config/rx/rx.h | 5 +-
gcc/config/rx/rx.md | 263 ++++++++++++++++--------------------
gcc/config/rx/rx.opt | 6 -
6 files changed, 266 insertions(+), 214 deletions(-)
diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md
index aa926be31ac..37fd63b538a 100644
--- a/gcc/config/rx/predicates.md
+++ b/gcc/config/rx/predicates.md
@@ -307,3 +307,17 @@
(define_predicate "rshift_operator"
(match_code "ashiftrt,lshiftrt")
)
+
+;; DI and DF are expanded into multiple mov instructions,
+;; so they require stronger constraints than regular move.
+(define_predicate "rx_double_src_operand"
+ (ior (and (match_code "reg,subreg,const_int,const_double")
+ (match_operand 0 "general_operand"))
+ (and (match_code "mem")
+ (match_operand 0 "rx_restricted_mem_operand"))))
+
+(define_predicate "rx_double_dest_operand"
+ (ior (and (match_code "reg,subreg")
+ (match_operand 0 "general_operand"))
+ (and (match_code "mem")
+ (match_operand 0 "rx_restricted_mem_operand"))))
diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h
index 829882b0bc8..5a36ef26948 100644
--- a/gcc/config/rx/rx-protos.h
+++ b/gcc/config/rx/rx-protos.h
@@ -70,6 +70,8 @@ extern void rx_copy_reg_dead_or_unused_notes (rtx reg, const
rtx_insn* src,
extern bool rx_fuse_in_memory_bitop (rtx* operands, rtx_insn* curr_insn,
rtx (*gen_insn)(rtx, rtx));
+extern void rx_split_double_move (rtx* operands, machine_mode mode);
+extern void rx_relax_double_operands (rtx* operands, machine_mode mode);
/* Result value of rx_find_set_of_reg. */
struct set_of_reg
diff --git a/gcc/config/rx/rx.cc b/gcc/config/rx/rx.cc
index 902e756a34e..4675cf6b286 100644
--- a/gcc/config/rx/rx.cc
+++ b/gcc/config/rx/rx.cc
@@ -148,17 +148,41 @@ rx_legitimize_address (rtx x,
rtx oldx ATTRIBUTE_UNUSED,
machine_mode mode ATTRIBUTE_UNUSED)
{
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+
if (rx_pid_data_operand (x) == PID_UNENCODED)
{
rtx rv = gen_pid_addr (gen_rtx_REG (SImode, rx_pid_base_regnum ()), x);
return rv;
}
- if (GET_CODE (x) == PLUS
- && GET_CODE (XEXP (x, 0)) == PLUS
- && REG_P (XEXP (XEXP (x, 0), 0))
- && REG_P (XEXP (x, 1)))
- return force_reg (SImode, x);
+ if (GET_CODE (x) == PLUS)
+ {
+ if (GET_CODE (op0) == PLUS && REG_P (XEXP (op0, 0)) &&
+ CONST_INT_P (op1))
+ {
+ rtx base = XEXP (op0, 0);
+ rtx index = XEXP (op0, 1);
+
+ rtx new_base = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, op1));
+ return gen_rtx_PLUS (Pmode, new_base, index);
+ }
+
+ if (GET_CODE (op0) == MULT || GET_CODE (op0) == ASHIFT)
+ op0 = force_reg (Pmode, op0);
+
+ if (GET_CODE (op1) == MULT || GET_CODE (op1) == ASHIFT)
+ op1 = force_reg (Pmode, op1);
+
+ if (GET_CODE (op0) == PLUS)
+ op0 = rx_legitimize_address (op0, op0, mode);
+ if (GET_CODE (op1) == PLUS)
+ op1 = rx_legitimize_address (op1, op1, mode);
+
+ if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+ return gen_rtx_PLUS (Pmode, op0, op1);
+ }
return x;
}
@@ -970,7 +994,8 @@ rx_gen_move_template (rtx * operands, bool is_movu)
rtx src = operands[1];
/* Decide which extension, if any, should be given to the move instruction.
*/
- switch (CONST_INT_P (src) ? GET_MODE (dest) : GET_MODE (src))
+ /* When zero-extending, always check the size of the source. */
+ switch ((is_movu || MEM_P(src)) ? GET_MODE (src) : GET_MODE(dest))
{
case E_QImode:
/* The .B extension is not valid when
@@ -984,10 +1009,9 @@ rx_gen_move_template (rtx * operands, bool is_movu)
loading an immediate into a register. */
extension = ".W";
break;
- case E_DFmode:
- case E_DImode:
case E_SFmode:
case E_SImode:
+ gcc_assert(! is_movu);
extension = ".L";
break;
case E_VOIDmode:
@@ -1025,18 +1049,8 @@ rx_gen_move_template (rtx * operands, bool is_movu)
else
dst_template = "%0";
- if (GET_MODE (dest) == DImode || GET_MODE (dest) == DFmode)
- {
- gcc_assert (! is_movu);
-
- if (REG_P (src) && REG_P (dest) && (REGNO (dest) == REGNO (src) + 1))
- sprintf (out_template, "mov.L\t%%H1, %%H0 ! mov.L\t%%1, %%0");
- else
- sprintf (out_template, "mov.L\t%%1, %%0 ! mov.L\t%%H1, %%H0");
- }
- else
- sprintf (out_template, "%s%s\t%s, %s", is_movu ? "movu" : "mov",
- extension, src_template, dst_template);
+ sprintf (out_template, "%s%s\t%s, %s", is_movu ? "movu" : "mov",
+ extension, src_template, dst_template);
return out_template;
}
@@ -1568,12 +1582,9 @@ rx_get_stack_layout (unsigned int * lowest,
* register_mask = 0;
}
- * frame_size = rx_round_up
- (get_frame_size (), STACK_BOUNDARY / BITS_PER_UNIT);
-
- if (crtl->args.size > 0)
- * frame_size += rx_round_up
- (crtl->args.size, STACK_BOUNDARY / BITS_PER_UNIT);
+ * frame_size = rx_round_up (
+ get_frame_size () + crtl->args.pretend_args_size,
+ STACK_BOUNDARY / BITS_PER_UNIT);
* stack_size = rx_round_up
(crtl->outgoing_args_size, STACK_BOUNDARY / BITS_PER_UNIT);
@@ -2221,30 +2232,27 @@ rx_initial_elimination_offset (int from, int to)
unsigned int frame_size;
unsigned int stack_size;
unsigned int mask;
+ unsigned int saved_regs_size = 0;
rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size);
- if (from == ARG_POINTER_REGNUM)
- {
- /* Extend the computed size of the stack frame to
- include the registers pushed in the prologue. */
- if (low)
- frame_size += ((high - low) + 1) * UNITS_PER_WORD;
- else
- frame_size += bit_count (mask) * UNITS_PER_WORD;
-
- /* Remember to include the return address. */
- frame_size += 1 * UNITS_PER_WORD;
+ if (mask != 0)
+ /* multiple push reg */
+ saved_regs_size = bit_count (mask) * UNITS_PER_WORD;
+ else if (low != 0)
+ /* pushm low - high */
+ saved_regs_size = (high - low + 1) * UNITS_PER_WORD;
+ if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+ return stack_size;
+ else if (from == ARG_POINTER_REGNUM)
+ {
if (to == FRAME_POINTER_REGNUM)
- return frame_size;
-
- gcc_assert (to == STACK_POINTER_REGNUM);
- return frame_size + stack_size;
+ return frame_size + saved_regs_size + 4;
+ else if (to == STACK_POINTER_REGNUM)
+ return frame_size + stack_size + saved_regs_size + 4;
}
-
- gcc_assert (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM);
- return stack_size;
+ gcc_unreachable ();
}
/* Decide if a variable should go into one of the small data sections. */
@@ -3495,12 +3503,6 @@ rx_ok_to_inline (tree caller, tree callee)
|| lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (callee)) != NULL_TREE;
}
-static bool
-rx_enable_lra (void)
-{
- return TARGET_ENABLE_LRA;
-}
-
rx_atomic_sequence::rx_atomic_sequence (const_tree fun_decl)
{
if (is_fast_interrupt_func (fun_decl) || is_interrupt_func (fun_decl))
@@ -3611,13 +3613,13 @@ rx_fuse_in_memory_bitop (rtx* operands, rtx_insn*
curr_insn,
static unsigned int
rx_hard_regno_nregs (unsigned int, machine_mode mode)
{
- return CLASS_MAX_NREGS (0, mode);
+ return (GET_MODE_SIZE (mode) <= 4) ? 1 : (GET_MODE_SIZE (mode) + 3) / 4;
}
/* Implement TARGET_HARD_REGNO_MODE_OK. */
static bool
-rx_hard_regno_mode_ok (unsigned int regno, machine_mode)
+rx_hard_regno_mode_ok (unsigned int regno, machine_mode mode ATTRIBUTE_UNUSED)
{
return REGNO_REG_CLASS (regno) == GR_REGS;
}
@@ -3627,7 +3629,9 @@ rx_hard_regno_mode_ok (unsigned int regno, machine_mode)
static bool
rx_modes_tieable_p (machine_mode mode1, machine_mode mode2)
{
- return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
+ return (GET_MODE_CLASS (mode1) == MODE_INT
+ && GET_MODE_CLASS (mode2) == MODE_INT)
+ || ((GET_MODE_CLASS (mode1) == MODE_FLOAT
|| GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
== (GET_MODE_CLASS (mode2) == MODE_FLOAT
|| GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
@@ -3644,7 +3648,82 @@ rx_c_mode_for_floating_type (enum tree_index ti)
return TARGET_64BIT_DOUBLES ? DFmode : SFmode;
return default_mode_for_floating_type (ti);
}
+
+static rtx
+rx_get_subword (rtx op, machine_mode mode, int reg_offset)
+{
+ int mem_offset = reg_offset * 4;
+ if (TARGET_BIG_ENDIAN_DATA)
+ mem_offset = 4 - mem_offset;
+
+ if (MEM_P (op))
+ {
+ rtx addr = XEXP (op, 0);
+ rtx new_addr = plus_constant (Pmode, addr, mem_offset);
+ rtx new_mem = gen_rtx_MEM (SImode, new_addr);
+ MEM_COPY_ATTRIBUTES (new_mem, op);
+ return new_mem;
+ }
+
+ if (REG_P (op) && REGNO (op) < FIRST_PSEUDO_REGISTER)
+ return gen_rtx_REG (SImode, REGNO (op) + reg_offset);
+
+ return simplify_gen_subreg (SImode, op, mode, mem_offset);
+}
+
+void
+rx_split_double_move (rtx * operands, machine_mode mode)
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+
+ rtx real_dest = (GET_CODE (dest) == SUBREG) ? SUBREG_REG (dest) : dest;
+ rtx real_src = (GET_CODE (src) == SUBREG) ? SUBREG_REG (src) : src;
+
+ rtx dest_low, dest_high, src_low, src_high;
+
+ src_low = rx_get_subword (MEM_P (real_src) ? real_src : src, mode, 0);
+ src_high = rx_get_subword (MEM_P (real_src) ? real_src : src, mode, 1);
+
+ dest_low = rx_get_subword (MEM_P (real_dest) ? real_dest : dest, mode, 0);
+ dest_high = rx_get_subword (MEM_P (real_dest) ? real_dest : dest, mode, 1);
+
+ if (REG_P (operands[0]) && reg_overlap_mentioned_p (dest_low, operands[1]))
+ {
+ emit_move_insn (dest_high, src_high);
+ emit_move_insn (dest_low, src_low);
+ }
+ else
+ {
+ emit_move_insn (dest_low, src_low);
+ emit_move_insn (dest_high, src_high);
+ }
+}
+
+void
+rx_relax_double_operands(rtx * operands, machine_mode mode)
+{
+ if (MEM_P (operands[0]) && !rx_restricted_mem_operand (operands[0], mode))
+ {
+ rtx addr = XEXP (operands[0], 0);
+ addr = force_reg (Pmode, addr);
+ operands[0] = replace_equiv_address (operands[0], addr);
+ }
+
+ if (MEM_P (operands[1]) && !rx_restricted_mem_operand (operands[1], mode))
+ {
+ rtx addr = XEXP (operands[1], 0);
+ addr = force_reg (Pmode, addr);
+ operands[1] = replace_equiv_address (operands[1], addr);
+ }
+
+ if (MEM_P (operands[0]) && !REG_P (operands[1]))
+ {
+ operands[1] = force_reg (mode, operands[1]);
+ }
+}
+
#undef TARGET_NARROW_VOLATILE_BITFIELD
#define TARGET_NARROW_VOLATILE_BITFIELD
rx_narrow_volatile_bitfield
@@ -3786,16 +3865,13 @@ rx_c_mode_for_floating_type (enum tree_index ti)
#undef TARGET_WARN_FUNC_RETURN
#define TARGET_WARN_FUNC_RETURN rx_warn_func_return
-#undef TARGET_LRA_P
-#define TARGET_LRA_P rx_enable_lra
-
#undef TARGET_HARD_REGNO_NREGS
#define TARGET_HARD_REGNO_NREGS rx_hard_regno_nregs
#undef TARGET_HARD_REGNO_MODE_OK
#define TARGET_HARD_REGNO_MODE_OK rx_hard_regno_mode_ok
#undef TARGET_MODES_TIEABLE_P
-#define TARGET_MODES_TIEABLE_P rx_modes_tieable_p
+#define TARGET_MODES_TIEABLE_P rx_modes_tieable_p
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS rx_rtx_costs
diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h
index a363a3caaad..f78c103fcb2 100644
--- a/gcc/config/rx/rx.h
+++ b/gcc/config/rx/rx.h
@@ -195,13 +195,10 @@ enum reg_class
{ \
{ 0x00000000 }, /* No registers, */ \
{ 0x0000ffff }, /* Integer registers. */ \
- { 0x0000ffff } /* All registers. */ \
+ { 0x0001ffff } /* All registers. */ \
}
#define N_REG_CLASSES (int) LIM_REG_CLASSES
-#define CLASS_MAX_NREGS(CLASS, MODE) ((GET_MODE_SIZE (MODE) \
- + UNITS_PER_WORD - 1) \
- / UNITS_PER_WORD)
#define GENERAL_REGS GR_REGS
#define BASE_REG_CLASS GR_REGS
diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
index 808dfc8b35a..0cccb342ff8 100644
--- a/gcc/config/rx/rx.md
+++ b/gcc/config/rx/rx.md
@@ -575,17 +575,11 @@
""
{
if (MEM_P (operands[0]) && MEM_P (operands[1]))
- operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);
+ operands[1] = force_reg (<register_modes:MODE>mode, operands[1]);
operands[0] = rx_maybe_pidify_operand (operands[0], 0);
operands[1] = rx_maybe_pidify_operand (operands[1], 0);
- if (GET_CODE (operands[0]) != REG
- && GET_CODE (operands[1]) == PLUS)
- operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);
- if (GET_CODE (operands[1]) == PLUS && GET_MODE (operands[1]) == SImode)
- {
- emit_insn (gen_addsi3 (operands[0], XEXP (operands[1], 0), XEXP
(operands[1], 1)));
- DONE;
- }
+ if (MEM_P (operands[0]) && GET_CODE (operands[1]) == PLUS)
+ operands[1] = force_reg (<register_modes:MODE>mode, operands[1]);
if (CONST_INT_P (operand1)
&& ! rx_is_legitimate_constant (<register_modes:MODE>mode, operand1))
FAIL;
@@ -603,6 +597,58 @@
(set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11,11")]
)
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ {
+ rx_relax_double_operands(operands, DImode);
+
+ emit_insn (gen_movdi_internal (operands[0], operands[1]));
+ DONE;
+ }
+)
+
+(define_insn_and_split "movdi_internal"
+ [(set (match_operand:DI 0 "rx_double_dest_operand" "=r,r,m")
+ (match_operand:DI 1 "rx_double_src_operand" "ri,m,r"))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ rx_split_double_move (operands, DImode);
+ DONE;
+ }
+ [(set_attr "length" "8")]
+)
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ {
+ rx_relax_double_operands(operands, DFmode);
+
+ emit_insn (gen_movdf_internal (operands[0], operands[1]));
+ DONE;
+ }
+)
+
+(define_insn_and_split "movdf_internal"
+ [(set (match_operand:DF 0 "rx_double_dest_operand" "=r,r,m")
+ (match_operand:DF 1 "rx_double_src_operand" "rF,m,r"))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ rx_split_double_move (operands, DFmode);
+ DONE;
+ }
+ [(set_attr "length" "8")]
+)
+
(define_insn "extend<small_int_modes:mode>si2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(sign_extend:SI (match_operand:small_int_modes
@@ -974,6 +1020,29 @@
(set_attr "length" "3,4,5,6,7,6")]
)
+(define_insn "addsi3_pid"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0")
+ (const:SI (unspec:SI [(match_operand:SI 2 "immediate_operand"
"i")] UNSPEC_PID_ADDR))))]
+ ""
+ "add\t%2, %0"
+ [(set_attr "length" "6")
+ (set_attr "timings" "11")]
+)
+
+(define_insn "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0")
+ (match_operand:DI 2 "rx_source_operand" "r,i,Q")))
+ (clobber (reg:CC CC_REG))]
+ ""
+ {
+ return "add\t%L2, %L0\n\tadc\t%H2, %H0";
+ }
+ [(set_attr "length" "6")
+ (set_attr "timings" "22")]
+)
+
;; Peepholes to match:
;; (set (reg A) (reg B))
;; (set (CC) (compare:CC (reg A/reg B) (const_int 0)))
@@ -1007,93 +1076,6 @@
(plus:SI (match_dup 1) (const_int 0)))])]
)
-(define_expand "adddi3"
- [(set (match_operand:DI 0 "register_operand")
- (plus:DI (match_operand:DI 1 "register_operand")
- (match_operand:DI 2 "rx_source_operand")))]
- ""
-{
- rtx op0l, op0h, op1l, op1h, op2l, op2h;
-
- op0l = gen_lowpart (SImode, operands[0]);
- op1l = gen_lowpart (SImode, operands[1]);
- op2l = gen_lowpart (SImode, operands[2]);
- op0h = gen_highpart (SImode, operands[0]);
- op1h = gen_highpart (SImode, operands[1]);
- op2h = gen_highpart_mode (SImode, DImode, operands[2]);
-
- emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
- DONE;
-})
-
-(define_insn_and_split "adddi3_internal"
- [(set (match_operand:SI 0 "register_operand" "=&r")
- (plus:SI (match_operand:SI 2 "register_operand" "r")
- (match_operand:SI 3 "rx_source_operand" "riQ")))
- (set (match_operand:SI 1 "register_operand" "=r")
- (plus:SI
- (plus:SI
- (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
- (match_operand:SI 4 "register_operand" "%1"))
- (match_operand:SI 5 "rx_source_operand" "riQ")))
- (clobber (match_scratch:SI 6 "=&r"))
- (clobber (reg:CC CC_REG))]
- ""
- "#"
- "reload_completed"
- [(const_int 0)]
-{
- rtx op0l = operands[0];
- rtx op0h = operands[1];
- rtx op1l = operands[2];
- rtx op2l = operands[3];
- rtx op1h = operands[4];
- rtx op2h = operands[5];
- rtx scratch = operands[6];
- rtx x;
-
- if (reg_overlap_mentioned_p (op0l, op1h))
- {
- emit_move_insn (scratch, op0l);
- op1h = scratch;
- if (reg_overlap_mentioned_p (op0l, op2h))
- op2h = scratch;
- }
- else if (reg_overlap_mentioned_p (op0l, op2h))
- {
- emit_move_insn (scratch, op0l);
- op2h = scratch;
- }
-
- if (rtx_equal_p (op0l, op1l))
- ;
- /* It is preferable that op0l == op1l... */
- else if (rtx_equal_p (op0l, op2l))
- x = op1l, op1l = op2l, op2l = x;
- /* ... but it is only a requirement if op2l == MEM. */
- else if (MEM_P (op2l))
- {
- /* Let's hope that we still have a scratch register free. */
- gcc_assert (op1h != scratch);
- emit_move_insn (scratch, op2l);
- op2l = scratch;
- }
-
- emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
-
- if (rtx_equal_p (op0h, op1h))
- ;
- else if (rtx_equal_p (op0h, op2h))
- x = op1h, op1h = op2h, op2h = x;
- else
- {
- emit_move_insn (op0h, op1h);
- op1h = op0h;
- }
- emit_insn (gen_adc_internal (op0h, op1h, op2h));
- DONE;
-})
-
(define_insn_and_split "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r")
(and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0")
@@ -1694,45 +1676,18 @@
(set_attr "length" "3,6")]
)
-(define_expand "subdi3"
- [(set (match_operand:DI 0 "register_operand")
- (minus:DI (match_operand:DI 1 "register_operand")
- (match_operand:DI 2 "register_operand")))]
- ""
-{
- rtx op0l, op0h, op1l, op1h, op2l, op2h;
-
- op0l = gen_lowpart (SImode, operands[0]);
- op1l = gen_lowpart (SImode, operands[1]);
- op2l = gen_lowpart (SImode, operands[2]);
- op0h = gen_highpart (SImode, operands[0]);
- op1h = gen_highpart (SImode, operands[1]);
- op2h = gen_highpart_mode (SImode, DImode, operands[2]);
-
- emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
- DONE;
-})
-
-(define_insn_and_split "subdi3_internal"
- [(set (match_operand:SI 0 "register_operand" "=&r,&r")
- (minus:SI (match_operand:SI 2 "register_operand" " 0, r")
- (match_operand:SI 3 "rx_compare_operand" "rQ, r")))
- (set (match_operand:SI 1 "register_operand" "= r, r")
- (minus:SI
- (minus:SI
- (match_operand:SI 4 "register_operand" " 1, 1")
- (match_operand:SI 5 "rx_compare_operand" " rQ,rQ"))
- (gtu:SI (match_dup 3) (match_dup 2))))
+(define_insn "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (minus:DI (match_operand:DI 1 "register_operand" "0,0")
+ (match_operand:DI 2 "rx_source_operand" "r,Q")))
(clobber (reg:CC CC_REG))]
""
- "#"
- "reload_completed"
- [(const_int 0)]
-{
- emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3]));
- emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5]));
- DONE;
-})
+ {
+ return "sub\t%L2, %L0\n\tsbb\t%H2, %H0";
+ }
+ [(set_attr "length" "6")
+ (set_attr "timings" "22")]
+)
(define_insn_and_split "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r")
@@ -1936,6 +1891,7 @@
[(set_attr "timings" "33")
(set_attr "length" "5")] ;; This length is corrected in
rx_adjust_insn_length
)
+
;; Floating Point Instructions
@@ -2870,20 +2826,33 @@
""
)
-(define_insn "movdi"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
- (match_operand:DI 1 "general_operand" "rmi"))]
- "TARGET_ENABLE_LRA"
- { return rx_gen_move_template (operands, false); }
- [(set_attr "length" "16")
- (set_attr "timings" "22")]
+;; RX does not allow addition without destroying CC.
+;; As an alternative to addptrsi3, we define addsi3, which hides changes to CC.
+(define_insn_and_split "*addsi3_lra"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "0,r")
+ (match_operand:SI 2 "rx_source_operand" "ri,ri")))]
+ "lra_in_progress || reload_completed"
+ "#"
+ "&& reload_completed"
+ [(parallel [
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 16))
+ ])]
)
-(define_insn "movdf"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=rm")
- (match_operand:DF 1 "general_operand" "rmi"))]
- "TARGET_ENABLE_LRA"
- { return rx_gen_move_template (operands, false); }
- [(set_attr "length" "16")
- (set_attr "timings" "22")]
+(define_insn_and_split "*ashlsi3_lra"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "rx_shift_operand" "r,i,i")))]
+ "lra_in_progress || reload_completed"
+ "@
+ shll\t%2, %0
+ shll\t%2, %0
+ shll\t%2, %1, %0"
+ "&& reload_completed"
+ [(parallel [
+ (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC CC_REG))
+ ])]
)
diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt
index 5caad487389..0e4c9872356 100644
--- a/gcc/config/rx/rx.opt
+++ b/gcc/config/rx/rx.opt
@@ -128,12 +128,6 @@ Enable the use the standard RX ABI where all stacked
function arguments are natu
;---------------------------------------------------
-mlra
-Target Mask(ENABLE_LRA)
-Enable the use of the LRA register allocator.
-
-;---------------------------------------------------
-
mallow-string-insns
Target Var(rx_allow_string_insns) Init(1)
Enables or disables the use of the SMOVF, SMOVB, SMOVU, SUNTIL, SWHILE and
RMPA instructions. Enabled by default.
--
2.47.3