diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 9080f979bba5..046f93a8df28 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -771,11 +771,7 @@ hppa_legitimize_address (x, oldx, mode) return plus_constant (ptr_reg, offset - newoffset); } - /* Try to arrange things so that indexing modes can be used, but - only do so if indexing is safe. - - Indexing is safe when the second operand for the outer PLUS - is a REG, SUBREG, SYMBOL_REF or the like. */ + /* Handle (plus (mult (a) (shadd_constant)) (b)). */ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT @@ -786,66 +782,145 @@ hppa_legitimize_address (x, oldx, mode) { int val = INTVAL (XEXP (XEXP (x, 0), 1)); rtx reg1, reg2; - reg1 = force_reg (Pmode, force_operand (XEXP (x, 1), 0)); - reg2 = force_reg (Pmode, - force_operand (XEXP (XEXP (x, 0), 0), 0)); - return force_reg (Pmode, - gen_rtx (PLUS, Pmode, - gen_rtx (MULT, Pmode, reg2, - GEN_INT (val)), - reg1)); + + reg1 = XEXP (x, 1); + if (GET_CODE (reg1) != REG) + reg1 = force_reg (Pmode, force_operand (reg1, 0)); + + reg2 = XEXP (XEXP (x, 0), 0); + if (GET_CODE (reg2) != REG) + reg2 = force_reg (Pmode, force_operand (reg2, 0)); + + if (INTVAL (XEXP (XEXP (x, 0), 1)) != GET_MODE_SIZE (mode)) + { + reg2 = force_reg (Pmode, gen_rtx (MULT, Pmode, reg2, GEN_INT (val))); + return force_reg (Pmode, gen_rtx (PLUS, Pmode, reg1, reg2)); + } + + return force_reg (Pmode, gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, + reg2, GEN_INT (val)), + reg1)); } /* Similarly for (plus (plus (mult (a) (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 ((mode == DFmode || mode == SFmode) - && GET_CODE (x) == PLUS + 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 - && shadd_constant_p (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)))) + && shadd_constant_p (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))) + && (mode == SFmode || mode == DFmode)) { - rtx regx1, regx2; - /* Add the two unscaled terms B and C; if either B or C isn't - a register or small constant int, then fail. */ - regx1 = XEXP (XEXP (x, 0), 1); - if (! (GET_CODE (regx1) == REG - || (GET_CODE (regx1) == CONST_INT - && INT_14_BITS (regx1)))) + /* First, try and figure out what to use as a base register. */ + rtx reg1, reg2, base, idx, orig_base; + + reg1 = XEXP (XEXP (x, 0), 1); + reg2 = XEXP (x, 1); + base = NULL_RTX; + idx = NULL_RTX; + + /* Make sure they're both regs. If one was a SYMBOL_REF [+ const], + then emit_move_sequence will turn on REGNO_POINTER_FLAG so we'll + know it's a base register below. */ + 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)); + + /* Figure out what the base and index are. */ + + if (GET_CODE (reg1) == REG + && REGNO_POINTER_FLAG (REGNO (reg1))) + { + base = reg1; + orig_base = XEXP (XEXP (x, 0), 1); + idx = gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, + XEXP (XEXP (XEXP (x, 0), 0), 0), + XEXP (XEXP (XEXP (x, 0), 0), 1)), + XEXP (x, 1)); + } + else if (GET_CODE (reg2) == REG + && REGNO_POINTER_FLAG (REGNO (reg2))) + { + base = reg2; + orig_base = XEXP (x, 1); + idx = XEXP (x, 0); + } + + if (base == 0) return orig; + + /* If the index adds a large constant, try to scale the + constant so that it can be loaded with only one insn. */ + if (GET_CODE (XEXP (idx, 1)) == CONST_INT + && VAL_14_BITS_P (INTVAL (XEXP (idx, 1)) + / INTVAL (XEXP (XEXP (idx, 0), 1))) + && INTVAL (XEXP (idx, 1)) % INTVAL (XEXP (XEXP (idx, 0), 1)) == 0) + { + /* Divide the CONST_INT by the scale factor, then add it to A. */ + int val = INTVAL (XEXP (idx, 1)); + + 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)); + + reg1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, reg1, GEN_INT (val))); + + /* We can now generate a simple scaled indexed address. */ + return force_reg (Pmode, gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, reg1, + XEXP (XEXP (idx, 0), 1)), + base)); + } + + /* If B + C is still a valid base register, then add them. */ + if (GET_CODE (XEXP (idx, 1)) == CONST_INT + && 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))); + + reg2 = XEXP (XEXP (idx, 0), 0); + 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)); + } + + /* Get the index into a register, then add the base + index and + return a register holding the result. */ + + /* First get A into a register. */ + reg1 = XEXP (XEXP (idx, 0), 0); + if (GET_CODE (reg1) != REG) + reg1 = force_reg (Pmode, force_operand (reg1, 0)); + + /* And get B into a register. */ + reg2 = XEXP (idx, 1); + if (GET_CODE (reg2) != REG) + reg2 = force_reg (Pmode, force_operand (reg2, 0)); + + reg1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, + gen_rtx (MULT, Pmode, reg1, + XEXP (XEXP (idx, 0), 1)), + reg2)); + + /* Add the result to our base register and return. */ + return force_reg (Pmode, gen_rtx (PLUS, Pmode, base, reg1)); - regx2 = XEXP (x, 1); - if (! (GET_CODE (regx2) == REG - || (GET_CODE (regx2) == CONST_INT - && INT_14_BITS (regx2)))) - return orig; - - /* Add them, make sure the result is in canonical form. */ - if (GET_CODE (regx1) == REG) - regx1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, regx1, regx2)); - else if (GET_CODE (regx2) == REG) - regx1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, regx2, regx1)); - else - regx1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, - force_reg (Pmode, regx1), - regx2)); - - /* Get the term to scale in a register. */ - regx2 = XEXP (XEXP (XEXP (x, 0), 0), 0); - if (GET_CODE (regx2) != REG) - regx2 = force_reg (Pmode, force_operand (regx2, 0)); - - /* And make an indexed address. */ - regx2 = gen_rtx (PLUS, Pmode, - gen_rtx (MULT, Pmode, regx2, - XEXP (XEXP (XEXP (x, 0), 0), 1)), - regx1); - - /* Return it. */ - return force_reg (Pmode, regx2); } /* Uh-oh. We might have an address for x[n-100000]. This needs @@ -879,12 +954,42 @@ hppa_legitimize_address (x, oldx, mode) (plus (mult (reg) (shadd_const)) (const (plus (symbol_ref) (const_int)))) - Where const_int can be divided evenly by shadd_const and - added to (reg). This allows more scaled indexed addresses. */ - if ((mode == DFmode || mode == SFmode) - && GET_CODE (XEXP (y, 0)) == SYMBOL_REF + Where const_int is small. In that case the const + expression is a valid pointer for indexing. + + 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 && GET_CODE (XEXP (y, 1)) == CONST_INT - && INTVAL (XEXP (y, 1)) % INTVAL (XEXP (XEXP (x, 0), 1)) == 0) + && INTVAL (XEXP (y, 1)) >= -4096 + && INTVAL (XEXP (y, 1)) <= 4095 + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1)))) + { + int val = INTVAL (XEXP (XEXP (x, 0), 1)); + rtx reg1, reg2; + + reg1 = XEXP (x, 1); + if (GET_CODE (reg1) != REG) + reg1 = force_reg (Pmode, force_operand (reg1, 0)); + + reg2 = XEXP (XEXP (x, 0), 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)); + } + else if ((mode == DFmode || mode == SFmode) + && GET_CODE (XEXP (y, 0)) == SYMBOL_REF + && GET_CODE (XEXP (x, 0)) == MULT + && 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 + && shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1)))) { regx1 = force_reg (Pmode, GEN_INT (INTVAL (XEXP (y, 1)) diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index f9a3d938b8f3..f69102549277 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -1405,7 +1405,8 @@ extern struct rtx_def *hppa_builtin_saveregs (); ((C) == 'Q' ? \ (IS_RELOADING_PSEUDO_P (OP) \ || (GET_CODE (OP) == MEM \ - && memory_address_p (GET_MODE (OP), XEXP (OP, 0))\ + && (memory_address_p (GET_MODE (OP), XEXP (OP, 0))\ + || reload_in_progress) \ && ! symbolic_memory_operand (OP, VOIDmode) \ && !(GET_CODE (XEXP (OP, 0)) == PLUS \ && (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\ @@ -1416,7 +1417,8 @@ extern struct rtx_def *hppa_builtin_saveregs (); && (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT \ || GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT) \ && (move_operand (OP, GET_MODE (OP)) \ - || memory_address_p (GET_MODE (OP), XEXP (OP, 0))))\ + || memory_address_p (GET_MODE (OP), XEXP (OP, 0))\ + || reload_in_progress)) \ : ((C) == 'T' ? \ (GET_CODE (OP) == MEM \ /* Using DFmode forces only short displacements \ diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index de3b00103c5a..d881956490cb 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -1664,6 +1664,52 @@ (set (match_dup 0) (lo_sum:SI (match_dup 2) (match_dup 1)))] "") +;; hppa_legitimize_address goes to a great deal of trouble to +;; create addresses which use indexing. In some cases, this +;; is a lose because there isn't any store instructions which +;; allow indexed addresses (with integer register source). +;; +;; These define_splits try to turn a 3 insn store into +;; a 2 insn store with some creative RTL rewriting. +(define_split + [(set (mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "shadd_operand" "")) + (plus:SI (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "const_int_operand" "")))) + (match_operand:SI 4 "register_operand" "")) + (clobber (match_operand:SI 5 "register_operand" ""))] + "" + [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1)) + (match_dup 2))) + (set (mem:SI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))] + "") + +(define_split + [(set (mem:HI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "shadd_operand" "")) + (plus:SI (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "const_int_operand" "")))) + (match_operand:HI 4 "register_operand" "")) + (clobber (match_operand:SI 5 "register_operand" ""))] + "" + [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1)) + (match_dup 2))) + (set (mem:HI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))] + "") + +(define_split + [(set (mem:QI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "shadd_operand" "")) + (plus:SI (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "const_int_operand" "")))) + (match_operand:QI 4 "register_operand" "")) + (clobber (match_operand:SI 5 "register_operand" ""))] + "" + [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1)) + (match_dup 2))) + (set (mem:QI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))] + "") + (define_expand "movhi" [(set (match_operand:HI 0 "general_operand" "") (match_operand:HI 1 "general_operand" ""))]