Beispiel #1
0
rtx
gen_lowpart_if_possible (machine_mode mode, rtx x)
{
  rtx result = gen_lowpart_common (mode, x);

  if (result)
    return result;
  else if (MEM_P (x))
    {
      /* This is the only other case we handle.  */
      poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (x));
      rtx new_rtx = adjust_address_nv (x, mode, offset);
      if (! memory_address_addr_space_p (mode, XEXP (new_rtx, 0),
					 MEM_ADDR_SPACE (x)))
	return 0;

      return new_rtx;
    }
  else if (mode != GET_MODE (x) && GET_MODE (x) != VOIDmode
	   && validate_subreg (mode, GET_MODE (x), x,
			        subreg_lowpart_offset (mode, GET_MODE (x))))
    return gen_lowpart_SUBREG (mode, x);
  else
    return 0;
}
Beispiel #2
0
/* Transform (subreg (plus reg const)) to (plus (subreg reg) const)
   when it is possible.  Return X or the transformation result if the
   transformation is done.  */
static rtx
move_plus_up (rtx x)
{
  rtx subreg_reg;
  enum machine_mode x_mode, subreg_reg_mode;
  
  if (GET_CODE (x) != SUBREG || !subreg_lowpart_p (x))
    return x;
  subreg_reg = SUBREG_REG (x);
  x_mode = GET_MODE (x);
  subreg_reg_mode = GET_MODE (subreg_reg);
  if (GET_CODE (x) == SUBREG && GET_CODE (subreg_reg) == PLUS
      && GET_MODE_SIZE (x_mode) <= GET_MODE_SIZE (subreg_reg_mode)
      && CONSTANT_P (XEXP (subreg_reg, 1))
      && GET_MODE_CLASS (x_mode) == MODE_INT
      && GET_MODE_CLASS (subreg_reg_mode) == MODE_INT)
    {
      rtx cst = simplify_subreg (x_mode, XEXP (subreg_reg, 1), subreg_reg_mode,
				 subreg_lowpart_offset (x_mode,
							subreg_reg_mode));
      if (cst && CONSTANT_P (cst))
	return gen_rtx_PLUS (x_mode, lowpart_subreg (x_mode,
						     XEXP (subreg_reg, 0),
						     subreg_reg_mode), cst);
    }
  return x;
}
static bool
nds32_expand_setmem_loop_v3m (rtx dstmem, rtx size, rtx value)
{
  rtx base_reg = copy_to_mode_reg (Pmode, XEXP (dstmem, 0));
  rtx need_align_bytes = gen_reg_rtx (SImode);
  rtx last_2_bit = gen_reg_rtx (SImode);
  rtx byte_loop_base = gen_reg_rtx (SImode);
  rtx byte_loop_size = gen_reg_rtx (SImode);
  rtx remain_size = gen_reg_rtx (SImode);
  rtx new_base_reg;
  rtx value4byte, value4doubleword;
  rtx byte_mode_size;
  rtx last_byte_loop_label = gen_label_rtx ();

  size = force_reg (SImode, size);

  value4doubleword = nds32_gen_dup_8_byte_to_double_word_value (value);
  value4byte = simplify_gen_subreg (QImode, value4doubleword, DImode,
				    subreg_lowpart_offset (QImode, DImode));

  emit_move_insn (byte_loop_size, size);
  emit_move_insn (byte_loop_base, base_reg);

  /* Jump to last byte loop if size is less than 16.  */
  emit_cmp_and_jump_insns (size, gen_int_mode (16, SImode), LE, NULL,
			   SImode, 1, last_byte_loop_label);

  /* Make sure align to 4 byte first since v3m can't unalign access.  */
  emit_insn (gen_andsi3 (last_2_bit,
			 base_reg,
			 gen_int_mode (0x3, SImode)));

  emit_insn (gen_subsi3 (need_align_bytes,
			 gen_int_mode (4, SImode),
			 last_2_bit));

  /* Align to 4 byte. */
  new_base_reg = emit_setmem_byte_loop (base_reg,
					need_align_bytes,
					value4byte,
					true);

  /* Calculate remain size. */
  emit_insn (gen_subsi3 (remain_size, size, need_align_bytes));

  /* Set memory word by word. */
  byte_mode_size = emit_setmem_doubleword_loop (new_base_reg,
						remain_size,
						value4doubleword);

  emit_move_insn (byte_loop_base, new_base_reg);
  emit_move_insn (byte_loop_size, byte_mode_size);

  emit_label (last_byte_loop_label);

  /* And set memory for remain bytes. */
  emit_setmem_byte_loop (byte_loop_base, byte_loop_size, value4byte, false);
  return true;
}
static bool
nds32_expand_setmem_unroll (rtx dstmem, rtx size, rtx value,
			    rtx align ATTRIBUTE_UNUSED,
			    rtx expected_align ATTRIBUTE_UNUSED,
			    rtx expected_size ATTRIBUTE_UNUSED)
{
  unsigned maximum_regs, maximum_bytes, start_regno, regno;
  rtx value4word;
  rtx dst_base_reg, new_base_reg;
  unsigned HOST_WIDE_INT remain_bytes, remain_words, prepare_regs, fill_per_smw;
  unsigned HOST_WIDE_INT real_size;

  if (TARGET_REDUCED_REGS)
    {
      maximum_regs  = 4;
      maximum_bytes = 64;
      start_regno   = 2;
    }
  else
    {
      maximum_regs  = 8;
      maximum_bytes = 128;
      start_regno   = 16;
    }

  real_size = UINTVAL (size) & GET_MODE_MASK(SImode);

  if (!(CONST_INT_P (size) && real_size <= maximum_bytes))
    return false;

  remain_bytes = real_size;

  gcc_assert (GET_MODE (value) == QImode || CONST_INT_P (value));

  value4word = nds32_gen_dup_4_byte_to_word_value (value);

  prepare_regs = remain_bytes / UNITS_PER_WORD;

  dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0));

  if (prepare_regs > maximum_regs)
    prepare_regs = maximum_regs;

  fill_per_smw = prepare_regs * UNITS_PER_WORD;

  regno = start_regno;
  switch (prepare_regs)
    {
    case 2:
    default:
      {
	rtx reg0 = gen_rtx_REG (SImode, regno);
	rtx reg1 = gen_rtx_REG (SImode, regno+1);
	unsigned last_regno = start_regno + prepare_regs - 1;

	emit_move_insn (reg0, value4word);
	emit_move_insn (reg1, value4word);
	rtx regd = gen_rtx_REG (DImode, regno);
	regno += 2;

	/* Try to utilize movd44!  */
	while (regno <= last_regno)
	  {
	    if ((regno + 1) <=last_regno)
	      {
		rtx reg = gen_rtx_REG (DImode, regno);
		emit_move_insn (reg, regd);
		regno += 2;
	      }
	    else
	      {
		rtx reg = gen_rtx_REG (SImode, regno);
		emit_move_insn (reg, reg0);
		regno += 1;
	      }
	  }
	break;
      }
    case 1:
      {
	rtx reg = gen_rtx_REG (SImode, regno++);
	emit_move_insn (reg, value4word);
      }
      break;
    case 0:
      break;
    }

  if (fill_per_smw)
    for (;remain_bytes >= fill_per_smw;remain_bytes -= fill_per_smw)
      {
	emit_insn (nds32_expand_store_multiple (start_regno, prepare_regs,
						dst_base_reg, dstmem,
						true, &new_base_reg));
	dst_base_reg = new_base_reg;
	dstmem = gen_rtx_MEM (SImode, dst_base_reg);
      }

  remain_words = remain_bytes / UNITS_PER_WORD;

  if (remain_words)
    {
      emit_insn (nds32_expand_store_multiple (start_regno, remain_words,
					      dst_base_reg, dstmem,
					      true, &new_base_reg));
      dst_base_reg = new_base_reg;
      dstmem = gen_rtx_MEM (SImode, dst_base_reg);
    }

  remain_bytes = remain_bytes - (remain_words * UNITS_PER_WORD);

  if (remain_bytes)
    {
      value = simplify_gen_subreg (QImode, value4word, SImode,
				   subreg_lowpart_offset(QImode, SImode));
      int offset = 0;
      for (;remain_bytes;--remain_bytes, ++offset)
	{
	  nds32_emit_load_store (value, dstmem, QImode, offset, false);
	}
    }

  return true;
}
static bool
nds32_expand_setmem_loop (rtx dstmem, rtx size, rtx value)
{
  rtx value4doubleword;
  rtx value4byte;
  rtx dst;
  rtx byte_mode_size;

  /* Emit loop version of setmem.
     memset:
       ! prepare word
       andi    $tmp1, $val, 0xff               ! $tmp1  <- 0x000000ab
       slli    $tmp2, $tmp1, 8                 ! $tmp2  <- 0x0000ab00
       or      $tmp3, $val, $tmp2              ! $tmp3  <- 0x0000abab
       slli    $tmp4, $tmp3, 16                ! $tmp4  <- 0xabab0000
       or      $val4word, $tmp3, $tmp4         ! $value4word  <- 0xabababab

       and     $size_for_word, $size, #-4
       beqz    $size_for_word, .Lword_mode_end

       add     $word_mode_end, $dst, $size_for_word
       andi    $byte_mode_size, $size, 3

     .Lword_mode:
       ! word-mode set loop
       smw.bim $value4word, [$dst], $value4word, 0
       bne     $word_mode_end, $dst, .Lword_mode

     .Lword_mode_end:
       beqz    $byte_mode_size, .Lend
       add     $byte_mode_end, $dst, $byte_mode_size

     .Lbyte_mode:
       ! byte-mode set loop
       sbi.bi  $value4word, [$dst] ,1
       bne     $byte_mode_end, $dst, .Lbyte_mode
     .Lend: */

  dst = copy_to_mode_reg (SImode, XEXP (dstmem, 0));

  /* ! 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  */
  value4doubleword = nds32_gen_dup_8_byte_to_double_word_value (value);

  /*   and     $size_for_word, $size, #-4
       beqz    $size_for_word, .Lword_mode_end

       add     $word_mode_end, $dst, $size_for_word
       andi    $byte_mode_size, $size, 3

     .Lword_mode:
       ! word-mode set loop
       smw.bim $value4word, [$dst], $value4word, 0
       bne     $word_mode_end, $dst, .Lword_mode
     .Lword_mode_end:  */
  byte_mode_size = emit_setmem_doubleword_loop (dst, size, value4doubleword);

  /*   beqz    $byte_mode_size, .Lend
       add     $byte_mode_end, $dst, $byte_mode_size

     .Lbyte_mode:
       ! byte-mode set loop
       sbi.bi  $value, [$dst] ,1
       bne     $byte_mode_end, $dst, .Lbyte_mode
     .Lend: */

  value4byte = simplify_gen_subreg (QImode, value4doubleword, DImode,
				    subreg_lowpart_offset (QImode, DImode));

  emit_setmem_byte_loop (dst, byte_mode_size, value4byte, false);

  return true;
}