This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

tree-ssa optimizer limitations (was Re: RFC: define_predicate)


Joern Rennecke <joern.rennecke@superh.com> writes:

>> if genpreds.c would put an additional switch statement before the user 
>> code.  Well, maybe in this case it is not that much more readable (maybe 
>> the opposite is true), but in many predicates the third argument to 
>> define_predicate would be superfluous, as in
>> 
>> +;; Return 1 if OP refers to a symbol.
>> +(define_predicate "symbolic_operand" "symbol_ref,const,label_ref"
>> +{
>> +  switch (GET_CODE (op))
>> +    {
>> +    case CONST:
>> +    case SYMBOL_REF:
>> +    case LABEL_REF:
>> +      return 1;
>> +
>> +    default:
>> +      break;
>> +    }
>> +  return 0;
>> +})
>> 
>> and that argument could be made optional (defaulting to "return 1;"). 
>> Does this make sense?
>
> It's very hard to optimize that switch statement away if it is not needed.
> I propose it is only inserted if you omit the third argument.

I would prefer to rely on the new optimizers to get this right (it
seems like the sort of thing that ought to be easy with SSA) but
disappointingly, they don't.  I've been revising this patch; the
current version takes input like this

;; True if OP refers to a symbol in the sdata section.
(define_predicate "sdata_symbolic_operand" 
  (match_code "symbol_ref,const")
{
  switch (GET_CODE (op))
    {
    case CONST:
      op = XEXP (op, 0);
      if (GET_CODE (op) != PLUS
	  || GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
	return false;
      op = XEXP (op, 0);
      /* FALLTHRU */

    case SYMBOL_REF:
      if (CONSTANT_POOL_ADDRESS_P (op))
	return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold;
      else
	return SYMBOL_REF_LOCAL_P (op) && SYMBOL_REF_SMALL_P (op);

    default:
      abort ();
    }
})

and produces code like this

static inline bool
sdata_symbolic_operand_1 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
  switch (GET_CODE (op))
    {
    case CONST:
      op = XEXP (op, 0);
      if (GET_CODE (op) != PLUS
	  || GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
	return false;
      op = XEXP (op, 0);
      /* FALLTHRU */

    case SYMBOL_REF:
      if (CONSTANT_POOL_ADDRESS_P (op))
	return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold;
      else
	return SYMBOL_REF_LOCAL_P (op) && SYMBOL_REF_SMALL_P (op);

    default:
      abort ();
    }
}

bool
sdata_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST) 
          && (sdata_symbolic_operand_1 (op, mode));
}

and ... known-value propagation into control flow statements doesn't
seem to be happening *at all*.  Most disappointing.  I mean, forget
the above, we've got crap like this in the -fdump-tree-optimized
output:

<L15>:;
  if ((unsigned char)T?363 == 0) goto <L17>; else goto <L33>;

<L33>:;
  T?388 = 1;
  goto <bb 15> (<L18>);

<L17>:;
  T?388 = 0;

<L18>:;
  return T?388;

where T?363 is guaranteed to be 0 or 1 when control reaches <L15>...

tree-ssa folks, what's the missing piece here?  Complete
-fdump-tree-optimized result of above is appended.  N.B. disabling
checking has no substantial effect.

zw

sdata_symbolic_operand (op, mode)
{
  struct rtx_def * const _rtx;
  static const char __FUNCTION__[25] = "sdata_symbolic_operand_1";
  _Bool T?387;
  _Bool T?386;
  int T?385;
  int T?384;
  unsigned char T?382?383;
  signed char T?382;
  unsigned int T?381;
  _Bool T?380;
  _Bool T?379;
  int T?378;
  int T?377;
  unsigned char T?375?376;
  signed char T?375;
  unsigned int T?374;
  unsigned int T?372?373;
  int T?372;
  int iftmp?371;
  unsigned int ia64_section_threshold?370;
  unsigned int T?369;
  unsigned char T?368;
  machine_mode T?367;
  int T?366;
  <unnamed type> T?365;
  <unnamed type> T?364;
  struct rtx_def * const T?358;
  int T?363;
  <unnamed type> T?362;
  struct rtx_def * T?361;
  unsigned int T?360;
  <unnamed type> T?359;
  struct rtx_def * op;
  machine_mode mode;
  unsigned char T?395;
  _Bool T?394;
  _Bool T?393;
  _Bool T?392;
  _Bool T?391;
  <unnamed type> T?390;
  int iftmp?389;
  int T?388;
  int <D10813>;

<bb 0>:
  T?390 = op->code;
  if ((T?390 == 82 || T?390 == 72) == 0) goto <L28>; else goto <L0>;

<L28>:;
  T?388 = 0;
  goto <bb 15> (<L18>);

<L0>:;
  switch (T?390)
    {
      case 72: goto <L1>;
      case 82: goto <L5>;
      default : goto <L14>;
    }

<L1>:;
  op = op->u.fld[0].rt_rtx;
  if (op->code != 87) goto <L29>; else goto <L2>;

<L2>:;
  op = op->u.fld[0].rt_rtx;
  if (op->code != 82) goto <L30>; else goto <L5>;

<L30>:;
  T?363 = 0;
  goto <bb 13> (<L15>);

<L5>:;
  if (op->code != 82) goto <L6>; else goto <L7>;

<L6>:;
  rtl_check_failed_flag ("CONSTANT_POOL_ADDRESS_P", op, "insn-preds.c", 330, &__FUNCTION__);

<L7>:;
  if (op->unchanging != 0) goto <L8>; else goto <L9>;

<L8>:;
  T?367 = get_pool_mode (op);
  T?363 = (unsigned int)mode_size[T?367] <= ia64_section_threshold;
  goto <bb 13> (<L15>);

<L9>:;
  T?372?373 = (unsigned int)op->u.fld[1].rt_int;
  if (((int)(unsigned char)(signed char)(T?372?373 >> 1) & 1) == 0) goto <L31>; else goto <L10>;

<L31>:;
  T?363 = 0;
  goto <bb 11> (<L13>);

<L10>:;
  if (((int)(unsigned char)(signed char)(T?372?373 >> 2) & 1) == 0) goto <L12>; else goto <L32>;

<L32>:;
  T?363 = 1;
  goto <bb 11> (<L13>);

<L12>:;
  T?363 = 0;

<L13>:;
  goto <bb 13> (<L15>);

<L14>:;
  fancy_abort ("insn-preds.c", 336, &__FUNCTION__);

<L29>:;
  T?363 = 0;

<L15>:;
  if ((unsigned char)T?363 == 0) goto <L17>; else goto <L33>;

<L33>:;
  T?388 = 1;
  goto <bb 15> (<L18>);

<L17>:;
  T?388 = 0;

<L18>:;
  return T?388;

}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]