Пример #1
0
bool
nds32_expand_strlen (rtx result, rtx str,
		     rtx target_char, rtx align ATTRIBUTE_UNUSED)
{
  rtx base_reg, backup_base_reg;
  rtx ffb_result;
  rtx target_char_ptr, length;
  rtx loop_label, tmp;

  if (optimize_size || optimize < 3)
    return false;

  gcc_assert (MEM_P (str));
  gcc_assert (CONST_INT_P (target_char) || REG_P (target_char));

  base_reg = copy_to_mode_reg (SImode, XEXP (str, 0));
  loop_label = gen_label_rtx ();

  ffb_result = gen_reg_rtx (Pmode);
  tmp = gen_reg_rtx (SImode);
  backup_base_reg = gen_reg_rtx (SImode);

  /* Emit loop version of strlen.
       move  $backup_base, $base
     .Lloop:
       lmw.bim $tmp, [$base], $tmp, 0
       ffb   $ffb_result, $tmp, $target_char   ! is there $target_char?
       beqz  $ffb_result, .Lloop
       add   $last_char_ptr, $base, $ffb_result
       sub   $length, $last_char_ptr, $backup_base  */

  /* move  $backup_base, $base  */
  emit_move_insn (backup_base_reg, base_reg);

  /* .Lloop:  */
  emit_label (loop_label);
  /* lmw.bim $tmp, [$base], $tmp, 0  */
  emit_insn (gen_unaligned_load_update_base_w (base_reg, tmp, base_reg));

  /*  ffb   $ffb_result, $tmp, $target_char   ! is there $target_char?  */
  emit_insn (gen_unspec_ffb (ffb_result, tmp, target_char));

  /* beqz  $ffb_result, .Lloop  */
  emit_cmp_and_jump_insns (ffb_result, const0_rtx, EQ, NULL,
			   SImode, 1, loop_label);

  /* add   $target_char_ptr, $base, $ffb_result   */
  target_char_ptr = expand_binop (Pmode, add_optab, base_reg,
				ffb_result, NULL_RTX, 0, OPTAB_WIDEN);

  /* sub   $length, $target_char_ptr, $backup_base  */
  length = expand_binop (Pmode, sub_optab, target_char_ptr,
			 backup_base_reg, NULL_RTX, 0, OPTAB_WIDEN);

  emit_move_insn (result, length);

  return true;
}
Пример #2
0
static rtx
nds32_gen_dup_4_byte_to_word_value_aux (rtx value, rtx value4word)
{
  gcc_assert (GET_MODE (value) == QImode || CONST_INT_P (value));

  if (CONST_INT_P (value))
    {
      unsigned HOST_WIDE_INT val = UINTVAL (value) & GET_MODE_MASK(QImode);
      rtx new_val = gen_int_mode (val | (val << 8)
				  | (val << 16) | (val << 24), SImode);
      /* Just calculate at here if it's constant value.  */
      emit_move_insn (value4word, new_val);
    }
  else
    {
      if (NDS32_EXT_DSP_P ())
	{
	  /* ! prepare word
	     insb    $tmp, $value, 1         ! $tmp  <- 0x0000abab
	     pkbb16  $tmp6, $tmp2, $tmp2   ! $value4word  <- 0xabababab */
	  rtx tmp = gen_reg_rtx (SImode);

	  convert_move (tmp, value, true);

	  emit_insn (
	    gen_insvsi_internal (tmp, gen_int_mode (0x8, SImode), tmp));

	  emit_insn (gen_pkbbsi_1 (value4word, tmp, tmp));
	}
      else
	{
	  /* ! prepare word
	     andi    $tmp1, $value, 0xff       ! $tmp1  <- 0x000000ab
	     slli    $tmp2, $tmp1, 8           ! $tmp2  <- 0x0000ab00
	     or      $tmp3, $tmp1, $tmp2       ! $tmp3  <- 0x0000abab
	     slli    $tmp4, $tmp3, 16          ! $tmp4  <- 0xabab0000
	     or      $val4word, $tmp3, $tmp4   ! $value4word  <- 0xabababab  */

	  rtx tmp1, tmp2, tmp3, tmp4;
	  tmp1 = expand_binop (SImode, and_optab, value,
			       gen_int_mode (0xff, SImode),
			       NULL_RTX, 0, OPTAB_WIDEN);
	  tmp2 = expand_binop (SImode, ashl_optab, tmp1,
			       gen_int_mode (8, SImode),
			       NULL_RTX, 0, OPTAB_WIDEN);
	  tmp3 = expand_binop (SImode, ior_optab, tmp1, tmp2,
			       NULL_RTX, 0, OPTAB_WIDEN);
	  tmp4 = expand_binop (SImode, ashl_optab, tmp3,
			       gen_int_mode (16, SImode),
			       NULL_RTX, 0, OPTAB_WIDEN);

	  emit_insn (gen_iorsi3 (value4word, tmp3, tmp4));
	}
    }

  return value4word;
}
Пример #3
0
static rtx
emit_setmem_doubleword_loop (rtx itr, rtx size, rtx value)
{
  rtx word_mode_label = gen_label_rtx ();
  rtx word_mode_end_label = gen_label_rtx ();
  rtx byte_mode_size = gen_reg_rtx (SImode);
  rtx byte_mode_size_tmp = gen_reg_rtx (SImode);
  rtx word_mode_end = gen_reg_rtx (SImode);
  rtx size_for_word = gen_reg_rtx (SImode);

  /* and     $size_for_word, $size, #~0x7  */
  size_for_word = expand_binop (SImode, and_optab, size,
				gen_int_mode (~0x7, SImode),
				NULL_RTX, 0, OPTAB_WIDEN);

  emit_move_insn (byte_mode_size, size);

  /* beqz    $size_for_word, .Lbyte_mode_entry  */
  emit_cmp_and_jump_insns (size_for_word, const0_rtx, EQ, NULL,
			   SImode, 1, word_mode_end_label);
  /* add     $word_mode_end, $dst, $size_for_word  */
  word_mode_end = expand_binop (Pmode, add_optab, itr, size_for_word,
				NULL_RTX, 0, OPTAB_WIDEN);

  /* andi    $byte_mode_size, $size, 0x7  */
  byte_mode_size_tmp = expand_binop (SImode, and_optab, size, GEN_INT (0x7),
				     NULL_RTX, 0, OPTAB_WIDEN);

  emit_move_insn (byte_mode_size, byte_mode_size_tmp);

  /* .Lword_mode:  */
  emit_label (word_mode_label);
  /*   ! word-mode set loop
       smw.bim $value4word, [$dst_itr], $value4word, 0
       bne     $word_mode_end, $dst_itr, .Lword_mode  */
  emit_insn (gen_unaligned_store_update_base_dw (itr,
						 itr,
						 value));
  emit_cmp_and_jump_insns (word_mode_end, itr, NE, NULL,
			   Pmode, 1, word_mode_label);

  emit_label (word_mode_end_label);

  return byte_mode_size;
}
Пример #4
0
static rtx
emit_setmem_byte_loop (rtx itr, rtx size, rtx value, bool need_end)
{
  rtx end  = gen_reg_rtx (Pmode);
  rtx byte_mode_label = gen_label_rtx ();
  rtx end_label = gen_label_rtx ();

  value = force_reg (QImode, value);

  if (need_end)
    end = expand_binop (Pmode, add_optab, itr, size,
			NULL_RTX, 0, OPTAB_WIDEN);
  /*   beqz    $byte_mode_size, .Lend
       add     $byte_mode_end, $dst_itr, $byte_mode_size  */
  emit_cmp_and_jump_insns (size, const0_rtx, EQ, NULL,
			   SImode, 1, end_label);

  if (!need_end)
    end = expand_binop (Pmode, add_optab, itr, size,
			NULL_RTX, 0, OPTAB_WIDEN);

  /* .Lbyte_mode:  */
  emit_label (byte_mode_label);

  /*   ! byte-mode set loop
       sbi.bi  $value, [$dst_itr] ,1
       bne     $byte_mode_end, $dst_itr, .Lbyte_mode */
  nds32_emit_post_inc_load_store (value, itr, QImode, false);

  emit_cmp_and_jump_insns (end, itr, NE, NULL,
			   Pmode, 1, byte_mode_label);
  /* .Lend: */
  emit_label (end_label);

  if (need_end)
    return end;
  else
    return NULL_RTX;
}
Пример #5
0
static void
do_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0,
                           rtx if_false_label, rtx if_true_label)
{
  int nwords = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
  rtx part;
  int i;
  rtx drop_through_label = 0;

  /* The fastest way of doing this comparison on almost any machine is to
     "or" all the words and compare the result.  If all have to be loaded
     from memory and this is a very wide item, it's possible this may
     be slower, but that's highly unlikely.  */

  part = gen_reg_rtx (word_mode);
  emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0)));
  for (i = 1; i < nwords && part != 0; i++)
    part = expand_binop (word_mode, ior_optab, part,
                         operand_subword_force (op0, i, GET_MODE (op0)),
                         part, 1, OPTAB_WIDEN);

  if (part != 0)
    {
      do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
                               NULL_RTX, if_false_label, if_true_label);

      return;
    }

  /* If we couldn't do the "or" simply, do this with a series of compares.  */
  if (! if_false_label)
    drop_through_label = if_false_label = gen_label_rtx ();

  for (i = 0; i < nwords; i++)
    do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
                             const0_rtx, EQ, 1, word_mode, NULL_RTX,
                             if_false_label, NULL_RTX);

  if (if_true_label)
    emit_jump (if_true_label);

  if (drop_through_label)
    emit_label (drop_through_label);
}
Пример #6
0
void
ubsan_expand_si_overflow_addsub_check (tree_code code, gimple stmt)
{
  rtx res, op0, op1;
  tree lhs, fn, arg0, arg1;
  rtx_code_label *done_label, *do_error;
  rtx target = NULL_RTX;

  lhs = gimple_call_lhs (stmt);
  arg0 = gimple_call_arg (stmt, 0);
  arg1 = gimple_call_arg (stmt, 1);
  done_label = gen_label_rtx ();
  do_error = gen_label_rtx ();
  do_pending_stack_adjust ();
  op0 = expand_normal (arg0);
  op1 = expand_normal (arg1);

  machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
  if (lhs)
    target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);

  enum insn_code icode
    = optab_handler (code == PLUS_EXPR ? addv4_optab : subv4_optab, mode);
  if (icode != CODE_FOR_nothing)
    {
      struct expand_operand ops[4];
      rtx_insn *last = get_last_insn ();

      res = gen_reg_rtx (mode);
      create_output_operand (&ops[0], res, mode);
      create_input_operand (&ops[1], op0, mode);
      create_input_operand (&ops[2], op1, mode);
      create_fixed_operand (&ops[3], do_error);
      if (maybe_expand_insn (icode, 4, ops))
	{
	  last = get_last_insn ();
	  if (profile_status_for_fn (cfun) != PROFILE_ABSENT
	      && JUMP_P (last)
	      && any_condjump_p (last)
	      && !find_reg_note (last, REG_BR_PROB, 0))
	    add_int_reg_note (last, REG_BR_PROB, PROB_VERY_UNLIKELY);
	  emit_jump (done_label);
        }
      else
	{
	  delete_insns_since (last);
	  icode = CODE_FOR_nothing;
	}
    }

  if (icode == CODE_FOR_nothing)
    {
      rtx_code_label *sub_check = gen_label_rtx ();
      int pos_neg = 3;

      /* Compute the operation.  On RTL level, the addition is always
	 unsigned.  */
      res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
			  op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);

      /* If we can prove one of the arguments (for MINUS_EXPR only
	 the second operand, as subtraction is not commutative) is always
	 non-negative or always negative, we can do just one comparison
	 and conditional jump instead of 2 at runtime, 3 present in the
	 emitted code.  If one of the arguments is CONST_INT, all we
	 need is to make sure it is op1, then the first
	 emit_cmp_and_jump_insns will be just folded.  Otherwise try
	 to use range info if available.  */
      if (code == PLUS_EXPR && CONST_INT_P (op0))
	{
	  rtx tem = op0;
	  op0 = op1;
	  op1 = tem;
	}
      else if (CONST_INT_P (op1))
	;
      else if (code == PLUS_EXPR && TREE_CODE (arg0) == SSA_NAME)
	{
	  wide_int arg0_min, arg0_max;
	  if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
	    {
	      if (!wi::neg_p (arg0_min, TYPE_SIGN (TREE_TYPE (arg0))))
		pos_neg = 1;
	      else if (wi::neg_p (arg0_max, TYPE_SIGN (TREE_TYPE (arg0))))
		pos_neg = 2;
	    }
	  if (pos_neg != 3)
	    {
	      rtx tem = op0;
	      op0 = op1;
	      op1 = tem;
	    }
	}
      if (pos_neg == 3 && !CONST_INT_P (op1) && TREE_CODE (arg1) == SSA_NAME)
	{
	  wide_int arg1_min, arg1_max;
	  if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
	    {
	      if (!wi::neg_p (arg1_min, TYPE_SIGN (TREE_TYPE (arg1))))
		pos_neg = 1;
	      else if (wi::neg_p (arg1_max, TYPE_SIGN (TREE_TYPE (arg1))))
		pos_neg = 2;
	    }
	}

      /* If the op1 is negative, we have to use a different check.  */
      if (pos_neg == 3)
	emit_cmp_and_jump_insns (op1, const0_rtx, LT, NULL_RTX, mode,
				 false, sub_check, PROB_EVEN);

      /* Compare the result of the operation with one of the operands.  */
      if (pos_neg & 1)
	emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? GE : LE,
				 NULL_RTX, mode, false, done_label,
				 PROB_VERY_LIKELY);

      /* If we get here, we have to print the error.  */
      if (pos_neg == 3)
	{
	  emit_jump (do_error);

	  emit_label (sub_check);
	}

      /* We have k = a + b for b < 0 here.  k <= a must hold.  */
      if (pos_neg & 2)
	emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? LE : GE,
				 NULL_RTX, mode, false, done_label,
				 PROB_VERY_LIKELY);
    }

  emit_label (do_error);
  /* Expand the ubsan builtin call.  */
  push_temp_slots ();
  fn = ubsan_build_overflow_builtin (code, gimple_location (stmt),
				     TREE_TYPE (arg0), arg0, arg1);
  expand_normal (fn);
  pop_temp_slots ();
  do_pending_stack_adjust ();

  /* We're done.  */
  emit_label (done_label);

  if (lhs)
    emit_move_insn (target, res);
}
Пример #7
0
static bool
nds32_expand_movmemsi_loop_known_size (rtx dstmem, rtx srcmem,
				       rtx size, rtx alignment)
{
  rtx dst_base_reg, src_base_reg;
  rtx dst_itr, src_itr;
  rtx dstmem_m, srcmem_m, dst_itr_m, src_itr_m;
  rtx dst_end;
  rtx double_word_mode_loop, byte_mode_loop;
  rtx tmp;
  int start_regno;
  bool align_to_4_bytes = (INTVAL (alignment) & 3) == 0;
  unsigned HOST_WIDE_INT total_bytes = UINTVAL (size);

  if (TARGET_ISA_V3M && !align_to_4_bytes)
    return 0;

  if (TARGET_REDUCED_REGS)
    start_regno = 2;
  else
    start_regno = 16;

  dst_itr = gen_reg_rtx (Pmode);
  src_itr = gen_reg_rtx (Pmode);
  dst_end = gen_reg_rtx (Pmode);
  tmp = gen_reg_rtx (QImode);

  double_word_mode_loop = gen_label_rtx ();
  byte_mode_loop = gen_label_rtx ();

  dst_base_reg = copy_to_mode_reg (Pmode, XEXP (dstmem, 0));
  src_base_reg = copy_to_mode_reg (Pmode, XEXP (srcmem, 0));

  if (total_bytes < 8)
    {
      /* Emit total_bytes less than 8 loop version of movmem.
	add     $dst_end, $dst, $size
	move    $dst_itr, $dst
	.Lbyte_mode_loop:
	lbi.bi  $tmp, [$src_itr], #1
	sbi.bi  $tmp, [$dst_itr], #1
	! Not readch upper bound. Loop.
	bne     $dst_itr, $dst_end, .Lbyte_mode_loop */

      /* add     $dst_end, $dst, $size */
      dst_end = expand_binop (Pmode, add_optab, dst_base_reg, size,
			      NULL_RTX, 0, OPTAB_WIDEN);
      /* move    $dst_itr, $dst
	 move    $src_itr, $src */
      emit_move_insn (dst_itr, dst_base_reg);
      emit_move_insn (src_itr, src_base_reg);

      /* .Lbyte_mode_loop: */
      emit_label (byte_mode_loop);

      /* lbi.bi  $tmp, [$src_itr], #1 */
      nds32_emit_post_inc_load_store (tmp, src_itr, QImode, true);

      /* sbi.bi  $tmp, [$dst_itr], #1 */
      nds32_emit_post_inc_load_store (tmp, dst_itr, QImode, false);
      /* ! Not readch upper bound. Loop.
	 bne     $dst_itr, $dst_end, .Lbyte_mode_loop */
      emit_cmp_and_jump_insns (dst_itr, dst_end, NE, NULL,
			       SImode, 1, byte_mode_loop);
      return true;
    }
  else if (total_bytes % 8 == 0)
    {
      /* Emit multiple of 8 loop version of movmem.

	 add     $dst_end, $dst, $size
	 move    $dst_itr, $dst
	 move    $src_itr, $src

	.Ldouble_word_mode_loop:
	lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr
	smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr
	! move will delete after register allocation
	move    $src_itr, $src_itr'
	move    $dst_itr, $dst_itr'
	! Not readch upper bound. Loop.
	bne     $double_word_end, $dst_itr, .Ldouble_word_mode_loop */

      /* add     $dst_end, $dst, $size */
      dst_end = expand_binop (Pmode, add_optab, dst_base_reg, size,
			      NULL_RTX, 0, OPTAB_WIDEN);

      /* move    $dst_itr, $dst
	 move    $src_itr, $src */
      emit_move_insn (dst_itr, dst_base_reg);
      emit_move_insn (src_itr, src_base_reg);

      /* .Ldouble_word_mode_loop: */
      emit_label (double_word_mode_loop);
      /* lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr
	 smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr */
      src_itr_m = src_itr;
      dst_itr_m = dst_itr;
      srcmem_m = srcmem;
      dstmem_m = dstmem;
      nds32_emit_mem_move_block (start_regno, 2,
				 &dst_itr_m, &dstmem_m,
				 &src_itr_m, &srcmem_m,
				 true);
      /* move    $src_itr, $src_itr'
	 move    $dst_itr, $dst_itr' */
      emit_move_insn (dst_itr, dst_itr_m);
      emit_move_insn (src_itr, src_itr_m);

      /* ! Not readch upper bound. Loop.
	 bne     $double_word_end, $dst_itr, .Ldouble_word_mode_loop */
      emit_cmp_and_jump_insns (dst_end, dst_itr, NE, NULL,
			       Pmode, 1, double_word_mode_loop);
    }
  else
    {
      /* Handle size greater than 8, and not a multiple of 8.  */
      return nds32_expand_movmemsi_loop_unknown_size (dstmem, srcmem,
						      size, alignment);
    }

  return true;
}
Пример #8
0
static bool
nds32_expand_movmemsi_loop_unknown_size (rtx dstmem, rtx srcmem,
					 rtx size,
					 rtx alignment)
{
  /* Emit loop version of movmem.

       andi    $size_least_3_bit, $size, #~7
       add     $dst_end, $dst, $size
       move    $dst_itr, $dst
       move    $src_itr, $src
       beqz    $size_least_3_bit, .Lbyte_mode_entry ! Not large enough.
       add     $double_word_end, $dst, $size_least_3_bit

     .Ldouble_word_mode_loop:
       lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr
       smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr
       ! move will delete after register allocation
       move    $src_itr, $src_itr'
       move    $dst_itr, $dst_itr'
       ! Not readch upper bound. Loop.
       bne     $double_word_end, $dst_itr, .Ldouble_word_mode_loop

     .Lbyte_mode_entry:
       beq     $dst_itr, $dst_end, .Lend_label
     .Lbyte_mode_loop:
       lbi.bi  $tmp, [$src_itr], #1
       sbi.bi  $tmp, [$dst_itr], #1
       ! Not readch upper bound. Loop.
       bne     $dst_itr, $dst_end, .Lbyte_mode_loop
     .Lend_label:
  */
  rtx dst_base_reg, src_base_reg;
  rtx dst_itr, src_itr;
  rtx dstmem_m, srcmem_m, dst_itr_m, src_itr_m;
  rtx dst_end;
  rtx size_least_3_bit;
  rtx double_word_end;
  rtx double_word_mode_loop, byte_mode_entry, byte_mode_loop, end_label;
  rtx tmp;
  rtx mask_least_3_bit;
  int start_regno;
  bool align_to_4_bytes = (INTVAL (alignment) & 3) == 0;

  if (TARGET_ISA_V3M && !align_to_4_bytes)
    return 0;

  if (TARGET_REDUCED_REGS)
    start_regno = 2;
  else
    start_regno = 16;

  dst_itr = gen_reg_rtx (Pmode);
  src_itr = gen_reg_rtx (Pmode);
  dst_end = gen_reg_rtx (Pmode);
  tmp = gen_reg_rtx (QImode);
  mask_least_3_bit = GEN_INT (~7);

  double_word_mode_loop = gen_label_rtx ();
  byte_mode_entry = gen_label_rtx ();
  byte_mode_loop = gen_label_rtx ();
  end_label = gen_label_rtx ();

  dst_base_reg = copy_to_mode_reg (Pmode, XEXP (dstmem, 0));
  src_base_reg = copy_to_mode_reg (Pmode, XEXP (srcmem, 0));
  /* andi   $size_least_3_bit, $size, #~7 */
  size_least_3_bit = expand_binop (SImode, and_optab, size, mask_least_3_bit,
				   NULL_RTX, 0, OPTAB_WIDEN);
  /* add     $dst_end, $dst, $size */
  dst_end = expand_binop (Pmode, add_optab, dst_base_reg, size,
			  NULL_RTX, 0, OPTAB_WIDEN);

  /* move    $dst_itr, $dst
     move    $src_itr, $src */
  emit_move_insn (dst_itr, dst_base_reg);
  emit_move_insn (src_itr, src_base_reg);

  /* beqz    $size_least_3_bit, .Lbyte_mode_entry ! Not large enough. */
  emit_cmp_and_jump_insns (size_least_3_bit, const0_rtx, EQ, NULL,
			   SImode, 1, byte_mode_entry);
  /* add     $double_word_end, $dst, $size_least_3_bit */
  double_word_end = expand_binop (Pmode, add_optab,
				  dst_base_reg, size_least_3_bit,
				  NULL_RTX, 0, OPTAB_WIDEN);

  /* .Ldouble_word_mode_loop: */
  emit_label (double_word_mode_loop);
  /* lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr
     smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr */
  src_itr_m = src_itr;
  dst_itr_m = dst_itr;
  srcmem_m = srcmem;
  dstmem_m = dstmem;
  nds32_emit_mem_move_block (start_regno, 2,
			     &dst_itr_m, &dstmem_m,
			     &src_itr_m, &srcmem_m,
			     true);
  /* move    $src_itr, $src_itr'
     move    $dst_itr, $dst_itr' */
  emit_move_insn (dst_itr, dst_itr_m);
  emit_move_insn (src_itr, src_itr_m);

  /* ! Not readch upper bound. Loop.
     bne     $double_word_end, $dst_itr, .Ldouble_word_mode_loop */
  emit_cmp_and_jump_insns (double_word_end, dst_itr, NE, NULL,
			   Pmode, 1, double_word_mode_loop);
  /* .Lbyte_mode_entry: */
  emit_label (byte_mode_entry);

  /* beq     $dst_itr, $dst_end, .Lend_label */
  emit_cmp_and_jump_insns (dst_itr, dst_end, EQ, NULL,
			   Pmode, 1, end_label);
  /* .Lbyte_mode_loop: */
  emit_label (byte_mode_loop);

  /* lbi.bi  $tmp, [$src_itr], #1 */
  nds32_emit_post_inc_load_store (tmp, src_itr, QImode, true);

  /* sbi.bi  $tmp, [$dst_itr], #1 */
  nds32_emit_post_inc_load_store (tmp, dst_itr, QImode, false);
  /* ! Not readch upper bound. Loop.
     bne     $dst_itr, $dst_end, .Lbyte_mode_loop */
  emit_cmp_and_jump_insns (dst_itr, dst_end, NE, NULL,
			   SImode, 1, byte_mode_loop);

  /* .Lend_label: */
  emit_label (end_label);

  return true;
}