/* { dg-do compile { target { ! ia32 } } } */
/* { dg-options "-O2 -mx32 -maddress-mode=long" } */

typedef struct rtx_def *rtx;
enum rtx_code { MINUS };
union rtunion_def {
  rtx rt_rtx;
};
typedef union rtunion_def rtunion;
struct rtx_def {
  enum rtx_code code: 16;
  union u {
    rtunion fld[1];
  }
  u;
};
rtx simplify_binary_operation (enum rtx_code code, int mode,
			       rtx op0, rtx op1);
struct simplify_plus_minus_op_data {
  rtx op;
  short neg;
};
void simplify_plus_minus (enum rtx_code code, int mode, rtx op0, rtx op1)
{
  struct simplify_plus_minus_op_data ops[8];
  rtx tem = (rtx) 0;
  int n_ops = 2, input_ops = 2;
  int changed, canonicalized = 0;
  int i, j;
  __builtin_memset (ops, 0, sizeof (ops));
  do
    {
      changed = 0;
      for (i = 0; i < n_ops; i++)
	{
	  rtx this_op = ops[i].op;
	  int this_neg = ops[i].neg;
	  enum rtx_code this_code = ((enum rtx_code) (this_op)->code);
	  switch (this_code)
	    {
	    case MINUS:
	      if (n_ops == 7)
		return;
	      n_ops++;
	      input_ops++;
	      changed = 1;
	      canonicalized |= this_neg; 
	      break;
	    }
	}
    }
  while (changed);
  do 
    {
      j =  n_ops - 1;
      for (i = n_ops - 1; j >= 0; j--)
	{
	  rtx lhs = ops[j].op, rhs = ops[i].op;
	  int lneg = ops[j].neg, rneg = ops[i].neg;
	  if (lhs != 0 && rhs != 0)
	    {
	      enum rtx_code ncode = MINUS;
	      if (((enum rtx_code) (lhs)->code) == MINUS)
		tem = simplify_binary_operation (ncode, mode, lhs, rhs);
	      if (tem && ! (((enum rtx_code) (tem)->code) == MINUS 
			    && ((((((tem)->u.fld[0]).rt_rtx))->u.fld[0]).rt_rtx) == lhs
			    && ((((((tem)->u.fld[0]).rt_rtx))->u.fld[1]).rt_rtx) == rhs))
		{
		  lneg &= rneg;
		  ops[i].op = tem;
		  ops[i].neg = lneg;
		  ops[j].op = (rtx) 0;
		  changed = 1;
		  canonicalized = 1;
		}
	    }
	}
      for (i = 0, j = 0; j < n_ops; j++)
	if (ops[j].op)
	  {
	    ops[i] = ops[j];
	    i++;
	  }
    }
  while (changed);
}
