diff mbox series

[avr] Reorder avr.cc so it requires less forward declarations.

Message ID 069c296c-e767-47dd-a5e1-c1891a0e08bf@gjlay.de
State New
Headers show
Series [avr] Reorder avr.cc so it requires less forward declarations. | expand

Commit Message

Georg-Johann Lay Sept. 10, 2024, 4:33 p.m. UTC
This patch reorders functions in avr.cc so that less
forward declarations are needed.

Johann

--

AVR: avr.cc - Reorder functions to require less forward decls.

gcc/
	* config/avr/avr.cc (avr_init_machine_status): Move code to...
	(avr_option_override) <init_machine_status>: ...lambda.
	(avr_insn_has_reg_unused_note_p): Move up.
	(_reg_unused_after, reg_unused_after): Move up.
	(output_reload_in_const): Move up.
diff mbox series

Patch

    AVR: avr.cc - Reorder functions to require less forward decls.
    
    gcc/
            * config/avr/avr.cc (avr_init_machine_status): Move code to...
            (avr_option_override) <init_machine_status>: ...lambda.
            (avr_insn_has_reg_unused_note_p): Move up.
            (_reg_unused_after, reg_unused_after): Move up.
            (output_reload_in_const): Move up.

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 1f809d8e1e3..f15d579ab1d 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -153,16 +153,6 @@  static const char *out_movqi_mr_r (rtx_insn *, rtx[], int *);
 static const char *out_movhi_mr_r (rtx_insn *, rtx[], int *);
 static const char *out_movsi_mr_r (rtx_insn *, rtx[], int *);
 
-static int get_sequence_length (rtx_insn *insns);
-static int sequent_regs_live (void);
-static const char *ptrreg_to_str (int);
-static int avr_num_arg_regs (machine_mode, const_tree);
-static int avr_operand_rtx_cost (rtx, machine_mode, enum rtx_code,
-				 int, bool);
-static void output_reload_in_const (rtx *, rtx, int *, bool);
-static struct machine_function *avr_init_machine_status (void);
-static bool _reg_unused_after (rtx_insn *insn, rtx reg, bool look_at_insn);
-
 
 /* Prototypes for hook implementors if needed before their implementation.  */
 
@@ -456,7 +446,10 @@  avr_option_override (void)
   avr_addr.sp_l = 0x3D + avr_arch->sfr_offset;
   avr_addr.sp_h = avr_addr.sp_l + 1;
 
-  init_machine_status = avr_init_machine_status;
+  init_machine_status = []()
+  {
+    return ggc_cleared_alloc<machine_function> ();
+  };
 
   avr_log_set_avr_log();
 
@@ -473,14 +466,6 @@  avr_option_override (void)
   }
 }
 
-/* Function to set up the backend function structure.  */
-
-static struct machine_function *
-avr_init_machine_status (void)
-{
-  return ggc_cleared_alloc<machine_function> ();
-}
-
 
 /* Implement `INIT_EXPANDERS'.  */
 /* The function works like a singleton.  */
@@ -1179,7 +1164,7 @@  sequent_regs_live (void)
 
 /* Obtain the length sequence of insns.  */
 
-int
+static int
 get_sequence_length (rtx_insn *insns)
 {
   int length = 0;
@@ -2933,6 +2918,7 @@  avr_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
   cfun->machine->sibcall_fails = 0;
 }
 
+
 /* Returns the number of registers to allocate for a function argument.  */
 
 static int
@@ -3099,6 +3085,152 @@  avr_xload_libgcc_p (machine_mode mode)
 }
 
 
+/* Return true when INSN has a REG_UNUSED note for hard reg REG.
+   rtlanal.cc::find_reg_note() uses == to compare XEXP (link, 0)
+   therefore use a custom function.  */
+
+static bool
+avr_insn_has_reg_unused_note_p (rtx_insn *insn, rtx reg)
+{
+  for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
+    if (REG_NOTE_KIND (link) == REG_UNUSED
+	&& REG_P (XEXP (link, 0))
+	&& REGNO (reg) >= REGNO (XEXP (link, 0))
+	&& END_REGNO (reg) <= END_REGNO (XEXP (link, 0)))
+      return true;
+
+  return false;
+}
+
+
+/* A helper for the next function.
+   Return nonzero if REG is not used after INSN.
+   We assume REG is a reload reg, and therefore does
+   not live past labels.  It may live past calls or jumps though.  */
+
+static bool
+_reg_unused_after (rtx_insn *insn, rtx reg, bool look_at_insn)
+{
+  if (look_at_insn)
+    {
+      /* If the reg is set by this instruction, then it is safe for our
+	 case.  Disregard the case where this is a store to memory, since
+	 we are checking a register used in the store address.  */
+      rtx set = single_set (insn);
+      if (set && !MEM_P (SET_DEST (set))
+	  && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+	return 1;
+
+      /* This case occurs when fuse-add introduced a POST_INC addressing,
+	 but the address register is unused after.  */
+      if (set)
+	{
+	  rtx mem = MEM_P (SET_SRC (set)) ? SET_SRC (set) : SET_DEST (set);
+	  if (MEM_P (mem)
+	      && reg_overlap_mentioned_p (reg, XEXP (mem, 0))
+	      && avr_insn_has_reg_unused_note_p (insn, reg))
+	    return 1;
+	}
+    }
+
+  while ((insn = NEXT_INSN (insn)))
+    {
+      rtx set;
+      enum rtx_code code = GET_CODE (insn);
+
+#if 0
+      /* If this is a label that existed before reload, then the register
+	 if dead here.  However, if this is a label added by reorg, then
+	 the register may still be live here.  We can't tell the difference,
+	 so we just ignore labels completely.  */
+      if (code == CODE_LABEL)
+	return 1;
+      /* else */
+#endif
+
+      if (!INSN_P (insn))
+	continue;
+
+      if (code == JUMP_INSN)
+	return 0;
+
+      /* If this is a sequence, we must handle them all at once.
+	 We could have for instance a call that sets the target register,
+	 and an insn in a delay slot that uses the register.  In this case,
+	 we must return 0.  */
+      else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+	{
+	  rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
+	  int retval = 0;
+
+	  for (int i = 0; i < seq->len (); i++)
+	    {
+	      rtx_insn *this_insn = seq->insn (i);
+	      rtx set = single_set (this_insn);
+
+	      if (CALL_P (this_insn))
+		code = CALL_INSN;
+	      else if (JUMP_P (this_insn))
+		{
+		  if (INSN_ANNULLED_BRANCH_P (this_insn))
+		    return 0;
+		  code = JUMP_INSN;
+		}
+
+	      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+		return 0;
+	      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+		{
+		  if (!MEM_P (SET_DEST (set)))
+		    retval = 1;
+		  else
+		    return 0;
+		}
+	      if (set == 0
+		  && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
+		return 0;
+	    }
+	  if (retval == 1)
+	    return 1;
+	  else if (code == JUMP_INSN)
+	    return 0;
+	}
+
+      if (code == CALL_INSN)
+	{
+	  rtx tem;
+	  for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+	    if (GET_CODE (XEXP (tem, 0)) == USE
+		&& REG_P (XEXP (XEXP (tem, 0), 0))
+		&& reg_overlap_mentioned_p (reg, XEXP (XEXP (tem, 0), 0)))
+	      return 0;
+	  if (call_used_or_fixed_reg_p (REGNO (reg)))
+	    return 1;
+	}
+
+      set = single_set (insn);
+
+      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+	return 0;
+      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+	return !MEM_P (SET_DEST (set));
+      if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+	return 0;
+    }
+  return 1;
+}
+
+
+/* Return nonzero if register REG dead after INSN.  */
+
+int
+reg_unused_after (rtx_insn *insn, rtx reg)
+{
+  return (dead_or_set_p (insn, reg)
+	  || (REG_P (reg) && _reg_unused_after (insn, reg, true)));
+}
+
+
 /* Fixme: This is a hack because secondary reloads don't works as expected.
 
    Find an unused d-register to be used as scratch in INSN.
@@ -3444,6 +3576,232 @@  avr_out_xload (rtx_insn * /*insn*/, rtx *op, int *plen)
 }
 
 
+/* A helper for `output_reload_insisf' and `output_reload_inhi'.  */
+/* Set register OP[0] to compile-time constant OP[1].
+   CLOBBER_REG is a QI clobber register or NULL_RTX.
+   LEN == NULL: output instructions.
+   LEN != NULL: set *LEN to the length of the instruction sequence
+		(in words) printed with LEN = NULL.
+   If CLEAR_P is true, OP[0] had been cleard to Zero already.
+   If CLEAR_P is false, nothing is known about OP[0].
+
+   The effect on cc0 is as follows:
+
+   Load 0 to any register except ZERO_REG : NONE
+   Load ld register with any value        : NONE
+   Anything else:                         : CLOBBER  */
+
+static void
+output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
+{
+  rtx src = op[1];
+  rtx dest = op[0];
+  rtx xval, xdest[4];
+  int ival[4];
+  int clobber_val = 1234;
+  bool cooked_clobber_p = false;
+  bool set_p = false;
+  machine_mode mode = GET_MODE (dest);
+  int n_bytes = GET_MODE_SIZE (mode);
+
+  gcc_assert (REG_P (dest)
+	      && CONSTANT_P (src));
+
+  if (len)
+    *len = 0;
+
+  /* (REG:SI 14) is special: It's neither in LD_REGS nor in NO_LD_REGS
+     but has some subregs that are in LD_REGS.  Use the MSB (REG:QI 17).  */
+
+  if (REGNO (dest) < REG_16
+      && REGNO (dest) + GET_MODE_SIZE (mode) > REG_16)
+    {
+      clobber_reg = all_regs_rtx[REGNO (dest) + n_bytes - 1];
+    }
+
+  /* We might need a clobber reg but don't have one.  Look at the value to
+     be loaded more closely.  A clobber is only needed if it is a symbol
+     or contains a byte that is neither 0, -1 or a power of 2.  */
+
+  if (NULL_RTX == clobber_reg
+      && !test_hard_reg_class (LD_REGS, dest)
+      && (! (CONST_INT_P (src) || CONST_FIXED_P (src) || CONST_DOUBLE_P (src))
+	  || !avr_popcount_each_byte (src, n_bytes,
+				      (1 << 0) | (1 << 1) | (1 << 8))))
+    {
+      /* We have no clobber register but need one.  Cook one up.
+	 That's cheaper than loading from constant pool.  */
+
+      cooked_clobber_p = true;
+      clobber_reg = all_regs_rtx[REG_Z + 1];
+      avr_asm_len ("mov __tmp_reg__,%0", &clobber_reg, len, 1);
+    }
+
+  /* Now start filling DEST from LSB to MSB.  */
+
+  for (int n = 0; n < n_bytes; n++)
+    {
+      bool done_byte = false;
+      rtx xop[3];
+
+      /* Crop the n-th destination byte.  */
+
+      xdest[n] = simplify_gen_subreg (QImode, dest, mode, n);
+      int ldreg_p = test_hard_reg_class (LD_REGS, xdest[n]);
+
+      if (!CONST_INT_P (src)
+	  && !CONST_FIXED_P (src)
+	  && !CONST_DOUBLE_P (src))
+	{
+	  static const char *const asm_code[][2] =
+	    {
+	      { "ldi %2,lo8(%1)"  CR_TAB "mov %0,%2",    "ldi %0,lo8(%1)"  },
+	      { "ldi %2,hi8(%1)"  CR_TAB "mov %0,%2",    "ldi %0,hi8(%1)"  },
+	      { "ldi %2,hlo8(%1)" CR_TAB "mov %0,%2",    "ldi %0,hlo8(%1)" },
+	      { "ldi %2,hhi8(%1)" CR_TAB "mov %0,%2",    "ldi %0,hhi8(%1)" }
+	    };
+
+	  xop[0] = xdest[n];
+	  xop[1] = src;
+	  xop[2] = clobber_reg;
+
+	  avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2);
+
+	  continue;
+	}
+
+      /* Crop the n-th source byte.  */
+
+      xval = simplify_gen_subreg (QImode, src, mode, n);
+      ival[n] = INTVAL (xval);
+
+      /* Look if we can reuse the low word by means of MOVW.  */
+
+      if (n == 2
+	  && n_bytes >= 4
+	  && AVR_HAVE_MOVW)
+	{
+	  rtx lo16 = simplify_gen_subreg (HImode, src, mode, 0);
+	  rtx hi16 = simplify_gen_subreg (HImode, src, mode, 2);
+
+	  if (INTVAL (lo16) == INTVAL (hi16))
+	    {
+	      if (INTVAL (lo16) != 0 || !clear_p)
+		avr_asm_len ("movw %C0,%A0", &op[0], len, 1);
+
+	      break;
+	    }
+	}
+
+      /* Don't use CLR so that cc0 is set as expected.  */
+
+      if (ival[n] == 0)
+	{
+	  if (!clear_p)
+	    avr_asm_len (ldreg_p ? "ldi %0,0"
+			 : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0"
+			 : "mov %0,__zero_reg__",
+			 &xdest[n], len, 1);
+	  continue;
+	}
+
+      if (clobber_val == ival[n]
+	  && REGNO (clobber_reg) == REGNO (xdest[n]))
+	{
+	  continue;
+	}
+
+      /* LD_REGS can use LDI to move a constant value */
+
+      if (ldreg_p)
+	{
+	  xop[0] = xdest[n];
+	  xop[1] = xval;
+	  avr_asm_len ("ldi %0,lo8(%1)", xop, len, 1);
+	  continue;
+	}
+
+      /* Try to reuse value already loaded in some lower byte. */
+
+      for (int j = 0; j < n; j++)
+	if (ival[j] == ival[n])
+	  {
+	    xop[0] = xdest[n];
+	    xop[1] = xdest[j];
+
+	    avr_asm_len ("mov %0,%1", xop, len, 1);
+	    done_byte = true;
+	    break;
+	  }
+
+      if (done_byte)
+	continue;
+
+      /* Need no clobber reg for -1: Use CLR/DEC */
+
+      if (ival[n] == -1)
+	{
+	  if (!clear_p)
+	    avr_asm_len ("clr %0", &xdest[n], len, 1);
+
+	  avr_asm_len ("dec %0", &xdest[n], len, 1);
+	  continue;
+	}
+      else if (ival[n] == 1)
+	{
+	  if (!clear_p)
+	    avr_asm_len ("clr %0", &xdest[n], len, 1);
+
+	  avr_asm_len ("inc %0", &xdest[n], len, 1);
+	  continue;
+	}
+
+      /* Use T flag or INC to manage powers of 2 if we have
+	 no clobber reg.  */
+
+      if (NULL_RTX == clobber_reg
+	  && single_one_operand (xval, QImode))
+	{
+	  xop[0] = xdest[n];
+	  xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode)));
+
+	  gcc_assert (constm1_rtx != xop[1]);
+
+	  if (!set_p)
+	    {
+	      set_p = true;
+	      avr_asm_len ("set", xop, len, 1);
+	    }
+
+	  if (!clear_p)
+	    avr_asm_len ("clr %0", xop, len, 1);
+
+	  avr_asm_len ("bld %0,%1", xop, len, 1);
+	  continue;
+	}
+
+      /* We actually need the LD_REGS clobber reg.  */
+
+      gcc_assert (NULL_RTX != clobber_reg);
+
+      xop[0] = xdest[n];
+      xop[1] = xval;
+      xop[2] = clobber_reg;
+      clobber_val = ival[n];
+
+      avr_asm_len ("ldi %2,lo8(%1)" CR_TAB
+		   "mov %0,%2", xop, len, 2);
+    }
+
+  /* If we cooked up a clobber reg above, restore it.  */
+
+  if (cooked_clobber_p)
+    {
+      avr_asm_len ("mov %0,__tmp_reg__", &clobber_reg, len, 1);
+    }
+}
+
+
 const char *
 output_movqi (rtx_insn *insn, rtx operands[], int *plen)
 {
@@ -9955,151 +10313,6 @@  avr_adjust_insn_length (rtx_insn *insn, int len)
 }
 
 
-/* Return true when INSN has a REG_UNUSED note for hard reg REG.
-   rtlanal.cc::find_reg_note() uses == to compare XEXP (link, 0)
-   therefore use a custom function.  */
-
-static bool
-avr_insn_has_reg_unused_note_p (rtx_insn *insn, rtx reg)
-{
-  for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1))
-    if (REG_NOTE_KIND (link) == REG_UNUSED
-	&& REG_P (XEXP (link, 0))
-	&& REGNO (reg) >= REGNO (XEXP (link, 0))
-	&& END_REGNO (reg) <= END_REGNO (XEXP (link, 0)))
-      return true;
-
-  return false;
-}
-
-
-/* Return nonzero if register REG dead after INSN.  */
-
-int
-reg_unused_after (rtx_insn *insn, rtx reg)
-{
-  return (dead_or_set_p (insn, reg)
-	  || (REG_P (reg) && _reg_unused_after (insn, reg, true)));
-}
-
-/* A helper for the previous function.
-   Return nonzero if REG is not used after INSN.
-   We assume REG is a reload reg, and therefore does
-   not live past labels.  It may live past calls or jumps though.  */
-
-bool
-_reg_unused_after (rtx_insn *insn, rtx reg, bool look_at_insn)
-{
-  if (look_at_insn)
-    {
-      /* If the reg is set by this instruction, then it is safe for our
-	 case.  Disregard the case where this is a store to memory, since
-	 we are checking a register used in the store address.  */
-      rtx set = single_set (insn);
-      if (set && !MEM_P (SET_DEST (set))
-	  && reg_overlap_mentioned_p (reg, SET_DEST (set)))
-	return 1;
-
-      /* This case occurs when fuse-add introduced a POST_INC addressing,
-	 but the address register is unused after.  */
-      if (set)
-	{
-	  rtx mem = MEM_P (SET_SRC (set)) ? SET_SRC (set) : SET_DEST (set);
-	  if (MEM_P (mem)
-	      && reg_overlap_mentioned_p (reg, XEXP (mem, 0))
-	      && avr_insn_has_reg_unused_note_p (insn, reg))
-	    return 1;
-	}
-    }
-
-  while ((insn = NEXT_INSN (insn)))
-    {
-      rtx set;
-      enum rtx_code code = GET_CODE (insn);
-
-#if 0
-      /* If this is a label that existed before reload, then the register
-	 if dead here.  However, if this is a label added by reorg, then
-	 the register may still be live here.  We can't tell the difference,
-	 so we just ignore labels completely.  */
-      if (code == CODE_LABEL)
-	return 1;
-      /* else */
-#endif
-
-      if (!INSN_P (insn))
-	continue;
-
-      if (code == JUMP_INSN)
-	return 0;
-
-      /* If this is a sequence, we must handle them all at once.
-	 We could have for instance a call that sets the target register,
-	 and an insn in a delay slot that uses the register.  In this case,
-	 we must return 0.  */
-      else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
-	{
-	  rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
-	  int retval = 0;
-
-	  for (int i = 0; i < seq->len (); i++)
-	    {
-	      rtx_insn *this_insn = seq->insn (i);
-	      rtx set = single_set (this_insn);
-
-	      if (CALL_P (this_insn))
-		code = CALL_INSN;
-	      else if (JUMP_P (this_insn))
-		{
-		  if (INSN_ANNULLED_BRANCH_P (this_insn))
-		    return 0;
-		  code = JUMP_INSN;
-		}
-
-	      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
-		return 0;
-	      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
-		{
-		  if (!MEM_P (SET_DEST (set)))
-		    retval = 1;
-		  else
-		    return 0;
-		}
-	      if (set == 0
-		  && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
-		return 0;
-	    }
-	  if (retval == 1)
-	    return 1;
-	  else if (code == JUMP_INSN)
-	    return 0;
-	}
-
-      if (code == CALL_INSN)
-	{
-	  rtx tem;
-	  for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-	    if (GET_CODE (XEXP (tem, 0)) == USE
-		&& REG_P (XEXP (XEXP (tem, 0), 0))
-		&& reg_overlap_mentioned_p (reg, XEXP (XEXP (tem, 0), 0)))
-	      return 0;
-	  if (call_used_or_fixed_reg_p (REGNO (reg)))
-	    return 1;
-	}
-
-      set = single_set (insn);
-
-      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
-	return 0;
-      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
-	return !MEM_P (SET_DEST (set));
-      if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
-	return 0;
-    }
-  return 1;
-}
-
-
 /* Implement `TARGET_ASM_INTEGER'.  */
 /* Target hook for assembling integer objects.  The AVR version needs
    special handling for references to certain labels.  */
@@ -11468,7 +11681,7 @@  avr_cbranch_cost (rtx x)
 }
 
 
-/* Mutually recursive subroutine of avr_rtx_cost for calculating the
+/* Mutually recursive subroutine of `avr_rtx_cost' for calculating the
    cost of an RTX operand given its context.  X is the rtx of the
    operand, MODE is its mode, and OUTER is the rtx_code of this
    operand's parent operator.  */
@@ -12938,232 +13151,6 @@  avr_regno_mode_code_ok_for_base_p (int regno, machine_mode /*mode*/,
 }
 
 
-/* A helper for `output_reload_insisf' and `output_reload_inhi'.  */
-/* Set 32-bit register OP[0] to compile-time constant OP[1].
-   CLOBBER_REG is a QI clobber register or NULL_RTX.
-   LEN == NULL: output instructions.
-   LEN != NULL: set *LEN to the length of the instruction sequence
-		(in words) printed with LEN = NULL.
-   If CLEAR_P is true, OP[0] had been cleard to Zero already.
-   If CLEAR_P is false, nothing is known about OP[0].
-
-   The effect on cc0 is as follows:
-
-   Load 0 to any register except ZERO_REG : NONE
-   Load ld register with any value        : NONE
-   Anything else:                         : CLOBBER  */
-
-static void
-output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
-{
-  rtx src = op[1];
-  rtx dest = op[0];
-  rtx xval, xdest[4];
-  int ival[4];
-  int clobber_val = 1234;
-  bool cooked_clobber_p = false;
-  bool set_p = false;
-  machine_mode mode = GET_MODE (dest);
-  int n_bytes = GET_MODE_SIZE (mode);
-
-  gcc_assert (REG_P (dest)
-	      && CONSTANT_P (src));
-
-  if (len)
-    *len = 0;
-
-  /* (REG:SI 14) is special: It's neither in LD_REGS nor in NO_LD_REGS
-     but has some subregs that are in LD_REGS.  Use the MSB (REG:QI 17).  */
-
-  if (REGNO (dest) < REG_16
-      && REGNO (dest) + GET_MODE_SIZE (mode) > REG_16)
-    {
-      clobber_reg = all_regs_rtx[REGNO (dest) + n_bytes - 1];
-    }
-
-  /* We might need a clobber reg but don't have one.  Look at the value to
-     be loaded more closely.  A clobber is only needed if it is a symbol
-     or contains a byte that is neither 0, -1 or a power of 2.  */
-
-  if (NULL_RTX == clobber_reg
-      && !test_hard_reg_class (LD_REGS, dest)
-      && (! (CONST_INT_P (src) || CONST_FIXED_P (src) || CONST_DOUBLE_P (src))
-	  || !avr_popcount_each_byte (src, n_bytes,
-				      (1 << 0) | (1 << 1) | (1 << 8))))
-    {
-      /* We have no clobber register but need one.  Cook one up.
-	 That's cheaper than loading from constant pool.  */
-
-      cooked_clobber_p = true;
-      clobber_reg = all_regs_rtx[REG_Z + 1];
-      avr_asm_len ("mov __tmp_reg__,%0", &clobber_reg, len, 1);
-    }
-
-  /* Now start filling DEST from LSB to MSB.  */
-
-  for (int n = 0; n < n_bytes; n++)
-    {
-      bool done_byte = false;
-      rtx xop[3];
-
-      /* Crop the n-th destination byte.  */
-
-      xdest[n] = simplify_gen_subreg (QImode, dest, mode, n);
-      int ldreg_p = test_hard_reg_class (LD_REGS, xdest[n]);
-
-      if (!CONST_INT_P (src)
-	  && !CONST_FIXED_P (src)
-	  && !CONST_DOUBLE_P (src))
-	{
-	  static const char *const asm_code[][2] =
-	    {
-	      { "ldi %2,lo8(%1)"  CR_TAB "mov %0,%2",    "ldi %0,lo8(%1)"  },
-	      { "ldi %2,hi8(%1)"  CR_TAB "mov %0,%2",    "ldi %0,hi8(%1)"  },
-	      { "ldi %2,hlo8(%1)" CR_TAB "mov %0,%2",    "ldi %0,hlo8(%1)" },
-	      { "ldi %2,hhi8(%1)" CR_TAB "mov %0,%2",    "ldi %0,hhi8(%1)" }
-	    };
-
-	  xop[0] = xdest[n];
-	  xop[1] = src;
-	  xop[2] = clobber_reg;
-
-	  avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2);
-
-	  continue;
-	}
-
-      /* Crop the n-th source byte.  */
-
-      xval = simplify_gen_subreg (QImode, src, mode, n);
-      ival[n] = INTVAL (xval);
-
-      /* Look if we can reuse the low word by means of MOVW.  */
-
-      if (n == 2
-	  && n_bytes >= 4
-	  && AVR_HAVE_MOVW)
-	{
-	  rtx lo16 = simplify_gen_subreg (HImode, src, mode, 0);
-	  rtx hi16 = simplify_gen_subreg (HImode, src, mode, 2);
-
-	  if (INTVAL (lo16) == INTVAL (hi16))
-	    {
-	      if (INTVAL (lo16) != 0 || !clear_p)
-		avr_asm_len ("movw %C0,%A0", &op[0], len, 1);
-
-	      break;
-	    }
-	}
-
-      /* Don't use CLR so that cc0 is set as expected.  */
-
-      if (ival[n] == 0)
-	{
-	  if (!clear_p)
-	    avr_asm_len (ldreg_p ? "ldi %0,0"
-			 : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0"
-			 : "mov %0,__zero_reg__",
-			 &xdest[n], len, 1);
-	  continue;
-	}
-
-      if (clobber_val == ival[n]
-	  && REGNO (clobber_reg) == REGNO (xdest[n]))
-	{
-	  continue;
-	}
-
-      /* LD_REGS can use LDI to move a constant value */
-
-      if (ldreg_p)
-	{
-	  xop[0] = xdest[n];
-	  xop[1] = xval;
-	  avr_asm_len ("ldi %0,lo8(%1)", xop, len, 1);
-	  continue;
-	}
-
-      /* Try to reuse value already loaded in some lower byte. */
-
-      for (int j = 0; j < n; j++)
-	if (ival[j] == ival[n])
-	  {
-	    xop[0] = xdest[n];
-	    xop[1] = xdest[j];
-
-	    avr_asm_len ("mov %0,%1", xop, len, 1);
-	    done_byte = true;
-	    break;
-	  }
-
-      if (done_byte)
-	continue;
-
-      /* Need no clobber reg for -1: Use CLR/DEC */
-
-      if (ival[n] == -1)
-	{
-	  if (!clear_p)
-	    avr_asm_len ("clr %0", &xdest[n], len, 1);
-
-	  avr_asm_len ("dec %0", &xdest[n], len, 1);
-	  continue;
-	}
-      else if (ival[n] == 1)
-	{
-	  if (!clear_p)
-	    avr_asm_len ("clr %0", &xdest[n], len, 1);
-
-	  avr_asm_len ("inc %0", &xdest[n], len, 1);
-	  continue;
-	}
-
-      /* Use T flag or INC to manage powers of 2 if we have
-	 no clobber reg.  */
-
-      if (NULL_RTX == clobber_reg
-	  && single_one_operand (xval, QImode))
-	{
-	  xop[0] = xdest[n];
-	  xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode)));
-
-	  gcc_assert (constm1_rtx != xop[1]);
-
-	  if (!set_p)
-	    {
-	      set_p = true;
-	      avr_asm_len ("set", xop, len, 1);
-	    }
-
-	  if (!clear_p)
-	    avr_asm_len ("clr %0", xop, len, 1);
-
-	  avr_asm_len ("bld %0,%1", xop, len, 1);
-	  continue;
-	}
-
-      /* We actually need the LD_REGS clobber reg.  */
-
-      gcc_assert (NULL_RTX != clobber_reg);
-
-      xop[0] = xdest[n];
-      xop[1] = xval;
-      xop[2] = clobber_reg;
-      clobber_val = ival[n];
-
-      avr_asm_len ("ldi %2,lo8(%1)" CR_TAB
-		   "mov %0,%2", xop, len, 2);
-    }
-
-  /* If we cooked up a clobber reg above, restore it.  */
-
-  if (cooked_clobber_p)
-    {
-      avr_asm_len ("mov %0,__tmp_reg__", &clobber_reg, len, 1);
-    }
-}
-
-
 /* Reload the constant OP[1] into the HI register OP[0].
    CLOBBER_REG is a QI clobber reg needed to move vast majority of consts
    into a NO_LD_REGS register.  If CLOBBER_REG is NULL_RTX we either don't