+2005-01-19 Richard Henderson <rth@redhat.com>
+
+ 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<VEC>_fix, mov<VEC>_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 <dvorakz@suse.cz>
PR tree-optimization/19038
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,
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 *);
*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)
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;
for_each_rtx (base_ptr, alpha_set_memflags_1, (void *) ref);
}
\f
-/* 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;
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)));
}
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)));
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
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
/* 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
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;
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;
}
/* 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;
}
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;
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. */
/* 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. */
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,
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.
/* 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.
})
(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))"
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))"
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")
(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;
})
(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))"
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))"
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))"
ldah %0,%h1($31)
#
#
+ #
ldq%A1 %0,%1
stq%A0 %r1,%0
fmov %R1,%0
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))"
lda %0,%1($31)
ldah %0,%h1($31)
lda %0,%1
+ #
ldq%A1 %0,%1
stq%A0 %r1,%0
cpys %R1,%R1,%0
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
(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;
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>mode, operands))
+ DONE;
+ else
+ FAIL;
+})
+
+
(define_expand "movmisalign<mode>"
[(set (match_operand:VEC 0 "nonimmediate_operand" "")
(match_operand:VEC 1 "general_operand" ""))]
})
(define_insn "*mov<mode>_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>mode)
|| reg_or_0_operand (operands[1], <MODE>mode))"
"@
bis $31,%r1,%0
+ #
ldq %0,%1
stq %r1,%0
cpys %R1,%R1,%0
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<mode>_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>mode)
|| reg_or_0_operand (operands[1], <MODE>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")
|| 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")
&& 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 ();
--- /dev/null
+# 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
--- /dev/null
+/* { 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--;
+ }
+ }
+}