Yoshinori Sato <[email protected]> writes:
> 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.

Thanks, LGTM.  Pushed to trunk as r17-468-g7ec6968058b393
(with a slightly tweaked changelog).

Richard

>
>       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))
> +   ])]
>  )

Reply via email to