[{"id":3682295,"web_url":"http://patchwork.ozlabs.org/comment/3682295/","msgid":"<87mryr80yg.fsf@gentoo.org>","list_archive_url":null,"date":"2026-04-25T16:21:59","subject":"Re: [RFC PATCH v3] RX: enable LRA is default","submitter":{"id":83216,"url":"http://patchwork.ozlabs.org/api/people/83216/","name":"Sam James","email":"sam@gentoo.org"},"content":"Yoshinori Sato <yoshinori.sato@nifty.com> writes:\n\n> Always enable LRA on RX targets.\n> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113948\n\nCC'd the RX maintainer (Nick). But some small comments, I can't offer\nany others here.\n\n>\n> The previous fix did not adequately address the LRA infinite loop issue.\n> It was discovered that the infinite loop was caused by the definition of\n> the register class.\n> The stack frame manipulation was not compatible with LRA register spills,\n> so that part has also been corrected.\n\nI think this should be two patches:\n1) to fix LRA incompatibilities;\n2) change the default;\nand perhaps even a third (but that's debatable);\n3) drop -mlra.\n\n>\n> v3 changes.\n> - A complete solution to the LRA infinite loop.\n> - I reverted the memory access cost adjustment because it no longer made sense.\n> - revert adc and sbb.\n>\n> ChangeLog:\n\nPlease add:\n\n       PR target/113948\n\n>         * gcc/config/rx/predicates.md (rx_double_src_operand): New.\n>         (rx_double_dest_operand): New.\n>         * gcc/config/rx/rx-protos.h (rx_split_double_move): New helper proto.\n>         (rx_relax_double_operands): Likewise.\n>         * gcc/config/rx/rx.cc (rx_legitimize_address): Add expand complex case\n> \t(rx_gen_move_template): Fix operation size in unsigned extend.\n>         (rx_gen_move_template): Remove DImode and DFmode.\n> \t(rx_get_stack_layout): Fix for frame size calculation.\n> \t(rx_initial_elimination_offset): The calculation method has been changed to one that supports LRA.\n>         (rx_enable_lra): Remove.\n> \t(rx_hard_regno_nregs): Rewrite.\n>         (rx_hard_regno_mode_ok): Add ATTRIBUTE_UNUSED.\n>         (rx_modes_tieable_p): Add int case.\n>         (rx_get_subword): New. Double word move helper.\n>         (rx_split_double_move): Likewise.\n>         (rx_relax_double_operands): Likewise.\n>         (TARGET_LRA_P): Remove.\n> \t* gcc/config/rx/rx.h (reg_class): Add CC for all regsisters.\n> \t(CLASS_MAX_NREGS): Remove.\n>         * gcc/config/rx/rx.md (mov<register_modes:mode>):\n> \tReplace copy_to_mode_reg to force_reg.\n>         (movdi): Limit the arguments to make register allocation easier.\n>         (movdf): Likewise.\n>         (movdi_internal): New.\n>         (movdf_internal): New.\n>         (addsi3_pid): New. Handling UNSPEC_PID_ADDR.\n>         (adddi3): New. simplify implementation.\n>         (subdi3): Likewise.\n>         (addsi3_lra): New. alternative addptrsi3.\n>         (ashlsi3_lra): likewise.\n>         * gcc/config/rx/rx.opt (mlra): Remove.\n>\n> Signed-off-by: Yoshinori Sato <yoshinori.sato@nifty.com>\n> ---\n>  gcc/config/rx/predicates.md |  14 ++\n>  gcc/config/rx/rx-protos.h   |   2 +\n>  gcc/config/rx/rx.cc         | 190 ++++++++++++++++++--------\n>  gcc/config/rx/rx.h          |   5 +-\n>  gcc/config/rx/rx.md         | 263 ++++++++++++++++--------------------\n>  gcc/config/rx/rx.opt        |   6 -\n>  6 files changed, 266 insertions(+), 214 deletions(-)\n>\n> diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md\n> index aa926be31ac..37fd63b538a 100644\n> --- a/gcc/config/rx/predicates.md\n> +++ b/gcc/config/rx/predicates.md\n> @@ -307,3 +307,17 @@\n>  (define_predicate \"rshift_operator\"\n>    (match_code \"ashiftrt,lshiftrt\")\n>  )\n> +\n> +;; DI and DF are expanded into multiple mov instructions,\n> +;; so they require stronger constraints than regular move.\n> +(define_predicate \"rx_double_src_operand\"\n> +  (ior (and (match_code \"reg,subreg,const_int,const_double\")\n> +            (match_operand 0 \"general_operand\"))\n> +       (and (match_code \"mem\")\n> +            (match_operand 0 \"rx_restricted_mem_operand\"))))\n> +\n> +(define_predicate \"rx_double_dest_operand\"\n> +  (ior (and (match_code \"reg,subreg\")\n> +            (match_operand 0 \"general_operand\"))\n> +       (and (match_code \"mem\")\n> +            (match_operand 0 \"rx_restricted_mem_operand\"))))\n> diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h\n> index 829882b0bc8..5a36ef26948 100644\n> --- a/gcc/config/rx/rx-protos.h\n> +++ b/gcc/config/rx/rx-protos.h\n> @@ -70,6 +70,8 @@ extern void rx_copy_reg_dead_or_unused_notes (rtx reg, const rtx_insn* src,\n>  \n>  extern bool rx_fuse_in_memory_bitop (rtx* operands, rtx_insn* curr_insn,\n>  \t\t\t\t     rtx (*gen_insn)(rtx, rtx));\n> +extern void rx_split_double_move (rtx* operands, machine_mode mode);\n> +extern void rx_relax_double_operands (rtx* operands, machine_mode mode);\n>  \n>  /* Result value of rx_find_set_of_reg.  */\n>  struct set_of_reg\n> diff --git a/gcc/config/rx/rx.cc b/gcc/config/rx/rx.cc\n> index 902e756a34e..4675cf6b286 100644\n> --- a/gcc/config/rx/rx.cc\n> +++ b/gcc/config/rx/rx.cc\n> @@ -148,17 +148,41 @@ rx_legitimize_address (rtx x,\n>  \t\t       rtx oldx ATTRIBUTE_UNUSED,\n>  \t\t       machine_mode mode ATTRIBUTE_UNUSED)\n>  {\n> +  rtx op0 = XEXP (x, 0);\n> +  rtx op1 = XEXP (x, 1);\n> +\n>    if (rx_pid_data_operand (x) == PID_UNENCODED)\n>      {\n>        rtx rv = gen_pid_addr (gen_rtx_REG (SImode, rx_pid_base_regnum ()), x);\n>        return rv;\n>      }\n>  \n> -  if (GET_CODE (x) == PLUS\n> -      && GET_CODE (XEXP (x, 0)) == PLUS\n> -      && REG_P (XEXP (XEXP (x, 0), 0))\n> -      && REG_P (XEXP (x, 1)))\n> -    return force_reg (SImode, x);\n> +  if (GET_CODE (x) == PLUS)\n> +    {\n> +      if (GET_CODE (op0) == PLUS && REG_P (XEXP (op0, 0)) &&\n> +\t  CONST_INT_P (op1))\n> +\t{\n> +\t  rtx base = XEXP (op0, 0);\n> +\t  rtx index = XEXP (op0, 1);\n> +\n> +\t  rtx new_base = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, op1));\n> +\t  return gen_rtx_PLUS (Pmode, new_base, index);\n> +\t}\n> +\n> +      if (GET_CODE (op0) == MULT || GET_CODE (op0) == ASHIFT)\n> +\top0 = force_reg (Pmode, op0);\n> +\n> +      if (GET_CODE (op1) == MULT || GET_CODE (op1) == ASHIFT)\n> +\top1 = force_reg (Pmode, op1);\n> +\n> +      if (GET_CODE (op0) == PLUS)\n> +\top0 = rx_legitimize_address (op0, op0, mode);\n> +      if (GET_CODE (op1) == PLUS)\n> +\top1 = rx_legitimize_address (op1, op1, mode);\n> +\n> +      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))\n> +\treturn gen_rtx_PLUS (Pmode, op0, op1);\n> +    }\n>  \n>    return x;\n>  }\n> @@ -970,7 +994,8 @@ rx_gen_move_template (rtx * operands, bool is_movu)\n>    rtx          src  = operands[1];\n>  \n>    /* Decide which extension, if any, should be given to the move instruction.  */\n> -  switch (CONST_INT_P (src) ? GET_MODE (dest) : GET_MODE (src))\n> +  /* When zero-extending, always check the size of the source. */\n> +  switch ((is_movu || MEM_P(src)) ? GET_MODE (src) : GET_MODE(dest))\n>      {\n>      case E_QImode:\n>        /* The .B extension is not valid when\n> @@ -984,10 +1009,9 @@ rx_gen_move_template (rtx * operands, bool is_movu)\n>  \t   loading an immediate into a register.  */\n>  \textension = \".W\";\n>        break;\n> -    case E_DFmode:\n> -    case E_DImode:\n>      case E_SFmode:\n>      case E_SImode:\n> +      gcc_assert(! is_movu);\n>        extension = \".L\";\n>        break;\n>      case E_VOIDmode:\n> @@ -1025,18 +1049,8 @@ rx_gen_move_template (rtx * operands, bool is_movu)\n>    else\n>      dst_template = \"%0\";\n>  \n> -  if (GET_MODE (dest) == DImode || GET_MODE (dest) == DFmode)\n> -    {\n> -      gcc_assert (! is_movu);\n> -\n> -      if (REG_P (src) && REG_P (dest) && (REGNO (dest) == REGNO (src) + 1))\n> -\tsprintf (out_template, \"mov.L\\t%%H1, %%H0 ! mov.L\\t%%1, %%0\");\n> -      else\n> -\tsprintf (out_template, \"mov.L\\t%%1, %%0 ! mov.L\\t%%H1, %%H0\");\n> -    }\n> -  else\n> -    sprintf (out_template, \"%s%s\\t%s, %s\", is_movu ? \"movu\" : \"mov\",\n> -\t     extension, src_template, dst_template);\n> +  sprintf (out_template, \"%s%s\\t%s, %s\", is_movu ? \"movu\" : \"mov\",\n> +\t   extension, src_template, dst_template);\n>    return out_template;\n>  }\n>  \f\n> @@ -1568,12 +1582,9 @@ rx_get_stack_layout (unsigned int * lowest,\n>        * register_mask = 0;\n>      }\n>  \n> -  * frame_size = rx_round_up\n> -    (get_frame_size (), STACK_BOUNDARY / BITS_PER_UNIT);\n> -\n> -  if (crtl->args.size > 0)\n> -    * frame_size += rx_round_up\n> -      (crtl->args.size, STACK_BOUNDARY / BITS_PER_UNIT);\n> +  * frame_size = rx_round_up (\n> +      get_frame_size () + crtl->args.pretend_args_size,\n> +      STACK_BOUNDARY / BITS_PER_UNIT);\n>  \n>    * stack_size = rx_round_up\n>      (crtl->outgoing_args_size, STACK_BOUNDARY / BITS_PER_UNIT);\n> @@ -2221,30 +2232,27 @@ rx_initial_elimination_offset (int from, int to)\n>    unsigned int frame_size;\n>    unsigned int stack_size;\n>    unsigned int mask;\n> +  unsigned int saved_regs_size = 0;\n>  \n>    rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size);\n>  \n> -  if (from == ARG_POINTER_REGNUM)\n> -    {\n> -      /* Extend the computed size of the stack frame to\n> -\t include the registers pushed in the prologue.  */\n> -      if (low)\n> -\tframe_size += ((high - low) + 1) * UNITS_PER_WORD;\n> -      else\n> -\tframe_size += bit_count (mask) * UNITS_PER_WORD;\n> -\n> -      /* Remember to include the return address.  */\n> -      frame_size += 1 * UNITS_PER_WORD;\n> +  if (mask != 0)\n> +    /* multiple push reg */\n> +    saved_regs_size = bit_count (mask) * UNITS_PER_WORD;\n> +  else if (low != 0)\n> +    /* pushm low - high */\n> +    saved_regs_size = (high - low + 1) * UNITS_PER_WORD;\n>  \n> +  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)\n> +    return stack_size;\n> +  else if (from == ARG_POINTER_REGNUM)\n> +    {\n>        if (to == FRAME_POINTER_REGNUM)\n> -\treturn frame_size;\n> -\n> -      gcc_assert (to == STACK_POINTER_REGNUM);\n> -      return frame_size + stack_size;\n> +\treturn frame_size + saved_regs_size + 4;\n> +      else if (to == STACK_POINTER_REGNUM)\n> +\treturn frame_size + stack_size + saved_regs_size + 4;\n>      }\n> -\n> -  gcc_assert (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM);\n> -  return stack_size;\n> +  gcc_unreachable ();\n>  }\n>  \n>  /* Decide if a variable should go into one of the small data sections.  */\n> @@ -3495,12 +3503,6 @@ rx_ok_to_inline (tree caller, tree callee)\n>      || lookup_attribute (\"gnu_inline\", DECL_ATTRIBUTES (callee)) != NULL_TREE;\n>  }\n>  \n> -static bool\n> -rx_enable_lra (void)\n> -{\n> -  return TARGET_ENABLE_LRA;\n> -}\n> -\n>  rx_atomic_sequence::rx_atomic_sequence (const_tree fun_decl)\n>  {\n>    if (is_fast_interrupt_func (fun_decl) || is_interrupt_func (fun_decl))\n> @@ -3611,13 +3613,13 @@ rx_fuse_in_memory_bitop (rtx* operands, rtx_insn* curr_insn,\n>  static unsigned int\n>  rx_hard_regno_nregs (unsigned int, machine_mode mode)\n>  {\n> -  return CLASS_MAX_NREGS (0, mode);\n> +  return (GET_MODE_SIZE (mode) <= 4) ? 1 : (GET_MODE_SIZE (mode) + 3) / 4;\n>  }\n>  \n>  /* Implement TARGET_HARD_REGNO_MODE_OK.  */\n>  \n>  static bool\n> -rx_hard_regno_mode_ok (unsigned int regno, machine_mode)\n> +rx_hard_regno_mode_ok (unsigned int regno, machine_mode mode ATTRIBUTE_UNUSED)\n>  {\n>    return REGNO_REG_CLASS (regno) == GR_REGS;\n>  }\n> @@ -3627,7 +3629,9 @@ rx_hard_regno_mode_ok (unsigned int regno, machine_mode)\n>  static bool\n>  rx_modes_tieable_p (machine_mode mode1, machine_mode mode2)\n>  {\n> -  return ((GET_MODE_CLASS (mode1) == MODE_FLOAT\n> +  return (GET_MODE_CLASS (mode1) == MODE_INT\n> +\t  && GET_MODE_CLASS (mode2) == MODE_INT)\n> +      || ((GET_MODE_CLASS (mode1) == MODE_FLOAT\n>  \t   || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)\n>  \t  == (GET_MODE_CLASS (mode2) == MODE_FLOAT\n>  \t      || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));\n> @@ -3644,7 +3648,82 @@ rx_c_mode_for_floating_type (enum tree_index ti)\n>      return TARGET_64BIT_DOUBLES ? DFmode : SFmode;\n>    return default_mode_for_floating_type (ti);\n>  }\n> +\n> +static rtx\n> +rx_get_subword (rtx op, machine_mode mode, int reg_offset)\n> +{\n> +  int mem_offset = reg_offset * 4;\n> +  if (TARGET_BIG_ENDIAN_DATA)\n> +    mem_offset = 4 - mem_offset;\n> +\n> +  if (MEM_P (op))\n> +    {\n> +      rtx addr = XEXP (op, 0);\n> +      rtx new_addr = plus_constant (Pmode, addr, mem_offset);\n> +      rtx new_mem = gen_rtx_MEM (SImode, new_addr);\n> +      MEM_COPY_ATTRIBUTES (new_mem, op);\n> +      return new_mem;\n> +    }\n> +\n> +  if (REG_P (op) && REGNO (op) < FIRST_PSEUDO_REGISTER)\n> +      return gen_rtx_REG (SImode, REGNO (op) + reg_offset);\n> +\n> +  return simplify_gen_subreg (SImode, op, mode, mem_offset);\n> +}\n> +\n> +void\n> +rx_split_double_move (rtx * operands, machine_mode mode)\n> +{\n> +  rtx dest = operands[0];\n> +  rtx src  = operands[1];\n> +\n> +  rtx real_dest = (GET_CODE (dest) == SUBREG) ? SUBREG_REG (dest) : dest;\n> +  rtx real_src  = (GET_CODE (src)  == SUBREG) ? SUBREG_REG (src)  : src;\n> +\n> +  rtx dest_low, dest_high, src_low, src_high;\n> +\n> +  src_low  = rx_get_subword (MEM_P (real_src) ? real_src : src, mode, 0);\n> +  src_high = rx_get_subword (MEM_P (real_src) ? real_src : src, mode, 1);\n> +\n> +  dest_low  = rx_get_subword (MEM_P (real_dest) ? real_dest : dest, mode, 0);\n> +  dest_high = rx_get_subword (MEM_P (real_dest) ? real_dest : dest, mode, 1);\n> +\n> +  if (REG_P (operands[0]) && reg_overlap_mentioned_p (dest_low, operands[1]))\n> +    {\n> +      emit_move_insn (dest_high, src_high);\n> +      emit_move_insn (dest_low, src_low);\n> +    }\n> +  else\n> +    {\n> +      emit_move_insn (dest_low, src_low);\n> +      emit_move_insn (dest_high, src_high);\n> +    }\n> +}\n> +\n> +void\n> +rx_relax_double_operands(rtx * operands, machine_mode mode)\n> +{\n> +  if (MEM_P (operands[0]) && !rx_restricted_mem_operand (operands[0], mode))\n> +    {\n> +      rtx addr = XEXP (operands[0], 0);\n> +      addr = force_reg (Pmode, addr);\n> +      operands[0] = replace_equiv_address (operands[0], addr);\n> +    }\n> +\n> +  if (MEM_P (operands[1]) && !rx_restricted_mem_operand (operands[1], mode))\n> +    {\n> +      rtx addr = XEXP (operands[1], 0);\n> +      addr = force_reg (Pmode, addr);\n> +      operands[1] = replace_equiv_address (operands[1], addr);\n> +    }\n> +\n> +  if (MEM_P (operands[0]) && !REG_P (operands[1]))\n> +    {\n> +      operands[1] = force_reg (mode, operands[1]);\n> +    }\n> +}\n>  \f\n> +\n>  #undef  TARGET_NARROW_VOLATILE_BITFIELD\n>  #define TARGET_NARROW_VOLATILE_BITFIELD\t\trx_narrow_volatile_bitfield\n>  \n> @@ -3786,16 +3865,13 @@ rx_c_mode_for_floating_type (enum tree_index ti)\n>  #undef  TARGET_WARN_FUNC_RETURN\n>  #define TARGET_WARN_FUNC_RETURN \t\trx_warn_func_return\n>  \n> -#undef  TARGET_LRA_P\n> -#define TARGET_LRA_P \t\t\t\trx_enable_lra\n> -\n>  #undef  TARGET_HARD_REGNO_NREGS\n>  #define TARGET_HARD_REGNO_NREGS\t\t\trx_hard_regno_nregs\n>  #undef  TARGET_HARD_REGNO_MODE_OK\n>  #define TARGET_HARD_REGNO_MODE_OK\t\trx_hard_regno_mode_ok\n>  \n>  #undef  TARGET_MODES_TIEABLE_P\n> -#define TARGET_MODES_TIEABLE_P\t\t\trx_modes_tieable_p\n> +#define TARGET_MODES_TIEABLE_P                 rx_modes_tieable_p\n>  \n>  #undef  TARGET_RTX_COSTS\n>  #define TARGET_RTX_COSTS rx_rtx_costs\n> diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h\n> index a363a3caaad..f78c103fcb2 100644\n> --- a/gcc/config/rx/rx.h\n> +++ b/gcc/config/rx/rx.h\n> @@ -195,13 +195,10 @@ enum reg_class\n>  {\t\t\t\t\t\t\t\\\n>    { 0x00000000 },\t/* No registers,  */\t\t\\\n>    { 0x0000ffff },\t/* Integer registers.  */\t\\\n> -  { 0x0000ffff }\t/* All registers.  */\t\t\\\n> +  { 0x0001ffff }\t/* All registers. */\t\t\\\n>  }\n>  \n>  #define N_REG_CLASSES\t\t\t(int) LIM_REG_CLASSES\n> -#define CLASS_MAX_NREGS(CLASS, MODE)    ((GET_MODE_SIZE (MODE) \\\n> -\t\t\t\t\t  + UNITS_PER_WORD - 1) \\\n> -\t\t\t\t\t / UNITS_PER_WORD)\n>  \n>  #define GENERAL_REGS\t\t\tGR_REGS\n>  #define BASE_REG_CLASS  \t\tGR_REGS\n> diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md\n> index 808dfc8b35a..0cccb342ff8 100644\n> --- a/gcc/config/rx/rx.md\n> +++ b/gcc/config/rx/rx.md\n> @@ -575,17 +575,11 @@\n>    \"\"\n>    {\n>      if (MEM_P (operands[0]) && MEM_P (operands[1]))\n> -      operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);\n> +      operands[1] = force_reg (<register_modes:MODE>mode, operands[1]);\n>      operands[0] = rx_maybe_pidify_operand (operands[0], 0);\n>      operands[1] = rx_maybe_pidify_operand (operands[1], 0);\n> -    if (GET_CODE (operands[0]) != REG\n> -\t&& GET_CODE (operands[1]) == PLUS)\n> -      operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]);\n> -    if (GET_CODE (operands[1]) == PLUS && GET_MODE (operands[1]) == SImode)\n> -      {\n> -        emit_insn (gen_addsi3 (operands[0], XEXP (operands[1], 0), XEXP (operands[1], 1)));\n> -        DONE;\n> -      }\n> +    if (MEM_P (operands[0]) && GET_CODE (operands[1]) == PLUS)\n> +      operands[1] = force_reg (<register_modes:MODE>mode, operands[1]);\n>      if (CONST_INT_P (operand1)\n>          && ! rx_is_legitimate_constant (<register_modes:MODE>mode, operand1))\n>        FAIL;\n> @@ -603,6 +597,58 @@\n>     (set_attr \"timings\" \"11,11,11,11,11,12,11,11,11,11,11,11\")]\n>  )\n>  \n> +(define_expand \"movdi\"\n> +  [(set (match_operand:DI 0 \"nonimmediate_operand\" \"\")\n> +        (match_operand:DI 1 \"general_operand\" \"\"))]\n> +  \"\"\n> +  {\n> +    rx_relax_double_operands(operands, DImode);\n> +\n> +    emit_insn (gen_movdi_internal (operands[0], operands[1]));\n> +    DONE;\n> +  }\n> +)\n> +\n> +(define_insn_and_split \"movdi_internal\"\n> +  [(set (match_operand:DI 0 \"rx_double_dest_operand\" \"=r,r,m\")\n> +        (match_operand:DI 1 \"rx_double_src_operand\"  \"ri,m,r\"))]\n> +  \"\"\n> +  \"#\"\n> +  \"reload_completed\"\n> +  [(const_int 0)]\n> +  {\n> +    rx_split_double_move (operands, DImode);\n> +    DONE;\n> +  }\n> +  [(set_attr \"length\" \"8\")]\n> +)\n> +\n> +(define_expand \"movdf\"\n> +  [(set (match_operand:DF 0 \"nonimmediate_operand\" \"\")\n> +        (match_operand:DF 1 \"general_operand\" \"\"))]\n> +  \"\"\n> +  {\n> +    rx_relax_double_operands(operands, DFmode);\n> +\n> +    emit_insn (gen_movdf_internal (operands[0], operands[1]));\n> +    DONE;\n> +  }\n> +)\n> +\n> +(define_insn_and_split \"movdf_internal\"\n> +  [(set (match_operand:DF 0 \"rx_double_dest_operand\" \"=r,r,m\")\n> +        (match_operand:DF 1 \"rx_double_src_operand\"  \"rF,m,r\"))]\n> +  \"\"\n> +  \"#\"\n> +  \"reload_completed\"\n> +  [(const_int 0)]\n> +  {\n> +    rx_split_double_move (operands, DFmode);\n> +    DONE;\n> +  }\n> +  [(set_attr \"length\" \"8\")]\n> +)\n> +\n>  (define_insn \"extend<small_int_modes:mode>si2\"\n>    [(set (match_operand:SI 0 \"register_operand\"    \"=r,r\")\n>          (sign_extend:SI (match_operand:small_int_modes\n> @@ -974,6 +1020,29 @@\n>     (set_attr \"length\"   \"3,4,5,6,7,6\")]\n>  )\n>  \n> +(define_insn \"addsi3_pid\"\n> +  [(set (match_operand:SI 0 \"register_operand\" \"=r\")\n> +        (plus:SI (match_operand:SI 1 \"register_operand\" \"%0\")\n> +                 (const:SI (unspec:SI [(match_operand:SI 2 \"immediate_operand\" \"i\")] UNSPEC_PID_ADDR))))]\n> +  \"\"\n> +  \"add\\t%2, %0\"\n> +  [(set_attr \"length\" \"6\")\n> +   (set_attr \"timings\" \"11\")]\n> +)\n> +\n> +(define_insn \"adddi3\"\n> +  [(set (match_operand:DI 0 \"register_operand\" \"=r,r,r\")\n> +\t(plus:DI (match_operand:DI 1 \"register_operand\"  \"%0,0,0\")\n> +\t\t (match_operand:DI 2 \"rx_source_operand\"  \"r,i,Q\")))\n> +   (clobber (reg:CC CC_REG))]\n> +  \"\"\n> +  {\n> +    return \"add\\t%L2, %L0\\n\\tadc\\t%H2, %H0\";\n> +  }\n> +  [(set_attr \"length\" \"6\")\n> +   (set_attr \"timings\" \"22\")]\n> +)\n> +\n>  ;; Peepholes to match:\n>  ;;   (set (reg A) (reg B))\n>  ;;   (set (CC) (compare:CC (reg A/reg B) (const_int 0)))\n> @@ -1007,93 +1076,6 @@\n>  \t\t   (plus:SI (match_dup 1) (const_int 0)))])]\n>  )\n>  \n> -(define_expand \"adddi3\"\n> -  [(set (match_operand:DI          0 \"register_operand\")\n> -\t(plus:DI (match_operand:DI 1 \"register_operand\")\n> -\t\t (match_operand:DI 2 \"rx_source_operand\")))]\n> -  \"\"\n> -{\n> -  rtx op0l, op0h, op1l, op1h, op2l, op2h;\n> -\n> -  op0l = gen_lowpart (SImode, operands[0]);\n> -  op1l = gen_lowpart (SImode, operands[1]);\n> -  op2l = gen_lowpart (SImode, operands[2]);\n> -  op0h = gen_highpart (SImode, operands[0]);\n> -  op1h = gen_highpart (SImode, operands[1]);\n> -  op2h = gen_highpart_mode (SImode, DImode, operands[2]);\n> -\n> -  emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));\n> -  DONE;\n> -})\n> -\n> -(define_insn_and_split \"adddi3_internal\"\n> -  [(set (match_operand:SI          0 \"register_operand\"  \"=&r\")\n> -\t(plus:SI (match_operand:SI 2 \"register_operand\"  \"r\")\n> -\t\t (match_operand:SI 3 \"rx_source_operand\" \"riQ\")))\n> -   (set (match_operand:SI          1 \"register_operand\"  \"=r\")\n> -\t(plus:SI\n> -\t  (plus:SI\n> -\t    (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))\n> -\t    (match_operand:SI      4 \"register_operand\"  \"%1\"))\n> -\t  (match_operand:SI        5 \"rx_source_operand\" \"riQ\")))\n> -   (clobber (match_scratch:SI      6                     \"=&r\"))\n> -   (clobber (reg:CC CC_REG))]\n> -  \"\"\n> -  \"#\"\n> -  \"reload_completed\"\n> -  [(const_int 0)]\n> -{\n> -  rtx op0l = operands[0];\n> -  rtx op0h = operands[1];\n> -  rtx op1l = operands[2];\n> -  rtx op2l = operands[3];\n> -  rtx op1h = operands[4];\n> -  rtx op2h = operands[5];\n> -  rtx scratch = operands[6];\n> -  rtx x;\n> -\n> -  if (reg_overlap_mentioned_p (op0l, op1h))\n> -    {\n> -      emit_move_insn (scratch, op0l);\n> -      op1h = scratch;\n> -      if (reg_overlap_mentioned_p (op0l, op2h))\n> -\top2h = scratch;\n> -    }\n> -  else if (reg_overlap_mentioned_p (op0l, op2h))\n> -    {\n> -      emit_move_insn (scratch, op0l);\n> -      op2h = scratch;\n> -    }\n> -\n> -  if (rtx_equal_p (op0l, op1l))\n> -    ;\n> -  /* It is preferable that op0l == op1l...  */\n> -  else if (rtx_equal_p (op0l, op2l))\n> -    x = op1l, op1l = op2l, op2l = x;\n> -  /* ... but it is only a requirement if op2l == MEM.  */\n> -  else if (MEM_P (op2l))\n> -    {\n> -      /* Let's hope that we still have a scratch register free.  */\n> -      gcc_assert (op1h != scratch);\n> -      emit_move_insn (scratch, op2l);\n> -      op2l = scratch;\n> -    }\n> -\n> -  emit_insn (gen_addsi3_flags (op0l, op1l, op2l));\n> -\n> -  if (rtx_equal_p (op0h, op1h))\n> -    ;\n> -  else if (rtx_equal_p (op0h, op2h))\n> -    x = op1h, op1h = op2h, op2h = x;\n> -  else\n> -    {\n> -      emit_move_insn (op0h, op1h);\n> -      op1h = op0h;\n> -    }\n> -  emit_insn (gen_adc_internal (op0h, op1h, op2h));\n> -  DONE;\n> -})\n> -\n>  (define_insn_and_split \"andsi3\"\n>    [(set (match_operand:SI         0 \"register_operand\"  \"=r,r,r,r,r,r,r,r,r\")\n>  \t(and:SI (match_operand:SI 1 \"register_operand\"  \"%0,0,0,0,0,0,r,r,0\")\n> @@ -1694,45 +1676,18 @@\n>     (set_attr \"length\"  \"3,6\")]\n>  )\n>  \n> -(define_expand \"subdi3\"\n> -  [(set (match_operand:DI           0 \"register_operand\")\n> -\t(minus:DI (match_operand:DI 1 \"register_operand\")\n> -\t\t  (match_operand:DI 2 \"register_operand\")))]\n> -  \"\"\n> -{\n> -  rtx op0l, op0h, op1l, op1h, op2l, op2h;\n> -\n> -  op0l = gen_lowpart (SImode, operands[0]);\n> -  op1l = gen_lowpart (SImode, operands[1]);\n> -  op2l = gen_lowpart (SImode, operands[2]);\n> -  op0h = gen_highpart (SImode, operands[0]);\n> -  op1h = gen_highpart (SImode, operands[1]);\n> -  op2h = gen_highpart_mode (SImode, DImode, operands[2]);\n> -\n> -  emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));\n> -  DONE;\n> -})\n> -\n> -(define_insn_and_split \"subdi3_internal\"\n> -  [(set (match_operand:SI          0 \"register_operand\"   \"=&r,&r\")\n> -\t(minus:SI (match_operand:SI 2 \"register_operand\"  \"  0, r\")\n> -\t\t  (match_operand:SI 3 \"rx_compare_operand\" \"rQ, r\")))\n> -   (set (match_operand:SI          1 \"register_operand\"   \"= r, r\")\n> -\t(minus:SI\n> -\t  (minus:SI\n> -\t    (match_operand:SI      4 \"register_operand\"   \"  1, 1\")\n> -\t    (match_operand:SI      5 \"rx_compare_operand\" \" rQ,rQ\"))\n> -\t  (gtu:SI (match_dup 3) (match_dup 2))))\n> +(define_insn \"subdi3\"\n> +  [(set (match_operand:DI 0 \"register_operand\" \"=r,r\")\n> +\t(minus:DI (match_operand:DI 1 \"register_operand\"  \"0,0\")\n> +\t\t (match_operand:DI 2 \"rx_source_operand\"  \"r,Q\")))\n>     (clobber (reg:CC CC_REG))]\n>    \"\"\n> -  \"#\"\n> -  \"reload_completed\"\n> -  [(const_int 0)]\n> -{\n> -  emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3]));\n> -  emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5]));\n> -  DONE;\n> -})\n> +  {\n> +    return \"sub\\t%L2, %L0\\n\\tsbb\\t%H2, %H0\";\n> +  }\n> +  [(set_attr \"length\" \"6\")\n> +   (set_attr \"timings\" \"22\")]\n> +)\n>  \n>  (define_insn_and_split \"xorsi3\"\n>    [(set (match_operand:SI         0 \"register_operand\" \"=r,r,r,r,r,r\")\n> @@ -1936,6 +1891,7 @@\n>    [(set_attr \"timings\" \"33\")\n>     (set_attr \"length\"  \"5\")] ;; This length is corrected in rx_adjust_insn_length\n>  )\n> +\n>  \f\n>  ;; Floating Point Instructions\n>  \n> @@ -2870,20 +2826,33 @@\n>    \"\"\n>  )\n>  \n> -(define_insn \"movdi\"\n> -  [(set (match_operand:DI 0 \"nonimmediate_operand\" \"=rm\")\n> -        (match_operand:DI 1 \"general_operand\"      \"rmi\"))]\n> -  \"TARGET_ENABLE_LRA\"\n> -  { return rx_gen_move_template (operands, false); }\n> -  [(set_attr \"length\" \"16\")\n> -   (set_attr \"timings\" \"22\")]\n> +;; RX does not allow addition without destroying CC.\n> +;; As an alternative to addptrsi3, we define addsi3, which hides changes to CC.\n> +(define_insn_and_split \"*addsi3_lra\"\n> +  [(set (match_operand:SI 0 \"register_operand\" \"=r,r\")\n> +        (plus:SI (match_operand:SI 1 \"register_operand\" \"0,r\")\n> +                 (match_operand:SI 2 \"rx_source_operand\" \"ri,ri\")))]\n> +  \"lra_in_progress || reload_completed\"\n> +  \"#\"\n> +  \"&& reload_completed\"\n> +  [(parallel [\n> +     (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))\n> +     (clobber (reg:CC 16))\n> +   ])]\n>  )\n>  \n> -(define_insn \"movdf\"\n> -  [(set (match_operand:DF 0 \"nonimmediate_operand\" \"=rm\")\n> -        (match_operand:DF 1 \"general_operand\"      \"rmi\"))]\n> -  \"TARGET_ENABLE_LRA\"\n> -  { return rx_gen_move_template (operands, false); }\n> -  [(set_attr \"length\" \"16\")\n> -   (set_attr \"timings\" \"22\")]\n> +(define_insn_and_split \"*ashlsi3_lra\"\n> +  [(set (match_operand:SI 0 \"register_operand\" \"=r,r,r\")\n> +        (ashift:SI (match_operand:SI 1 \"register_operand\" \"%0,0,r\")\n> +                   (match_operand:SI 2 \"rx_shift_operand\" \"r,i,i\")))]\n> +  \"lra_in_progress || reload_completed\"\n> +  \"@\n> +   shll\\t%2, %0\n> +   shll\\t%2, %0\n> +   shll\\t%2, %1, %0\"\n> +  \"&& reload_completed\"\n> +  [(parallel [\n> +     (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))\n> +     (clobber (reg:CC CC_REG))\n> +   ])]\n>  )\n> diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt\n> index 5caad487389..0e4c9872356 100644\n> --- a/gcc/config/rx/rx.opt\n> +++ b/gcc/config/rx/rx.opt\n> @@ -128,12 +128,6 @@ Enable the use the standard RX ABI where all stacked function arguments are natu\n>  \n>  ;---------------------------------------------------\n>  \n> -mlra\n> -Target Mask(ENABLE_LRA)\n> -Enable the use of the LRA register allocator.\n> -\n> -;---------------------------------------------------\n> -\n>  mallow-string-insns\n>  Target Var(rx_allow_string_insns) Init(1)\n>  Enables or disables the use of the SMOVF, SMOVB, SMOVU, SUNTIL, SWHILE and RMPA instructions.  Enabled by default.","headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gentoo.org","sourceware.org; spf=pass smtp.mailfrom=gentoo.org","server2.sourceware.org;\n arc=none smtp.remote-ip=140.211.166.183"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g2w8w0D8nz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 26 Apr 2026 02:22:38 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id CBDE04BB1C3E\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 25 Apr 2026 16:22:36 +0000 (GMT)","from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183])\n by sourceware.org (Postfix) with ESMTP id 98C624B99F57\n for <gcc-patches@gcc.gnu.org>; Sat, 25 Apr 2026 16:22:05 +0000 (GMT)","from mop.sam.mop\n (2.8.3.0.0.0.0.0.0.0.0.0.0.0.0.0.a.5.c.d.c.d.9.1.0.b.8.0.1.0.0.2.ip6.arpa\n [IPv6:2001:8b0:19dc:dc5a::382])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n (No client certificate requested) (Authenticated sender: sam)\n by smtp.gentoo.org (Postfix) with ESMTPSA id C10913420D6;\n Sat, 25 Apr 2026 16:22:03 +0000 (UTC)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org CBDE04BB1C3E","OpenDKIM Filter v2.11.0 sourceware.org 98C624B99F57"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 98C624B99F57","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 98C624B99F57","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777134125; cv=none;\n b=Ts82fz4PrDh5sTENIeS8x8tJ7Oliz39AzpxmlmdYI5aq7Jyjv9U3lT9+G4YvgVGMtxZVggTpq6MSxP3yqYN8uV2rpjPU8AG3JlIlixNFhvB/oL0jEVpVoUm5Vouqo58gs0eT66udFn8N9VjIaIdGY/u4q06zKB28x9EWfTFtUyA=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777134125; c=relaxed/simple;\n bh=h62KrlgIUr3UwRFzOdDu3yaEqt3AqtN5dQUQF33QifU=;\n h=From:To:Subject:Date:Message-ID:MIME-Version;\n b=wmSKi9Uj80PSFEDSrJlCAIwfsI71PPRY1RKWwKiPJ6X6fiaeVQDjcb8XyoUKt4mi3Zl7CxK+WcGiFfbpCjfZ1ZGLApRsQi5sSD86XHr/gkGKbxpLUeE26RZItxXFPMFLFaAIGDHy9Hqwa6+CH8+iQhjHka1HKN9BfTmqQx/HVJk=","ARC-Authentication-Results":"i=1; server2.sourceware.org","From":"Sam James <sam@gentoo.org>","To":"Yoshinori Sato <yoshinori.sato@nifty.com>","Cc":"gcc-patches@gcc.gnu.org, Nick Clifton <nickc@redhat.com>","Subject":"Re: [RFC PATCH v3] RX: enable LRA is default","In-Reply-To":"<20260425161006.3588504-1-yoshinori.sato@nifty.com>","Organization":"Gentoo","References":"<20260425161006.3588504-1-yoshinori.sato@nifty.com>","User-Agent":"mu4e 1.14.0; emacs 31.0.50","Date":"Sat, 25 Apr 2026 17:21:59 +0100","Message-ID":"<87mryr80yg.fsf@gentoo.org>","MIME-Version":"1.0","Content-Type":"multipart/signed; boundary=\"=-=-=\";\n micalg=pgp-sha512; protocol=\"application/pgp-signature\"","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"}}]