[PATCH] Extend CSE to use constant anchors

Eric Botcazou ebotcazou@adacore.com
Sat May 23 09:10:00 GMT 2009


> The patch does not directly fix PR/33699 anymore.  That will require
> further modifications in the cost model and possibly fwprop.  Should I
> still put the PR number in the changelog?

I think so.

> 	* target.h (struct gcc_target): Fix indentation.  Add
> 	const_anchor.
> 	* target-def.h (TARGET_CONST_ANCHOR): New macro.
> 	(TARGET_INITIALIZER): Use it.
> 	* cse.c (insert): Rename this ...
> 	(insert_with_costs): ... to this.  Add cost parameters.  Update
> 	function comment.
> 	(insert): New function.  Call insert_with_costs.
> 	(compute_const_anchors, insert_const_anchor, insert_const_anchors,
> 	find_reg_offset_for_const, try_const_anchors): New functions.
> 	(cse_insn): Call try_const_anchors.  Adjust cost of src_related
> 	when using a const-anchor.  Call insert_const_anchors.

Looks good, but see the nits below:

> +/* Compute upper and lower anchors for CST.  Also compute the offset of
> CST +   from these anchors/bases such that *_BASE + *_OFFS = CST.  Return
> false iff +   CST is equal to an anchor.  */
> +
> +static bool
> +compute_const_anchors (rtx cst,
> +		       HOST_WIDE_INT *lower_base, HOST_WIDE_INT *lower_offs,
> +		       HOST_WIDE_INT *upper_base, HOST_WIDE_INT *upper_offs)
> +{
> +  HOST_WIDE_INT n = INTVAL (cst);
> +
> +  *lower_base = n & ~(targetm.const_anchor - 1);
> +  if (*lower_base == n)
> +    return false;
> +
> +  *upper_base =
> +    (n + (targetm.const_anchor - 1)) & ~(targetm.const_anchor - 1);

This requires targetm.const_anchor to be a power of 2.

> +  *upper_offs = n - *upper_base;
> +  *lower_offs = n - *lower_base;
> +  return true;
> +}
> +
> +/* Insert the equivalence between ANCHOR and EXP in mode MODE.  REG is
> +   the register in EXP.  */
> +
> +static void
> +insert_const_anchor (HOST_WIDE_INT anchor, rtx exp, enum machine_mode
> mode, +		     rtx reg)
> +{
> +  struct table_elt *elt;
> +  unsigned hash;
> +  rtx anchor_exp;
> +
> +  anchor_exp = GEN_INT (anchor);
> +  hash = HASH (anchor_exp, mode);
> +  elt = lookup (anchor_exp, hash, mode);
> +  if (!elt)
> +    elt = insert (anchor_exp, NULL, hash, mode);
> +
> +  hash = HASH (exp, mode);
> +  if (insert_regs (exp, elt, 0))
> +    {
> +      rehash_using_reg (exp);
> +      hash = HASH (exp, mode);
> +    }

exp is a plus_constant (reg, xxx) so rehash_using_reg (exp) is a no-op.

You don't need to call insert_regs since it's done just before the call to 
insert_const_anchors in cse_insn.

> +  /* Use the cost of the register rather than the whole expression.
> +     When looking up constant anchors we will further offset the
> +     corresponding expression therefore it does not make sense to
> +     prefer REGs over reg-immediate additions.  Instead prefer the
> +     oldest expression.  Also don't prefer pseudos over hard regs.  */
> +  insert_with_costs (exp, elt, hash, mode, COST (reg), 1);

Why the last sentence?

> +
> +/* The constant CST is equivalent to the register REG.  Create
> +   equivalences between the two anchors of CST and the corresponding
> +   register-offset expressions using REG.  */
> +
> +static void
> +insert_const_anchors (rtx reg, rtx cst, enum machine_mode mode)
> +{
> +  HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
> +
> +  if (!compute_const_anchors (cst, &lower_base, &lower_offs,
> +			      &upper_base, &upper_offs))
> +      return;
> +
> +  /* Ignore anchors of value 0.  Constants accessible from zero are
> +     simple.  */
> +  if (lower_base != 0)
> +    insert_const_anchor (lower_base, plus_constant (reg, -lower_offs),
> mode, +			 reg);
> +
> +  if (upper_base != 0)
> +    insert_const_anchor (upper_base, plus_constant (reg, -upper_offs),
> mode, +			 reg);
> +}

I would pass the naked offset to insert_const_anchor:

insert_const_anchor (upper_base, mode, reg, -offset);

> +/* We need to express ANCHOR_ELT->exp + OFFS.  Walk the equivalence list
> of +   ANCHOR_ELT and see if offsetting any of the entries by OFFS would
> create a +   valid expression.  */

Missing comment about the return value.

> +static rtx
> +find_reg_offset_for_const (struct table_elt *anchor_elt, HOST_WIDE_INT
> offs, +			   unsigned *old)
> +{
> +  struct table_elt *elt;
> +  unsigned idx;
> +  struct table_elt *match_elt;
> +  rtx match;
> +
> +  /* Find the cheapest and *oldest* expression to maximize the chance of
> +     reusing the same pseudo.  */
> +
> +  match_elt = NULL;
> +  match = NULL_RTX;
> +  for (elt = anchor_elt->first_same_value, idx = 0;
> +       elt;
> +       elt = elt->next_same_value, idx++)
> +    {
> +      if (match_elt && CHEAPER (match_elt, elt))
> +	return match;
> +
> +      if (REG_P (elt->exp)
> +	  || (GET_CODE (elt->exp) == PLUS
> +	      && REG_P (XEXP (elt->exp, 0))
> +	      && GET_CODE (XEXP (elt->exp, 1)) == CONST_INT))
> +	{
> +	  rtx x;
> +
> +	  /* Ignore expressions that are no longer valid.  */
> +	  if (!REG_P (elt->exp) && !exp_equiv_p (elt->exp, elt->exp, 1, false))
> +	    continue;

Why excluding REGs from the validity check?

> +	  x = plus_constant (elt->exp, offs);
> +	  if (REG_P (x)
> +	      || (GET_CODE (x) == PLUS
> +		  && IN_RANGE (INTVAL (XEXP (x, 1)),
> +			       -targetm.const_anchor,
> +			       targetm.const_anchor - 1)))
> +	    {
> +	      match = x;
> +	      match_elt = elt;
> +	      *old = idx;
> +	    }
> +	}
> +    }
> +
> +  return match;
> +}
> +
> +/* Try to express the constant SRC_CONST using a register-offset
> expression +   derived from a constant anchor.  */

register+offset :-)  "Return it on success and NULL_RTX on failure".

> +
> +static rtx
> +try_const_anchors (rtx src_const, enum machine_mode mode)
> +{
> +  struct table_elt *lower_elt, *upper_elt;
> +  HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
> +  rtx lower_anchor_rtx, upper_anchor_rtx;
> +  rtx lower_exp = NULL_RTX, upper_exp = NULL_RTX;
> +  unsigned lower_old, upper_old;
> +
> +  if (!compute_const_anchors (src_const, &lower_base, &lower_offs,
> +			      &upper_base, &upper_offs))
> +    return NULL_RTX;
> +
> +  lower_anchor_rtx = GEN_INT (lower_base);
> +  upper_anchor_rtx = GEN_INT (upper_base);
> +  lower_elt = lookup (lower_anchor_rtx, HASH (lower_anchor_rtx, mode),
> mode); +  upper_elt = lookup (upper_anchor_rtx, HASH (upper_anchor_rtx,
> mode), mode); +
> +  if (lower_elt)
> +    lower_exp = find_reg_offset_for_const (lower_elt, lower_offs,
> &lower_old); +  if (upper_elt)
> +    upper_exp = find_reg_offset_for_const (upper_elt, upper_offs,
> &upper_old); +
> +  if (!lower_exp)
> +    return upper_exp;
> +  if (!upper_exp)
> +    return lower_exp;
> +  /* Return the older expression.  */
> +  if (lower_old < upper_old)
> +    return upper_exp;
> +  return lower_exp;

  if (!lower_exp)
    return upper_exp;
  if (!upper_exp)
    return lower_exp;

  /* Return the older expression.  */
  return (upper_old > lower_old ? upper_exp : lower_exp);

>  

>  /* CSE processing for one instruction.
>     First simplify sources and addresses of all assignments
> @@ -4249,6 +4429,7 @@ cse_insn (rtx insn)
>        rtx src_eqv_here;
>        rtx src_const = 0;
>        rtx src_related = 0;
> +      bool src_related_is_const_anchor = false;
>        struct table_elt *src_const_elt = 0;
>        int src_cost = MAX_COST;
>        int src_eqv_cost = MAX_COST;
> @@ -4598,6 +4779,19 @@ cse_insn (rtx insn)
>  	}
>  #endif /* LOAD_EXTEND_OP */
>
> +      /* Try to express the constant using a register-offset expression
> +	 derived from a constant anchor.  */

register+offset :-)

> @@ -5436,6 +5642,14 @@ cse_insn (rtx insn)
>  	elt = insert (dest, sets[i].src_elt,
>  		      sets[i].dest_hash, GET_MODE (dest));
>
> +	/* If this is a constant, insert the constant anchors with the
> +	   equivalent register-offset expressions using register DEST.  */
> +	if (targetm.const_anchor
> +	    && REG_P (dest)
> +	    && SCALAR_INT_MODE_P (GET_MODE (dest))
> +	    && GET_CODE (sets[i].src_elt->exp) == CONST_INT)
> +	  insert_const_anchors (dest, sets[i].src_elt->exp, GET_MODE (dest));

Why not do that in insert instead? It does similar special processing already

-- 
Eric Botcazou



More information about the Gcc-patches mailing list