--- * config/alpha/alpha.c: Include genimm-hash.h (genimm_alpha): New class. (genimm_alpha::genimm_alpha): New. (genimm_alpha::set0, genimm_alpha::opN): New. (genimm_alpha::exam_simple): New. (genimm_alpha::exam_sub): New. (genimm_alpha::exam_search): Extract from the body of the old alpha_emit_set_const_1. (genimm_alpha::exam_full): New. (genimm_alpha::exam_generate): New. (alpha_emit_set_const_1): Remove. (alpha_emit_set_const): Rewrite using genimm_hash. (alpha_legitimate_constant_p): Use alpha_emit_set_const. --- gcc/config/alpha/alpha.c | 497 ++++++++++++++++++++++++----------------------- 1 file changed, 250 insertions(+), 247 deletions(-)
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index ca07cc7..6933601 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -77,6 +77,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "builtins.h" #include "rtl-iter.h" +#include "genimm-hash.h" /* This file should be included last. */ #include "target-def.h" @@ -1726,249 +1727,277 @@ alpha_set_memflags (rtx seq, rtx ref) gcc_unreachable (); } -static rtx alpha_emit_set_const (rtx, machine_mode, HOST_WIDE_INT, - int, bool); +namespace { -/* Internal routine for alpha_emit_set_const to check for N or below insns. - If NO_OUTPUT is true, then we only check to see if N insns are possible, - and return pc_rtx if successful. */ +/* All constants can be constructed in 5 insns. */ +struct genimm_alpha : genimm_base<rtx_code, 5> +{ + static const int max_simple = 2; -static rtx -alpha_emit_set_const_1 (rtx target, machine_mode mode, - HOST_WIDE_INT c, int n, bool no_output) + genimm_alpha(HOST_WIDE_INT c); + void set0 (HOST_WIDE_INT o); + void opN (rtx_code r, HOST_WIDE_INT o); + + bool exam_simple (HOST_WIDE_INT c, machine_mode mode, int budget); + bool exam_sub (HOST_WIDE_INT c, int budget); + bool exam_search (HOST_WIDE_INT c, int budget); + void exam_full (HOST_WIDE_INT c); + void generate (rtx dest, machine_mode mode) const; +}; + +genimm_alpha::genimm_alpha (HOST_WIDE_INT c) + : genimm_base (c) { - HOST_WIDE_INT new_const; - int i, bits; - /* Use a pseudo if highly optimizing and still generating RTL. */ - rtx subtarget - = (flag_expensive_optimizations && can_create_pseudo_p () ? 0 : target); - rtx temp, insn; +#ifdef ENABLE_CHECKING + code[0] = code[1] = code[2] = code[3] = code[4] = UNKNOWN; + op[0] = op[1] = op[2] = op[3] = op[4] = 0; +#endif +} + +void +genimm_alpha::set0 (HOST_WIDE_INT o) +{ + cost = 1; + code[0] = SET; + op[0] = o; +} + +void +genimm_alpha::opN (rtx_code r, HOST_WIDE_INT o) +{ + int n = cost++; + gcc_checking_assert (n > 0 && n < max_cost); + code[n] = r; + op[n] = o; +} - /* If this is a sign-extended 32-bit constant, we can do this in at most - three insns, so do it if we have enough insns left. */ +/* Only handle simple one and two insn constants. */ - if (c >> 31 == -1 || c >> 31 == 0) +bool +genimm_alpha::exam_simple (HOST_WIDE_INT c, machine_mode mode, int budget) +{ + HOST_WIDE_INT lo = sext_hwi (c, 16); + HOST_WIDE_INT hi = sext_hwi (c - lo, 32); + + if (c == lo || c == hi) + { + set0 (c); + return true; + } + if (budget >= 2 && (c == hi + lo || mode == SImode)) { - HOST_WIDE_INT low = ((c & 0xffff) ^ 0x8000) - 0x8000; - HOST_WIDE_INT tmp1 = c - low; - HOST_WIDE_INT high = (((tmp1 >> 16) & 0xffff) ^ 0x8000) - 0x8000; - HOST_WIDE_INT extra = 0; + set0 (hi); + opN (PLUS, lo); + return true; + } + return false; +} - /* If HIGH will be interpreted as negative but the constant is - positive, we must adjust it to do two ldha insns. */ +bool +genimm_alpha::exam_sub (HOST_WIDE_INT c, int budget) +{ + return (exam_simple (c, DImode, budget) + || (budget > 1 && exam_search (c, budget))); +} - if ((high & 0x8000) != 0 && c >= 0) - { - extra = 0x4000; - tmp1 -= 0x40000000; - high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); - } +/* The body of the recursive search for C within BUDGET. + We've already failed exam_simple. */ - if (c == low || (low == 0 && extra == 0)) +bool +genimm_alpha::exam_search (HOST_WIDE_INT c, int budget) +{ + const int sub_budget = budget - 1; + HOST_WIDE_INT test; + + /* Simple subtractions. */ + test = sext_hwi (c, 16); + if (test != 0) + { + if (exam_sub (c - test, sub_budget)) { - /* We used to use copy_to_suggested_reg (GEN_INT (c), target, mode) - but that meant that we can't handle INT_MIN on 32-bit machines - (like NT/Alpha), because we recurse indefinitely through - emit_move_insn to gen_movdi. So instead, since we know exactly - what we want, create it explicitly. */ - - if (no_output) - return pc_rtx; - if (target == NULL) - target = gen_reg_rtx (mode); - emit_insn (gen_rtx_SET (target, GEN_INT (c))); - return target; + opN (PLUS, test); + return true; } - else if (n >= 2 + (extra != 0)) + /* Note that it doesn't help to try LDAH at this point. + Zeroing bits in the middle of C when we know there + are low bits set doesn't produce a simpler constant. */ + } + else + { + test = sext_hwi (c, 32); + if (test != 0) { - if (no_output) - return pc_rtx; - if (!can_create_pseudo_p ()) + if (exam_sub (c - test, sub_budget)) { - emit_insn (gen_rtx_SET (target, GEN_INT (high << 16))); - temp = target; + opN (PLUS, test); + return true; } - else - temp = copy_to_suggested_reg (GEN_INT (high << 16), - subtarget, mode); - /* As of 2002-02-23, addsi3 is only available when not optimizing. - This means that if we go through expand_binop, we'll try to - generate extensions, etc, which will require new pseudos, which - will fail during some split phases. The SImode add patterns - still exist, but are not named. So build the insns by hand. */ - - if (extra != 0) + /* Form constants between 0x80000000 - 0xfffe0000 by splitting + the LDAH into two. The ordering of operations here should + prefer to load 0x7fff0000 into a register first, which would + then be sharable by other constant loading sequences. */ + HOST_WIDE_INT uhi = c & HOST_WIDE_INT_UC (0xffff0000); + test = 0x7fff0000; + if (uhi == c && uhi - test <= test) { - if (! subtarget) - subtarget = gen_reg_rtx (mode); - insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16)); - insn = gen_rtx_SET (subtarget, insn); - emit_insn (insn); - temp = subtarget; + set0 (test); + opN (PLUS, uhi - test); + return true; } - - if (target == NULL) - target = gen_reg_rtx (mode); - insn = gen_rtx_PLUS (mode, temp, GEN_INT (low)); - insn = gen_rtx_SET (target, insn); - emit_insn (insn); - return target; } } - /* If we couldn't do it that way, try some other methods. But if we have - no instructions left, don't bother. Likewise, if this is SImode and - we can't make pseudos, we can't do anything since the expand_binop - and expand_unop calls will widen and try to make pseudos. */ - - if (n == 1 || (mode == SImode && !can_create_pseudo_p ())) - return 0; - - /* Next, see if we can load a related constant and then shift and possibly - negate it to get the constant we want. Try this once each increasing - numbers of insns. */ + /* Try complimenting. */ + if (exam_sub (~c, sub_budget)) + { + opN (NOT, 0); + return true; + } - for (i = 1; i < n; i++) + /* Try to form a constant and do a left shift. We can do this + if some low-order bits are zero. The bits we are shifting out + could be any value, but here we'll just try the zero- and sign- + extended forms of the constant. To try to increase the chance + of having the same constant in more than one insn, start at the + highest number of bits to shift, but try all possibilities in + case a ZAPNOT will be useful. */ + for (int bits = ctz_hwi (c); bits > 0; --bits) { - /* First, see if minus some low bits, we've an easy load of - high bits. */ + /* First try with ones being shifted out. */ + test = c >> bits; + bool ok = exam_sub (test, sub_budget); + if (!ok && c < 0) + { + /* If that failed, try with zeros being shifted out. */ + test = (unsigned HOST_WIDE_INT)c >> bits; + ok = exam_sub (test, sub_budget); + } + if (ok) + { + opN (ASHIFT, bits); + return true; + } + } - new_const = ((c & 0xffff) ^ 0x8000) - 0x8000; - if (new_const != 0) + /* Try a right shift, shifting in zeros. */ + for (int bits = clz_hwi (c); bits > 0; --bits) + { + test = c << bits; + bool ok = exam_sub (test, sub_budget); + if (!ok) { - temp = alpha_emit_set_const (subtarget, mode, c - new_const, i, no_output); - if (temp) - { - if (no_output) - return temp; - return expand_binop (mode, add_optab, temp, GEN_INT (new_const), - target, 0, OPTAB_WIDEN); - } + test |= (HOST_WIDE_INT_1U << bits) - 1; + ok = exam_sub (test, sub_budget); + } + if (ok) + { + opN (LSHIFTRT, bits); + return true; } + } - /* Next try complementing. */ - temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output); - if (temp) + /* Try a right shift, shifting in ones. */ + for (int bits = clz_hwi (~c) - 1; bits > 0; --bits) + { + test = c << bits; + bool ok = exam_sub (test, sub_budget); + if (!ok) { - if (no_output) - return temp; - return expand_unop (mode, one_cmpl_optab, temp, target, 0); + test |= (HOST_WIDE_INT_1U << bits) - 1; + ok = exam_sub (test, sub_budget); } + if (ok) + { + opN (ASHIFTRT, bits); + return true; + } + } - /* Next try to form a constant and do a left shift. We can do this - if some low-order bits are zero; the exact_log2 call below tells - us that information. The bits we are shifting out could be any - value, but here we'll just try the 0- and sign-extended forms of - the constant. To try to increase the chance of having the same - constant in more than one insn, start at the highest number of - bits to shift, but try all possibilities in case a ZAPNOT will - be useful. */ - - bits = exact_log2 (c & -c); - if (bits > 0) - for (; bits > 0; bits--) - { - new_const = c >> bits; - temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); - if (!temp && c < 0) - { - new_const = (unsigned HOST_WIDE_INT)c >> bits; - temp = alpha_emit_set_const (subtarget, mode, new_const, - i, no_output); - } - if (temp) - { - if (no_output) - return temp; - return expand_binop (mode, ashl_optab, temp, GEN_INT (bits), - target, 0, OPTAB_WIDEN); - } - } + /* Try loading a value and zapping bytes. */ + test = c; + for (int i = 0; i < 64; i += 8) + { + HOST_WIDE_INT byte = HOST_WIDE_INT_UC (0xff) << i; + if ((c & byte) == 0) + test |= byte; + } + if (test != c && exam_sub (test, sub_budget)) + { + opN (AND, c | ~test); + return true; + } - /* Now try high-order zero bits. Here we try the shifted-in bits as - all zero and all ones. Be careful to avoid shifting outside the - mode and to avoid shifting outside the host wide int size. */ + return false; +} - bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) - - floor_log2 (c) - 1); - if (bits > 0) - for (; bits > 0; bits--) - { - new_const = c << bits; - temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); - if (!temp) - { - new_const = (c << bits) | ((HOST_WIDE_INT_1U << bits) - 1); - temp = alpha_emit_set_const (subtarget, mode, new_const, - i, no_output); - } - if (temp) - { - if (no_output) - return temp; - return expand_binop (mode, lshr_optab, temp, GEN_INT (bits), - target, 1, OPTAB_WIDEN); - } - } +/* Only handle full 64-bit constants requiring 5 insns. */ - /* Now try high-order 1 bits. We get that with a sign-extension. - But one bit isn't enough here. Be careful to avoid shifting outside - the mode and to avoid shifting outside the host wide int size. */ +void +genimm_alpha::exam_full (HOST_WIDE_INT c) +{ + HOST_WIDE_INT lo = sext_hwi (c, 16); + HOST_WIDE_INT hi = sext_hwi (c - lo, 32); - bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) - - floor_log2 (~ c) - 2); - if (bits > 0) - for (; bits > 0; bits--) - { - new_const = c << bits; - temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); - if (!temp) - { - new_const = (c << bits) | ((HOST_WIDE_INT_1U << bits) - 1); - temp = alpha_emit_set_const (subtarget, mode, new_const, - i, no_output); - } - if (temp) - { - if (no_output) - return temp; - return expand_binop (mode, ashr_optab, temp, GEN_INT (bits), - target, 0, OPTAB_WIDEN); - } - } - } + bool ok = exam_simple ((c - hi - lo) >> 32, DImode, max_simple); + gcc_assert (ok); - /* Finally, see if can load a value into the target that is the same as the - constant except that all bytes that are 0 are changed to be 0xff. If we - can, then we can do a ZAPNOT to obtain the desired constant. */ + opN (ASHIFT, 32); + if (hi) + opN (PLUS, hi); + if (lo) + opN (PLUS, lo); +} - new_const = c; - for (i = 0; i < 64; i += 8) - if ((new_const & ((HOST_WIDE_INT) 0xff << i)) == 0) - new_const |= (HOST_WIDE_INT) 0xff << i; +/* Emit insns for the generated recipe. */ - /* We are only called for SImode and DImode. If this is SImode, ensure that - we are sign extended to a full word. */ +void +genimm_alpha::generate (rtx dest, machine_mode mode) const +{ + bool do_subtargets = optimize && can_create_pseudo_p (); + rtx op1 = NULL; + rtx_insn *insn = NULL; + int i, n = cost; - if (mode == SImode) - new_const = ((new_const & 0xffffffff) ^ 0x80000000) - 0x80000000; + gcc_checking_assert (n >= 1 && n <= max_cost); + gcc_checking_assert (code[0] == SET); - if (new_const != c) + for (i = 0; i < n; ++i) { - temp = alpha_emit_set_const (subtarget, mode, new_const, n - 1, no_output); - if (temp) + rtx sub = (do_subtargets && i + 1 < n ? gen_reg_rtx (mode) : dest); + rtx op2 = GEN_INT (op[i]); + rtx_code r = code[i]; + rtx x; + + switch (r) { - if (no_output) - return temp; - return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new_const), - target, 0, OPTAB_WIDEN); + case SET: + x = op2; + break; + case AND: + case PLUS: + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + x = gen_rtx_fmt_ee (r, mode, op1, op2); + break; + case NOT: + x = gen_rtx_fmt_e (r, mode, op1); + break; + default: + gcc_unreachable (); } + + insn = emit_insn (gen_rtx_SET (sub, x)); + op1 = sub; } - return 0; + if (n > 1) + set_unique_reg_note (insn, REG_EQUAL, GEN_INT (value)); } +} // anon namespace + /* Try to output insns to set TARGET equal to the constant C if it can be done in less than N insns. Do all computations in MODE. Returns the place where the output has been placed if it can be done and the insns have been @@ -1976,62 +2005,36 @@ alpha_emit_set_const_1 (rtx target, machine_mode mode, insns and emitted. */ static rtx -alpha_emit_set_const (rtx target, machine_mode mode, +alpha_emit_set_const (rtx target, machine_mode origmode, HOST_WIDE_INT c, int n, bool no_output) { - machine_mode orig_mode = mode; - rtx orig_target = target; - rtx result = 0; - int i; + machine_mode mode = origmode; + if (mode == V8QImode || mode == V4HImode || mode == V2SImode) + mode = DImode; - /* If we can't make any pseudos, TARGET is an SImode hard register, we - can't load this constant in one insn, do this in DImode. */ - if (!can_create_pseudo_p () && mode == SImode - && REG_P (target) && REGNO (target) < FIRST_PSEUDO_REGISTER) - { - result = alpha_emit_set_const_1 (target, mode, c, 1, no_output); - if (result) - return result; + genimm_alpha data = genimm_hash<genimm_alpha>::hash (c, mode); + if (data.cost > n) + return NULL; - target = no_output ? NULL : gen_lowpart (DImode, target); - mode = DImode; - } - else if (mode == V8QImode || mode == V4HImode || mode == V2SImode) - { - target = no_output ? NULL : gen_lowpart (DImode, target); - mode = DImode; - } + /* If we're not emitting output, we only need return a nonnull value. */ + if (no_output) + return pc_rtx; - /* Try 1 insn, then 2, then up to N. */ - for (i = 1; i <= n; i++) + if (origmode == mode) + data.generate (target, mode); + else { - result = alpha_emit_set_const_1 (target, mode, c, i, no_output); - if (result) + rtx low = gen_lowpart (mode, target); + if (can_create_pseudo_p ()) { - rtx_insn *insn; - rtx set; - - if (no_output) - return result; - - insn = get_last_insn (); - set = single_set (insn); - if (! CONSTANT_P (SET_SRC (set))) - set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c)); - break; + target = gen_reg_rtx (mode); + data.generate (target, mode); + emit_move_insn (low, target); } + else + data.generate (low, mode); } - - /* Allow for the case where we changed the mode of TARGET. */ - if (result) - { - if (result == target) - result = orig_target; - else if (mode != orig_mode) - result = gen_lowpart (orig_mode, result); - } - - return result; + return target; } /* Having failed to find a 3 insn sequence in alpha_emit_set_const, @@ -2129,7 +2132,7 @@ alpha_legitimate_constant_p (machine_mode mode, rtx x) mode = DImode; gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2); i0 = CONST_WIDE_INT_ELT (x, 1); - if (alpha_emit_set_const_1 (NULL_RTX, mode, i0, 3, true) == NULL) + if (alpha_emit_set_const (NULL_RTX, mode, i0, 3, true) == NULL) return false; i0 = CONST_WIDE_INT_ELT (x, 0); goto do_integer; @@ -2153,7 +2156,7 @@ alpha_legitimate_constant_p (machine_mode mode, rtx x) return true; i0 = alpha_extract_integer (x); do_integer: - return alpha_emit_set_const_1 (NULL_RTX, mode, i0, 3, true) != NULL; + return alpha_emit_set_const (NULL_RTX, mode, i0, 3, true) != NULL; default: return false; -- 2.4.3