return ret;
}
+/* Helper for hppa_legitimize_address. Given X, return true if it
+ is a left shift by 1, 2 or 3 positions or a multiply by 2, 4 or 8.
+
+ This respectively represent canonical shift-add rtxs or scaled
+ memory addresses. */
+static bool
+mem_shadd_or_shadd_rtx_p (rtx x)
+{
+ return ((GET_CODE (x) == ASHIFT
+ || GET_CODE (x) == MULT)
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && ((GET_CODE (x) == ASHIFT
+ && pa_shadd_constant_p (INTVAL (XEXP (x, 1))))
+ || (GET_CODE (x) == MULT
+ && pa_mem_shadd_constant_p (INTVAL (XEXP (x, 1))))));
+}
+
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
manner if Y is 2, 4, or 8. (allows more shadd insns and shifted indexed
addressing modes to be used).
+ Note that the addresses passed into hppa_legitimize_address always
+ come from a MEM, so we only have to match the MULT form on incoming
+ addresses. But to be future proof we also match the ASHIFT form.
+
+ However, this routine always places those shift-add sequences into
+ registers, so we have to generate the ASHIFT form as our output.
+
Put X and Z into registers. Then put the entire expression into
a register. */
return plus_constant (Pmode, ptr_reg, offset - newoffset);
}
- /* Handle (plus (mult (a) (shadd_constant)) (b)). */
+ /* Handle (plus (mult (a) (mem_shadd_constant)) (b)). */
- if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && pa_shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1)))
+ if (GET_CODE (x) == PLUS
+ && mem_shadd_or_shadd_rtx_p (XEXP (x, 0))
&& (OBJECT_P (XEXP (x, 1))
|| GET_CODE (XEXP (x, 1)) == SUBREG)
&& GET_CODE (XEXP (x, 1)) != CONST)
{
- int val = INTVAL (XEXP (XEXP (x, 0), 1));
- rtx reg1, reg2;
+ /* If we were given a MULT, we must fix the constant
+ as we're going to create the ASHIFT form. */
+ int shift_val = INTVAL (XEXP (XEXP (x, 0), 1));
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ shift_val = exact_log2 (shift_val);
+ rtx reg1, reg2;
reg1 = XEXP (x, 1);
if (GET_CODE (reg1) != REG)
reg1 = force_reg (Pmode, force_operand (reg1, 0));
if (GET_CODE (reg2) != REG)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
- return force_reg (Pmode, gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode,
- reg2,
- GEN_INT (val)),
- reg1));
+ return force_reg (Pmode,
+ gen_rtx_PLUS (Pmode,
+ gen_rtx_ASHIFT (Pmode, reg2,
+ GEN_INT (shift_val)),
+ reg1));
}
- /* Similarly for (plus (plus (mult (a) (shadd_constant)) (b)) (c)).
+ /* Similarly for (plus (plus (mult (a) (mem_shadd_constant)) (b)) (c)).
Only do so for floating point modes since this is more speculative
and we lose if it's an integer store. */
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
- && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
- && pa_shadd_constant_p (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)))
+ && mem_shadd_or_shadd_rtx_p (XEXP (XEXP (x, 0), 0))
&& (mode == SFmode || mode == DFmode))
{
+ int shift_val = INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1));
+
+ /* If we were given a MULT, we must fix the constant
+ as we're going to create the ASHIFT form. */
+ if (GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT)
+ shift_val = exact_log2 (shift_val);
- /* First, try and figure out what to use as a base register. */
+ /* Try and figure out what to use as a base register. */
rtx reg1, reg2, base, idx;
reg1 = XEXP (XEXP (x, 0), 1);
{
base = reg1;
idx = gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode,
- XEXP (XEXP (XEXP (x, 0), 0), 0),
- XEXP (XEXP (XEXP (x, 0), 0), 1)),
+ gen_rtx_ASHIFT (Pmode,
+ XEXP (XEXP (XEXP (x, 0), 0), 0),
+ GEN_INT (shift_val)),
XEXP (x, 1));
}
else if (GET_CODE (reg2) == REG
{
/* Divide the CONST_INT by the scale factor, then add it to A. */
int val = INTVAL (XEXP (idx, 1));
+ val /= (1 << shift_val);
- val /= INTVAL (XEXP (XEXP (idx, 0), 1));
reg1 = XEXP (XEXP (idx, 0), 0);
if (GET_CODE (reg1) != REG)
reg1 = force_reg (Pmode, force_operand (reg1, 0));
return
force_reg
(Pmode, gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode, reg1,
- XEXP (XEXP (idx, 0), 1)),
+ gen_rtx_ASHIFT (Pmode, reg1,
+ GEN_INT (shift_val)),
base));
}
&& INTVAL (XEXP (idx, 1)) <= 4096
&& INTVAL (XEXP (idx, 1)) >= -4096)
{
- int val = INTVAL (XEXP (XEXP (idx, 0), 1));
rtx reg1, reg2;
reg1 = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, XEXP (idx, 1)));
if (GET_CODE (reg2) != CONST_INT)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
- return force_reg (Pmode, gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode,
- reg2,
- GEN_INT (val)),
- reg1));
+ return force_reg (Pmode,
+ gen_rtx_PLUS (Pmode,
+ gen_rtx_ASHIFT (Pmode, reg2,
+ GEN_INT (shift_val)),
+ reg1));
}
/* Get the index into a register, then add the base + index and
reg1 = force_reg (Pmode,
gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode, reg1,
- XEXP (XEXP (idx, 0), 1)),
+ gen_rtx_ASHIFT (Pmode, reg1,
+ GEN_INT (shift_val)),
reg2));
/* Add the result to our base register and return. */
if (GET_CODE (y) == PLUS || GET_CODE (y) == MINUS)
{
/* See if this looks like
- (plus (mult (reg) (shadd_const))
+ (plus (mult (reg) (mem_shadd_const))
(const (plus (symbol_ref) (const_int))))
Where const_int is small. In that case the const
If const_int is big, but can be divided evenly by shadd_const
and added to (reg). This allows more scaled indexed addresses. */
if (GET_CODE (XEXP (y, 0)) == SYMBOL_REF
- && GET_CODE (XEXP (x, 0)) == MULT
+ && mem_shadd_or_shadd_rtx_p (XEXP (x, 0))
&& GET_CODE (XEXP (y, 1)) == CONST_INT
&& INTVAL (XEXP (y, 1)) >= -4096
- && INTVAL (XEXP (y, 1)) <= 4095
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && pa_shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
+ && INTVAL (XEXP (y, 1)) <= 4095)
{
- int val = INTVAL (XEXP (XEXP (x, 0), 1));
+ int shift_val = INTVAL (XEXP (XEXP (x, 0), 1));
+
+ /* If we were given a MULT, we must fix the constant
+ as we're going to create the ASHIFT form. */
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ shift_val = exact_log2 (shift_val);
+
rtx reg1, reg2;
reg1 = XEXP (x, 1);
if (GET_CODE (reg2) != REG)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
- return force_reg (Pmode,
- gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode,
- reg2,
- GEN_INT (val)),
- reg1));
+ return
+ force_reg (Pmode,
+ gen_rtx_PLUS (Pmode,
+ gen_rtx_ASHIFT (Pmode,
+ reg2,
+ GEN_INT (shift_val)),
+ reg1));
}
else if ((mode == DFmode || mode == SFmode)
&& GET_CODE (XEXP (y, 0)) == SYMBOL_REF
- && GET_CODE (XEXP (x, 0)) == MULT
+ && mem_shadd_or_shadd_rtx_p (XEXP (x, 0))
&& GET_CODE (XEXP (y, 1)) == CONST_INT
- && INTVAL (XEXP (y, 1)) % INTVAL (XEXP (XEXP (x, 0), 1)) == 0
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && pa_shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
+ && INTVAL (XEXP (y, 1)) % (1 << INTVAL (XEXP (XEXP (x, 0), 1))) == 0)
{
+ int shift_val = INTVAL (XEXP (XEXP (x, 0), 1));
+
+ /* If we were given a MULT, we must fix the constant
+ as we're going to create the ASHIFT form. */
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ shift_val = exact_log2 (shift_val);
+
regx1
= force_reg (Pmode, GEN_INT (INTVAL (XEXP (y, 1))
/ INTVAL (XEXP (XEXP (x, 0), 1))));
return
force_reg (Pmode,
gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode, regx2,
- XEXP (XEXP (x, 0), 1)),
+ gen_rtx_ASHIFT (Pmode, regx2,
+ GEN_INT (shift_val)),
force_reg (Pmode, XEXP (y, 0))));
}
else if (GET_CODE (XEXP (y, 1)) == CONST_INT