参照元

説明

引数

返り値

参考

実装

/* We want to create (subreg:OMODE (obj:IMODE) OFFSET).  Return true if
   this construct would be valid, and false otherwise.  */

bool
validate_subreg (machine_mode omode, machine_mode imode,
		 const_rtx reg, poly_uint64 offset)
{
  poly_uint64 isize = GET_MODE_SIZE (imode);
  poly_uint64 osize = GET_MODE_SIZE (omode);

  /* The sizes must be ordered, so that we know whether the subreg
     is partial, paradoxical or complete.  */
  if (!ordered_p (isize, osize))
    return false;

  /* All subregs must be aligned.  */
  if (!multiple_p (offset, osize))
    return false;

  /* The subreg offset cannot be outside the inner object.  */
  if (maybe_ge (offset, isize))
    return false;
  poly_uint64 regsize = REGMODE_NATURAL_SIZE (imode);
  /* ??? This should not be here.  Temporarily continue to allow word_mode
     subregs of anything.  The most common offender is (subreg:SI (reg:DF)).
     Generally, backends are doing something sketchy but it'll take time to
     fix them all.  */
  if (omode == word_mode)
    ;
  /* ??? Similarly, e.g. with (subreg:DF (reg:TI)).  Though store_bit_field
     is the culprit here, and not the backends.  */
  else if (known_ge (osize, regsize) && known_ge (isize, osize))
    ;
  /* Allow component subregs of complex and vector.  Though given the below
     extraction rules, it's not always clear what that means.  */
  else if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
	   && GET_MODE_INNER (imode) == omode)
    ;
  /* ??? x86 sse code makes heavy use of *paradoxical* vector subregs,
     i.e. (subreg:V4SF (reg:SF) 0).  This surely isn't the cleanest way to
     represent this.  It's questionable if this ought to be represented at
     all -- why can't this all be hidden in post-reload splitters that make
     arbitrarily mode changes to the registers themselves.  */
  else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode)
    ;
  /* Subregs involving floating point modes are not allowed to
     change size.  Therefore (subreg:DI (reg:DF) 0) is fine, but
     (subreg:SI (reg:DF) 0) isn't.  */
  else if (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))
    {
      if (! (known_eq (isize, osize)
	     /* LRA can use subreg to store a floating point value in
		an integer mode.  Although the floating point and the
		integer modes need the same number of hard registers,
		the size of floating point mode can be less than the
		integer mode.  LRA also uses subregs for a register
		should be used in different mode in on insn.  */
	     || lra_in_progress))
	return false;
    }
  /* Paradoxical subregs must have offset zero.  */
  if (maybe_gt (osize, isize))
    return known_eq (offset, 0U);
  /* This is a normal subreg.  Verify that the offset is representable.  */

  /* For hard registers, we already have most of these rules collected in
     subreg_offset_representable_p.  */
  if (reg && REG_P (reg) && HARD_REGISTER_P (reg))
    {
      unsigned int regno = REGNO (reg);

      if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
	  && GET_MODE_INNER (imode) == omode)
	;
      else if (!REG_CAN_CHANGE_MODE_P (regno, imode, omode))
	return false;

      return subreg_offset_representable_p (regno, imode, offset, omode);
    }
  /* The outer size must be ordered wrt the register size, otherwise
     we wouldn't know at compile time how many registers the outer
     mode occupies.  */
  if (!ordered_p (osize, regsize))
    return false;
  /* For pseudo registers, we want most of the same checks.  Namely:

     Assume that the pseudo register will be allocated to hard registers
     that can hold REGSIZE bytes each.  If OSIZE is not a multiple of REGSIZE,
     the remainder must correspond to the lowpart of the containing hard
     register.  If BYTES_BIG_ENDIAN, the lowpart is at the highest offset,
     otherwise it is at the lowest offset.

     Given that we've already checked the mode and offset alignment,
     we only have to check subblock subregs here.  */
  if (maybe_lt (osize, regsize)
      && ! (lra_in_progress && (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))))
    {
      /* It is invalid for the target to pick a register size for a mode
	 that isn't ordered wrt to the size of that mode.  */
      poly_uint64 block_size = ordered_min (isize, regsize);
      unsigned int start_reg;
      poly_uint64 offset_within_reg;
      if (!can_div_trunc_p (offset, block_size, &start_reg, &offset_within_reg)
	  || (BYTES_BIG_ENDIAN
	      ? maybe_ne (offset_within_reg, block_size - osize)
	      : maybe_ne (offset_within_reg, 0U)))
	return false;
    }
  return true;
}

コメント


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2020-03-13 (金) 19:53:22