The LRA was confused and looping due to the definition of the register class.
The LRA yielded incorrect results because the manipulation of stack frames
and the movement of double words relied heavily on existing reloads.
These changes ensure that the correct code is generated even when the "-mlra"
option is specified.
v5 changes.
- Moved the XEXP extractions inside the PLUS check in rx_legitimize_address.
- Replaced the magic number 8 with UNITS_PER_WORD * 2.
- Fixed the C comment style.
- Reverted the redundant changes in rx_modes_tieable_p.
- Added the missing function comments for rx_get_subword, rx_split_double_move,
and rx_relax_double_operands.
- Removed the redundant checks in rx_relax_double_operands and fixed the
indentation.
- Removed the redundant emit_insn and DONE in the movdi and movdf expanders.
- Replaced the output template of *ashlsi3_lra with "#" since it is
always split.
PR113948
ChangeLog:
* gcc/config/rx/rx-protos.h (rx_split_double_move): New helper
prototype.
(rx_relax_double_operands): Likewise.
* gcc/config/rx/rx.cc (rx_legitimize_address): Add expand complex case.
(rx_is_legitimate_address): Add double word 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_hard_regno_nregs): Use CEIL.
(rx_hard_regno_mode_ok): Add ATTRIBUTE_UNUSED.
(rx_get_subword): New. Double word move helper.
(rx_split_double_move): Likewise.
(rx_relax_double_operands): Likewise.
* 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.
(addsi3_lra): New. alternative addptrsi3.
(ashlsi3_lra): likewise.
Signed-off-by: Yoshinori Sato <[email protected]>
---
gcc/config/rx/rx-protos.h | 2 +
gcc/config/rx/rx.cc | 150 ++++++++++++++++++++++++++++----------
gcc/config/rx/rx.h | 5 +-
gcc/config/rx/rx.md | 113 +++++++++++++++++++++-------
4 files changed, 203 insertions(+), 67 deletions(-)
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..69f4b214fee 100644
--- a/gcc/config/rx/rx.cc
+++ b/gcc/config/rx/rx.cc
@@ -154,11 +154,22 @@ rx_legitimize_address (rtx 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)
+ {
+ rtx op0 = XEXP (x, 0);
+ rtx op1 = XEXP (x, 1);
+
+ 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 simplify_gen_binary (PLUS, Pmode, new_base, index);
+ }
+ }
return x;
}
@@ -194,6 +205,27 @@ rx_is_legitimate_address (machine_mode mode, rtx x,
Post-increment Register Indirect. */
return RTX_OK_FOR_BASE (XEXP (x, 0), strict);
+ if (GET_MODE_SIZE (mode) == UNITS_PER_WORD * 2)
+ {
+ /* Since double-word memory access is split into multiple parts,
+ only simple indirect addresses are accepted. */
+ if (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
+ return false;
+
+ if (GET_CODE (x) == PLUS)
+ {
+ rtx base = XEXP (x, 0);
+ rtx index = XEXP (x, 1);
+
+ if (!REG_P (base) || !CONST_INT_P (index))
+ return false;
+
+ if (!IN_RANGE (INTVAL (index), 0, (0x10000 * 4) - 1 - 4)
+ || (INTVAL (index) % 4) != 0)
+ return false;
+ }
+ }
+
switch (rx_pid_data_operand (x))
{
case PID_UNENCODED:
@@ -970,7 +1002,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 +1017,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 +1057,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 +1590,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,26 +2240,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 (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 == 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;
+ frame_size += UNITS_PER_WORD;
if (to == FRAME_POINTER_REGNUM)
- return frame_size;
+ return frame_size + saved_regs_size;
gcc_assert (to == STACK_POINTER_REGNUM);
- return frame_size + stack_size;
+ return frame_size + stack_size + saved_regs_size;
}
gcc_assert (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM);
@@ -3611,13 +3631,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 CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
}
/* 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;
}
@@ -3644,7 +3664,61 @@ rx_c_mode_for_floating_type (enum tree_index ti)
return TARGET_64BIT_DOUBLES ? DFmode : SFmode;
return default_mode_for_floating_type (ti);
}
+
+/* Return one word of doubleword value OP, where OP has mode MODE.
+ A REG_OFFSET of 0 selects the low word and a REG_OFFSET of 1 selects
+ the high word. */
+static rtx
+rx_get_subword (rtx op, machine_mode mode, int reg_offset)
+{
+ unsigned int mem_offset = reg_offset * 4;
+ if (TARGET_BIG_ENDIAN_DATA)
+ mem_offset = 4 - mem_offset;
+
+ if (MEM_P (op))
+ return adjust_address (op, SImode, mem_offset);
+ else
+ return simplify_gen_subreg (SImode, op, mode, mem_offset);
+}
+
+/* Split a doubleword move with operands OPERANDS.
+ Both operands have mode MODE. */
+void
+rx_split_double_move (rtx * operands, machine_mode mode)
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+
+ rtx dest_low, dest_high, src_low, src_high;
+
+ src_low = rx_get_subword (src, mode, 0);
+ src_high = rx_get_subword (src, mode, 1);
+
+ dest_low = rx_get_subword (dest, mode, 0);
+ dest_high = rx_get_subword (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);
+ }
+}
+
+/* Adjust the operands of a doubleword move. OPERANDS gives the operands and
+ MODE gives the mode of the operands. */
+void
+rx_relax_double_operands(rtx * operands, machine_mode mode)
+{
+ 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
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 83aab0f14b2..b3398ab9fc5 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,52 @@
(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);
+ }
+)
+
+(define_insn_and_split "movdi_internal"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m")
+ (match_operand:DI 1 "general_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);
+ }
+)
+
+(define_insn_and_split "movdf_internal"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
+ (match_operand:DF 1 "general_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
@@ -975,6 +1015,18 @@
(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))))
+ (clobber (reg:CC CC_REG))]
+
+ ""
+ "add\t%2, %0"
+ [(set_attr "length" "6")
+ (set_attr "timings" "11")]
+)
+
;; Peepholes to match:
;; (set (reg A) (reg B))
;; (set (CC) (compare:CC (reg A/reg B) (const_int 0)))
@@ -1938,6 +1990,7 @@
[(set_attr "timings" "33")
(set_attr "length" "5")] ;; This length is corrected in
rx_adjust_insn_length
)
+
;; Floating Point Instructions
@@ -2872,20 +2925,30 @@
""
)
-(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")]
-)
-
-(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")]
+;; 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")))]
+ "!post_ra_split_completed"
+ "#"
+ "&& 1"
+ [(parallel [
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC 16))
+ ])]
+)
+
+(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")))]
+ "!post_ra_split_completed"
+ "#"
+ "&& 1"
+ [(parallel [
+ (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
+ (clobber (reg:CC CC_REG))
+ ])]
)
--
2.47.3