From: Richard Henderson Date: Thu, 20 Jan 2005 03:59:00 +0000 (-0800) Subject: re PR target/19518 ([alpha] unrecognizable insn (set (reg:V4HI) (const_vector:V4HI... X-Git-Tag: releases/gcc-4.0.0~1429 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=72910a0b3b6c68d3ca4d636b9a06923c07a45df8;p=thirdparty%2Fgcc.git re PR target/19518 ([alpha] unrecognizable insn (set (reg:V4HI) (const_vector:V4HI)) with builtins) PR target/19518 * config/alpha/alpha.c (alpha_rtx_costs): Handle HIGH. (alpha_preferred_reload_class): Handle CONST_VECTOR. (alpha_emit_set_const_1): Add no_output parameter; don't emit rtl if true. (alpha_emit_set_const): Likewise. Make static. (alpha_emit_set_long_const): Make static. (alpha_extract_integer): Split out from alpha_expand_mov. (alpha_split_const_mov): Likewise. (alpha_expand_mov): Use them. Handle CONST_VECTOR. (alpha_legitimate_constant_p): New. * config/alpha/alpha-protos.h: Update. * config/alpha/alpha.h (REGISTER_MOVE_COST): Correct fp<->gp cost. (LEGITIMATE_CONSTANT_P): Re-implement with a function. * config/alpha/alpha.md (movsi): Add n alternative. (movsi_nt_vms, movdi_er_nofix, movdi_er_fix, movdi_fix): Likewise. (mov_fix, mov_nofix): Add i alternative. (splitters for all of the above): Use alpha_split_const_mov. * config/alpha/predicates.md (non_add_const_operand): New. (non_zero_const_operand): New. (input_operand): Use alpha_legitimate_constant_p after reload. From-SVN: r93943 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5141fc03c8cb..540ad52fe061 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2005-01-19 Richard Henderson + + PR target/19518 + * config/alpha/alpha.c (alpha_rtx_costs): Handle HIGH. + (alpha_preferred_reload_class): Handle CONST_VECTOR. + (alpha_emit_set_const_1): Add no_output parameter; don't emit + rtl if true. + (alpha_emit_set_const): Likewise. Make static. + (alpha_emit_set_long_const): Make static. + (alpha_extract_integer): Split out from alpha_expand_mov. + (alpha_split_const_mov): Likewise. + (alpha_expand_mov): Use them. Handle CONST_VECTOR. + (alpha_legitimate_constant_p): New. + * config/alpha/alpha-protos.h: Update. + * config/alpha/alpha.h (REGISTER_MOVE_COST): Correct fp<->gp cost. + (LEGITIMATE_CONSTANT_P): Re-implement with a function. + * config/alpha/alpha.md (movsi): Add n alternative. + (movsi_nt_vms, movdi_er_nofix, movdi_er_fix, movdi_fix): Likewise. + (mov_fix, mov_nofix): Add i alternative. + (splitters for all of the above): Use alpha_split_const_mov. + * config/alpha/predicates.md (non_add_const_operand): New. + (non_zero_const_operand): New. + (input_operand): Use alpha_legitimate_constant_p after reload. + 2005-01-19 Zdenek Dvorak PR tree-optimization/19038 diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index 24f24e6b2bf1..d1ffada3dcfa 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -42,6 +42,7 @@ extern bool alpha_extra_constraint (rtx, int); extern rtx alpha_tablejump_addr_vec (rtx); extern rtx alpha_tablejump_best_label (rtx); +extern bool alpha_legitimate_constant_p (rtx); extern bool alpha_legitimate_address_p (enum machine_mode, rtx, int); extern rtx alpha_legitimize_address (rtx, rtx, enum machine_mode); extern rtx alpha_legitimize_reload_address (rtx, enum machine_mode, @@ -56,8 +57,7 @@ extern enum reg_class secondary_reload_class (enum reg_class, enum machine_mode, rtx, int); extern void alpha_set_memflags (rtx, rtx); -extern rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT, int); -extern rtx alpha_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT); +extern bool alpha_split_const_mov (enum machine_mode, rtx *); extern bool alpha_expand_mov (enum machine_mode, rtx *); extern bool alpha_expand_mov_nobwx (enum machine_mode, rtx *); extern void alpha_expand_movmisalign (enum machine_mode, rtx *); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index aed7ada56190..037dc4ad33e7 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -1384,6 +1384,11 @@ alpha_rtx_costs (rtx x, int code, int outer_code, int *total) *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency); return true; + case HIGH: + /* This is effectively an add_operand. */ + *total = 2; + return true; + case PLUS: case MINUS: if (float_mode_p) @@ -1557,7 +1562,9 @@ alpha_preferred_reload_class(rtx x, enum reg_class class) return class; /* These sorts of constants we can easily drop to memory. */ - if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) + if (GET_CODE (x) == CONST_INT + || GET_CODE (x) == CONST_DOUBLE + || GET_CODE (x) == CONST_VECTOR) { if (class == FLOAT_REGS) return NO_REGS; @@ -1679,11 +1686,16 @@ alpha_set_memflags (rtx insn, rtx ref) for_each_rtx (base_ptr, alpha_set_memflags_1, (void *) ref); } -/* Internal routine for alpha_emit_set_const to check for N or below insns. */ +static rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT, + int, bool); + +/* 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. */ static rtx alpha_emit_set_const_1 (rtx target, enum machine_mode mode, - HOST_WIDE_INT c, int n) + HOST_WIDE_INT c, int n, bool no_output) { HOST_WIDE_INT new; int i, bits; @@ -1722,6 +1734,8 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode, 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 (VOIDmode, target, GEN_INT (c))); @@ -1729,6 +1743,8 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode, } else if (n >= 2 + (extra != 0)) { + if (no_output) + return pc_rtx; if (no_new_pseudos) { emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (high << 16))); @@ -1781,14 +1797,26 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode, high bits. */ new = ((c & 0xffff) ^ 0x8000) - 0x8000; - if (new != 0 - && (temp = alpha_emit_set_const (subtarget, mode, c - new, i)) != 0) - return expand_binop (mode, add_optab, temp, GEN_INT (new), - target, 0, OPTAB_WIDEN); + if (new != 0) + { + temp = alpha_emit_set_const (subtarget, mode, c - new, i, no_output); + if (temp) + { + if (no_output) + return temp; + return expand_binop (mode, add_optab, temp, GEN_INT (new), + target, 0, OPTAB_WIDEN); + } + } /* Next try complementing. */ - if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0) - return expand_unop (mode, one_cmpl_optab, temp, target, 0); + temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output); + if (temp) + { + if (no_output) + return temp; + return expand_unop (mode, one_cmpl_optab, temp, target, 0); + } /* 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 @@ -1799,16 +1827,26 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode, bits to shift, but try all possibilities in case a ZAPNOT will be useful. */ - if ((bits = exact_log2 (c & - c)) > 0) + bits = exact_log2 (c & -c); + if (bits > 0) for (; bits > 0; bits--) - if ((temp = (alpha_emit_set_const - (subtarget, mode, c >> bits, i))) != 0 - || ((temp = (alpha_emit_set_const - (subtarget, mode, - ((unsigned HOST_WIDE_INT) c) >> bits, i))) - != 0)) - return expand_binop (mode, ashl_optab, temp, GEN_INT (bits), - target, 0, OPTAB_WIDEN); + { + new = c >> bits; + temp = alpha_emit_set_const (subtarget, mode, new, i, no_output); + if (!temp && c < 0) + { + new = (unsigned HOST_WIDE_INT)c >> bits; + temp = alpha_emit_set_const (subtarget, mode, new, + i, no_output); + } + if (temp) + { + if (no_output) + return temp; + return expand_binop (mode, ashl_optab, temp, GEN_INT (bits), + target, 0, OPTAB_WIDEN); + } + } /* 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 @@ -1816,35 +1854,53 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode, /* On narrow hosts, don't shift a 1 into the high bit, since we'll confuse the recursive call and set all of the high 32 bits. */ - if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) - - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64))) > 0) + bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) + - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64)); + if (bits > 0) for (; bits > 0; bits--) - if ((temp = alpha_emit_set_const (subtarget, mode, - c << bits, i)) != 0 - || ((temp = (alpha_emit_set_const - (subtarget, mode, - ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)), - i))) - != 0)) - return expand_binop (mode, lshr_optab, temp, GEN_INT (bits), - target, 1, OPTAB_WIDEN); + { + new = c << bits; + temp = alpha_emit_set_const (subtarget, mode, new, i, no_output); + if (!temp) + { + new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1); + temp = alpha_emit_set_const (subtarget, mode, new, + i, no_output); + } + if (temp) + { + if (no_output) + return temp; + return expand_binop (mode, lshr_optab, temp, GEN_INT (bits), + target, 1, OPTAB_WIDEN); + } + } /* 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. */ - if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) - - floor_log2 (~ c) - 2)) > 0) + bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) + - floor_log2 (~ c) - 2); + if (bits > 0) for (; bits > 0; bits--) - if ((temp = alpha_emit_set_const (subtarget, mode, - c << bits, i)) != 0 - || ((temp = (alpha_emit_set_const - (subtarget, mode, - ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)), - i))) - != 0)) - return expand_binop (mode, ashr_optab, temp, GEN_INT (bits), - target, 0, OPTAB_WIDEN); + { + new = c << bits; + temp = alpha_emit_set_const (subtarget, mode, new, i, no_output); + if (!temp) + { + new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1); + temp = alpha_emit_set_const (subtarget, mode, new, + i, no_output); + } + if (temp) + { + if (no_output) + return temp; + return expand_binop (mode, ashr_optab, temp, GEN_INT (bits), + target, 0, OPTAB_WIDEN); + } + } } #if HOST_BITS_PER_WIDE_INT == 64 @@ -1863,10 +1919,17 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode, if (mode == SImode) new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000; - if (new != c && new != -1 - && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0) - return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new), - target, 0, OPTAB_WIDEN); + if (new != c) + { + temp = alpha_emit_set_const (subtarget, mode, new, n - 1, no_output); + if (temp) + { + if (no_output) + return temp; + return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new), + target, 0, OPTAB_WIDEN); + } + } #endif return 0; @@ -1878,32 +1941,46 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode, emitted. If it would take more than N insns, zero is returned and no insns and emitted. */ -rtx +static rtx alpha_emit_set_const (rtx target, enum machine_mode mode, - HOST_WIDE_INT c, int n) + HOST_WIDE_INT c, int n, bool no_output) { - rtx result = 0; + enum machine_mode orig_mode = mode; rtx orig_target = target; + rtx result = 0; int i; /* 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 (no_new_pseudos && mode == SImode - && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER - && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0) + && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER) + { + result = alpha_emit_set_const_1 (target, mode, c, 1, no_output); + if (result) + return result; + + target = no_output ? NULL : gen_lowpart (DImode, target); + mode = DImode; + } + else if (mode == V8QImode || mode == V4HImode || mode == V2SImode) { - target = gen_lowpart (DImode, target); + target = no_output ? NULL : gen_lowpart (DImode, target); mode = DImode; } /* Try 1 insn, then 2, then up to N. */ for (i = 1; i <= n; i++) { - result = alpha_emit_set_const_1 (target, mode, c, i); + result = alpha_emit_set_const_1 (target, mode, c, i, no_output); if (result) { - rtx insn = get_last_insn (); - rtx set = single_set (insn); + rtx insn, 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; @@ -1911,8 +1988,13 @@ alpha_emit_set_const (rtx target, enum machine_mode mode, } /* Allow for the case where we changed the mode of TARGET. */ - if (result == target) - result = orig_target; + if (result) + { + if (result == target) + result = orig_target; + else if (mode != orig_mode) + result = gen_lowpart (orig_mode, result); + } return result; } @@ -1922,7 +2004,7 @@ alpha_emit_set_const (rtx target, enum machine_mode mode, exponential run times encountered when looking for longer sequences with alpha_emit_set_const. */ -rtx +static rtx alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2) { HOST_WIDE_INT d1, d2, d3, d4; @@ -1976,6 +2058,114 @@ alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2) return target; } +/* Given an integral CONST_INT, CONST_DOUBLE, or CONST_VECTOR, return + the low 64 bits. */ + +static void +alpha_extract_integer (rtx x, HOST_WIDE_INT *p0, HOST_WIDE_INT *p1) +{ + HOST_WIDE_INT i0, i1; + + if (GET_CODE (x) == CONST_VECTOR) + x = simplify_subreg (DImode, x, GET_MODE (x), 0); + + + if (GET_CODE (x) == CONST_INT) + { + i0 = INTVAL (x); + i1 = -(i0 < 0); + } + else if (HOST_BITS_PER_WIDE_INT >= 64) + { + i0 = CONST_DOUBLE_LOW (x); + i1 = -(i0 < 0); + } + else + { + i0 = CONST_DOUBLE_LOW (x); + i1 = CONST_DOUBLE_HIGH (x); + } + + *p0 = i0; + *p1 = i1; +} + +/* Implement LEGITIMATE_CONSTANT_P. This is all constants for which we + are willing to load the value into a register via a move pattern. + Normally this is all symbolic constants, integral constants that + take three or fewer instructions, and floating-point zero. */ + +bool +alpha_legitimate_constant_p (rtx x) +{ + enum machine_mode mode = GET_MODE (x); + HOST_WIDE_INT i0, i1; + + switch (GET_CODE (x)) + { + case CONST: + case LABEL_REF: + case SYMBOL_REF: + case HIGH: + return true; + + case CONST_DOUBLE: + if (x == CONST0_RTX (mode)) + return true; + if (FLOAT_MODE_P (mode)) + return false; + goto do_integer; + + case CONST_VECTOR: + if (x == CONST0_RTX (mode)) + return true; + if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT) + return false; + if (GET_MODE_SIZE (mode) != 8) + return false; + goto do_integer; + + case CONST_INT: + do_integer: + if (TARGET_BUILD_CONSTANTS) + return true; + alpha_extract_integer (x, &i0, &i1); + if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == (-i0 < 0)) + return alpha_emit_set_const_1 (x, mode, i0, 3, true) != NULL; + return false; + + default: + return false; + } +} + +/* Operand 1 is known to be a constant, and should require more than one + instruction to load. Emit that multi-part load. */ + +bool +alpha_split_const_mov (enum machine_mode mode, rtx *operands) +{ + HOST_WIDE_INT i0, i1; + rtx temp = NULL_RTX; + + alpha_extract_integer (operands[1], &i0, &i1); + + if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0)) + temp = alpha_emit_set_const (operands[0], mode, i0, 3, false); + + if (!temp && TARGET_BUILD_CONSTANTS) + temp = alpha_emit_set_long_const (operands[0], i0, i1); + + if (temp) + { + if (!rtx_equal_p (operands[0], temp)) + emit_move_insn (operands[0], temp); + return true; + } + + return false; +} + /* Expand a move instruction; return true if all work is done. We don't handle non-bwx subword loads here. */ @@ -2008,40 +2198,11 @@ alpha_expand_mov (enum machine_mode mode, rtx *operands) /* Split large integers. */ if (GET_CODE (operands[1]) == CONST_INT - || GET_CODE (operands[1]) == CONST_DOUBLE) + || GET_CODE (operands[1]) == CONST_DOUBLE + || GET_CODE (operands[1]) == CONST_VECTOR) { - HOST_WIDE_INT i0, i1; - rtx temp = NULL_RTX; - - if (GET_CODE (operands[1]) == CONST_INT) - { - i0 = INTVAL (operands[1]); - i1 = -(i0 < 0); - } - else if (HOST_BITS_PER_WIDE_INT >= 64) - { - i0 = CONST_DOUBLE_LOW (operands[1]); - i1 = -(i0 < 0); - } - else - { - i0 = CONST_DOUBLE_LOW (operands[1]); - i1 = CONST_DOUBLE_HIGH (operands[1]); - } - - if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0)) - temp = alpha_emit_set_const (operands[0], mode, i0, 3); - - if (!temp && TARGET_BUILD_CONSTANTS) - temp = alpha_emit_set_long_const (operands[0], i0, i1); - - if (temp) - { - if (rtx_equal_p (operands[0], temp)) - return true; - operands[1] = temp; - return false; - } + if (alpha_split_const_mov (mode, operands)) + return true; } /* Otherwise we've nothing left but to drop the thing to memory. */ @@ -7029,7 +7190,8 @@ alpha_expand_epilogue (void) else { rtx tmp = gen_rtx_REG (DImode, 23); - FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3)); + FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, + 3, false)); if (!sp_adj2) { /* We can't drop new things to memory this late, afaik, diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index e9a409816a17..21a634c39ec8 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -884,10 +884,10 @@ enum reg_class { reduce the impact of not being able to allocate a pseudo to a hard register. */ -#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ - (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS) \ - ? 2 \ - : TARGET_FIX ? 3 : 4+2*alpha_memory_latency) +#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ + (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS) ? 2 \ + : TARGET_FIX ? ((CLASS1) == FLOAT_REGS ? 6 : 8) \ + : 4+2*alpha_memory_latency) /* A C expressions returning the cost of moving data of MODE from a register to or from memory. @@ -1213,9 +1213,7 @@ do { \ /* Include all constant integers and constant doubles, but not floating-point, except for floating-point zero. */ -#define LEGITIMATE_CONSTANT_P(X) \ - (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \ - || (X) == CONST0_RTX (GET_MODE (X))) +#define LEGITIMATE_CONSTANT_P alpha_legitimate_constant_p /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its validity for a certain class. diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md index 2679324d10a5..0f68d36b93bd 100644 --- a/gcc/config/alpha/alpha.md +++ b/gcc/config/alpha/alpha.md @@ -5128,8 +5128,8 @@ }) (define_insn "*movsi" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m") - (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m") + (match_operand:SI 1 "input_operand" "rJ,K,L,n,m,rJ"))] "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK) && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" @@ -5137,13 +5137,14 @@ bis $31,%r1,%0 lda %0,%1($31) ldah %0,%h1($31) + # ldl %0,%1 stl %r1,%0" - [(set_attr "type" "ilog,iadd,iadd,ild,ist")]) + [(set_attr "type" "ilog,iadd,iadd,multi,ild,ist")]) (define_insn "*movsi_nt_vms" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m") - (match_operand:SI 1 "input_operand" "rJ,K,L,s,m,rJ"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m") + (match_operand:SI 1 "input_operand" "rJ,K,L,s,n,m,rJ"))] "(TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS) && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" @@ -5152,9 +5153,10 @@ lda %0,%1 ldah %0,%h1 lda %0,%1 + # ldl %0,%1 stl %r1,%0" - [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist")]) + [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist")]) (define_insn "*movhi_nobwx" [(set (match_operand:HI 0 "register_operand" "=r,r") @@ -5221,15 +5223,11 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "! add_operand (operands[1], SImode)" - [(set (match_dup 0) (match_dup 2)) - (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))] + (match_operand:SI 1 "non_add_const_operand" ""))] + "" + [(const_int 0)] { - rtx tem - = alpha_emit_set_const (operands[0], SImode, INTVAL (operands[1]), 2); - - if (tem == operands[0]) + if (alpha_split_const_mov (SImode, operands)) DONE; else FAIL; @@ -5452,8 +5450,8 @@ }) (define_insn "*movdi_er_nofix" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q") - (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,m,rJ,*fJ,Q,*f"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q") + (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,n,m,rJ,*fJ,Q,*f"))] "TARGET_EXPLICIT_RELOCS && ! TARGET_FIX && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" @@ -5463,21 +5461,22 @@ ldah %0,%h1($31) # # + # ldq%A1 %0,%1 stq%A0 %r1,%0 fmov %R1,%0 ldt %0,%1 stt %R1,%0" - [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst") - (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*")]) + [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst") + (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*")]) ;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should ;; have been split up by the rules above but we shouldn't reject the ;; possibility of them getting through. (define_insn "*movdi_nofix" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q") - (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,m,rJ,*fJ,Q,*f"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q") + (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,n,m,rJ,*fJ,Q,*f"))] "! TARGET_FIX && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" @@ -5487,19 +5486,20 @@ ldah %0,%h1($31) laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0) lda %0,%1 + # ldq%A1 %0,%1 stq%A0 %r1,%0 cpys %R1,%R1,%0 ldt %0,%1 stt %R1,%0" - [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,ild,ist,fcpys,fld,fst") - (set_attr "length" "*,*,*,16,*,*,*,*,*,*")]) + [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,multi,ild,ist,fcpys,fld,fst") + (set_attr "length" "*,*,*,16,*,*,*,*,*,*,*")]) (define_insn "*movdi_er_fix" [(set (match_operand:DI 0 "nonimmediate_operand" - "=r,r,r,r,r,r, m, *f,*f, Q, r,*f") + "=r,r,r,r,r,r,r, m, *f,*f, Q, r,*f") (match_operand:DI 1 "input_operand" - "rJ,K,L,T,s,m,rJ,*fJ, Q,*f,*f, r"))] + "rJ,K,L,T,s,n,m,rJ,*fJ, Q,*f,*f, r"))] "TARGET_EXPLICIT_RELOCS && TARGET_FIX && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" @@ -5509,6 +5509,7 @@ ldah %0,%h1($31) # # + # ldq%A1 %0,%1 stq%A0 %r1,%0 fmov %R1,%0 @@ -5516,12 +5517,12 @@ stt %R1,%0 ftoit %1,%0 itoft %1,%0" - [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof") - (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*,*")]) + [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof") + (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*,*,*")]) (define_insn "*movdi_fix" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q,r,*f") - (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f,*f,r"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q,r,*f") + (match_operand:DI 1 "input_operand" "rJ,K,L,s,n,m,rJ,*fJ,Q,*f,*f,r"))] "! TARGET_EXPLICIT_RELOCS && TARGET_FIX && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" @@ -5530,6 +5531,7 @@ lda %0,%1($31) ldah %0,%h1($31) lda %0,%1 + # ldq%A1 %0,%1 stq%A0 %r1,%0 cpys %R1,%R1,%0 @@ -5537,7 +5539,7 @@ stt %R1,%0 ftoit %1,%0 itoft %1,%0" - [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")]) + [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof")]) ;; VMS needs to set up "vms_base_regno" for unwinding. This move ;; often appears dead to the life analysis code, at which point we @@ -5568,15 +5570,11 @@ (define_split [(set (match_operand:DI 0 "register_operand" "") - (match_operand:DI 1 "const_int_operand" ""))] - "! add_operand (operands[1], DImode)" - [(set (match_dup 0) (match_dup 2)) - (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] + (match_operand:DI 1 "non_add_const_operand" ""))] + "" + [(const_int 0)] { - rtx tem - = alpha_emit_set_const (operands[0], DImode, INTVAL (operands[1]), 2); - - if (tem == operands[0]) + if (alpha_split_const_mov (DImode, operands)) DONE; else FAIL; @@ -6103,6 +6101,19 @@ DONE; }) +(define_split + [(set (match_operand:VEC 0 "register_operand" "") + (match_operand:VEC 1 "non_zero_const_operand" ""))] + "" + [(const_int 0)] +{ + if (alpha_split_const_mov (mode, operands)) + DONE; + else + FAIL; +}) + + (define_expand "movmisalign" [(set (match_operand:VEC 0 "nonimmediate_operand" "") (match_operand:VEC 1 "general_operand" ""))] @@ -6113,13 +6124,14 @@ }) (define_insn "*mov_fix" - [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,m,*f,*f,m,r,*f") - (match_operand:VEC 1 "input_operand" "rW,m,rW,*fW,m,*f,*f,r"))] + [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m,r,*f") + (match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f,*f,r"))] "TARGET_FIX && (register_operand (operands[0], mode) || reg_or_0_operand (operands[1], mode))" "@ bis $31,%r1,%0 + # ldq %0,%1 stq %r1,%0 cpys %R1,%R1,%0 @@ -6127,22 +6139,23 @@ stt %R1,%0 ftoit %1,%0 itoft %1,%0" - [(set_attr "type" "ilog,ild,ist,fcpys,fld,fst,ftoi,itof")]) + [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst,ftoi,itof")]) (define_insn "*mov_nofix" - [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,m,*f,*f,m") - (match_operand:VEC 1 "input_operand" "rW,m,rW,*fW,m,*f"))] + [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m") + (match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f"))] "! TARGET_FIX && (register_operand (operands[0], mode) || reg_or_0_operand (operands[1], mode))" "@ bis $31,%r1,%0 + # ldq %0,%1 stq %r1,%0 cpys %R1,%R1,%0 ldt %0,%1 stt %R1,%0" - [(set_attr "type" "ilog,ild,ist,fcpys,fld,fst")]) + [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst")]) (define_insn "uminv8qi3" [(set (match_operand:V8QI 0 "register_operand" "=r") diff --git a/gcc/config/alpha/predicates.md b/gcc/config/alpha/predicates.md index b060dd17741d..6a58ed679054 100644 --- a/gcc/config/alpha/predicates.md +++ b/gcc/config/alpha/predicates.md @@ -66,6 +66,17 @@ || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O')") (match_operand 0 "register_operand"))) +;; Return 1 if the operand is a non-symbolic constant operand that +;; does not satisfy add_operand. +(define_predicate "non_add_const_operand" + (and (match_code "const_int,const_double,const_vector") + (not (match_operand 0 "add_operand")))) + +;; Return 1 if the operand is a non-symbolic, non-zero constant operand. +(define_predicate "non_zero_const_operand" + (and (match_code "const_int,const_double,const_vector") + (match_test "op != CONST0_RTX (mode)"))) + ;; Return 1 if OP is the constant 4 or 8. (define_predicate "const48_operand" (and (match_code "const_int") @@ -205,11 +216,19 @@ && general_operand (op, mode)); case CONST_DOUBLE: + return op == CONST0_RTX (mode); + case CONST_VECTOR: + if (reload_in_progress || reload_completed) + return alpha_legitimate_constant_p (op); return op == CONST0_RTX (mode); case CONST_INT: - return mode == QImode || mode == HImode || add_operand (op, mode); + if (mode == QImode || mode == HImode) + return true; + if (reload_in_progress || reload_completed) + return alpha_legitimate_constant_p (op); + return add_operand (op, mode); default: abort (); diff --git a/gcc/testsuite/gcc.target/alpha/alpha.exp b/gcc/testsuite/gcc.target/alpha/alpha.exp new file mode 100644 index 000000000000..47ad3e17b4e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/alpha.exp @@ -0,0 +1,41 @@ +# Copyright (C) 2005 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an Alpha target. +if ![istarget alpha*-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/alpha/pr19518.c b/gcc/testsuite/gcc.target/alpha/pr19518.c new file mode 100644 index 000000000000..42c58b5a5bbe --- /dev/null +++ b/gcc/testsuite/gcc.target/alpha/pr19518.c @@ -0,0 +1,60 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mcpu=ev67" } */ + +typedef short INT16; +typedef unsigned int CARD32; +typedef unsigned short CARD16; +typedef unsigned char CARD8; +typedef struct _Picture *PicturePtr; +typedef int FbStride; +typedef unsigned long __m64; +extern __m64 load8888 (__m64); +static __inline __m64 _mm_adds_pu8(__m64 __m1, __m64 __m2) +{ + return __m1 + __builtin_alpha_minsb8(__m2, ~__m1); +} +static __inline __m64 _mm_packs_pu16(__m64 __m1, __m64 __m2) +{ + __m1 = __builtin_alpha_minuw4(__m1, 0x00ff00ff00ff00ff); + __m2 = __builtin_alpha_minuw4(__m2, 0x00ff00ff00ff00ff); + return __m1 | (__m2 << 32); +} +typedef unsigned long long ullong; +static __inline__ __m64 pix_multiply(__m64 a) +{ + if (a) + return a; +} +static __inline__ __m64 over(__m64 src, __m64 srca, __m64 dest) +{ + return _mm_adds_pu8(src, pix_multiply(dest)); +} + +void fbCompositeSolid_nx8888mmx(CARD8 op, PicturePtr pSrc, PicturePtr pMask, + INT16 yDst, CARD16 width, CARD16 height) +{ + CARD32 src; + CARD32 *dstLine, *dst; + CARD16 w; + FbStride dstStride; + __m64 vsrc, vsrca; + vsrc = load8888(src); + while (height--) { + dst = dstLine; + dstLine += dstStride; + while (w && (unsigned long) dst & 7) { + *dst = _mm_packs_pu16(_mm_adds_pu8(vsrc, load8888(*dst)), + _mm_setzero_si64()); + dst++; + } + while (w >= 2) { + __m64 dest0, dest1; + *(__m64 *) dst = _mm_packs_pu16(dest0, dest1); + w -= 2; + } + while (w) { + *dst = _mm_packs_pu16(_mm_adds_pu8(vsrc, pix_multiply(0)), 0); + w--; + } + } +}