Commit 6c174fc0 by Richard Henderson Committed by Richard Henderson

c-decl.c (init_decl_processing): Provide proper fallback symbol for __builtin_memset.

* c-decl.c (init_decl_processing): Provide proper fallback symbol
for __builtin_memset.
* expr.c (expand_builtin) [MEMSET]: Arg 3 type code is INTEGER_TYPE
not INTEGER_CST.  Assert arg 3 is a constant.
* alpha.c (mode_width_operand): Accept 64-bit modes.
(mode_mask_operand): Likewise.
(print_operand): Likewise for 'M' and 'U' codes.
(alpha_expand_unaligned_load): New function.
(alpha_expand_unaligned_store): Likewise.
(alpha_expand_unaligned_load_words): Likewise.
(alpha_expand_unaligned_store_words): Likewise.
(alpha_expand_block_move): Likewise.
(alpha_expand_block_clear): Likewise.
* alpha.h (MOVE_RATIO): New define.
* alpha.md (extxl, ext*h, ins*l, mskxl): Name them.
(insql, insxh, mskxh, extv, extzv, insv, movstrqi, clrstrqi): New.
* alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Set to 3.
(CONSTANT_ALIGNMENT, DATA_ALIGNMENT): Disable.

From-SVN: r17278
parent 8fbf199e
Fri Jan 2 04:34:14 1998 Richard Henderson <rth@cygnus.com>
* c-decl.c (init_decl_processing): Provide proper fallback symbol
for __builtin_memset.
* expr.c (expand_builtin) [MEMSET]: Arg 3 type code is INTEGER_TYPE
not INTEGER_CST. Assert arg 3 is a constant.
* alpha.c (mode_width_operand): Accept 64-bit modes.
(mode_mask_operand): Likewise.
(print_operand): Likewise for 'M' and 'U' codes.
(alpha_expand_unaligned_load): New function.
(alpha_expand_unaligned_store): Likewise.
(alpha_expand_unaligned_load_words): Likewise.
(alpha_expand_unaligned_store_words): Likewise.
(alpha_expand_block_move): Likewise.
(alpha_expand_block_clear): Likewise.
* alpha.h (MOVE_RATIO): New define.
* alpha.md (extxl, ext*h, ins*l, mskxl): Name them.
(insql, insxh, mskxh, extv, extzv, insv, movstrqi, clrstrqi): New.
* alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Set to 3.
(CONSTANT_ALIGNMENT, DATA_ALIGNMENT): Disable.
Thu Jan 1 15:40:15 1998 Richard Henderson <rth@cygnus.com> Thu Jan 1 15:40:15 1998 Richard Henderson <rth@cygnus.com>
* configure.in: Put parenthesis around TARGET_CPU_DEFAULT's value. * configure.in: Put parenthesis around TARGET_CPU_DEFAULT's value.
......
...@@ -3353,7 +3353,7 @@ init_decl_processing () ...@@ -3353,7 +3353,7 @@ init_decl_processing ()
builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet, builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
BUILT_IN_MEMCMP, "memcmp"); BUILT_IN_MEMCMP, "memcmp");
builtin_function ("__builtin_memset", memset_ftype, builtin_function ("__builtin_memset", memset_ftype,
BUILT_IN_MEMSET, NULL_PTR); BUILT_IN_MEMSET, "memset");
builtin_function ("__builtin_strcmp", int_ftype_string_string, builtin_function ("__builtin_strcmp", int_ftype_string_string,
BUILT_IN_STRCMP, "strcmp"); BUILT_IN_STRCMP, "strcmp");
builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr, builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
...@@ -3450,8 +3450,6 @@ init_decl_processing () ...@@ -3450,8 +3450,6 @@ init_decl_processing ()
BUILT_IN_FMOD, NULL_PTR); BUILT_IN_FMOD, NULL_PTR);
builtin_function ("__builtin_frem", double_ftype_double_double, builtin_function ("__builtin_frem", double_ftype_double_double,
BUILT_IN_FREM, NULL_PTR); BUILT_IN_FREM, NULL_PTR);
builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int,
BUILT_IN_MEMSET, NULL_PTR);
builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP, builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
NULL_PTR); NULL_PTR);
builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN, builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
......
...@@ -450,7 +450,8 @@ mode_width_operand (op, mode) ...@@ -450,7 +450,8 @@ mode_width_operand (op, mode)
enum machine_mode mode; enum machine_mode mode;
{ {
return (GET_CODE (op) == CONST_INT return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32)); && (INTVAL (op) == 8 || INTVAL (op) == 16
|| INTVAL (op) == 32 || INTVAL (op) == 64));
} }
/* Return 1 if OP is a constant that is the width of an integral machine mode /* Return 1 if OP is a constant that is the width of an integral machine mode
...@@ -463,7 +464,12 @@ mode_mask_operand (op, mode) ...@@ -463,7 +464,12 @@ mode_mask_operand (op, mode)
{ {
#if HOST_BITS_PER_WIDE_INT == 32 #if HOST_BITS_PER_WIDE_INT == 32
if (GET_CODE (op) == CONST_DOUBLE) if (GET_CODE (op) == CONST_DOUBLE)
return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1; return (CONST_DOUBLE_LOW (op) == -1
&& (CONST_DOUBLE_HIGH (op) == -1
|| CONST_DOUBLE_HIGH (op) == 0));
#else
if (GET_CODE (op) == CONST_DOUBLE)
return (CONST_DOUBLE_LOW (op) == -1 && CONST_DOUBLE_HIGH (op) == 0);
#endif #endif
return (GET_CODE (op) == CONST_INT return (GET_CODE (op) == CONST_INT
...@@ -471,6 +477,7 @@ mode_mask_operand (op, mode) ...@@ -471,6 +477,7 @@ mode_mask_operand (op, mode)
|| INTVAL (op) == 0xffff || INTVAL (op) == 0xffff
#if HOST_BITS_PER_WIDE_INT == 64 #if HOST_BITS_PER_WIDE_INT == 64
|| INTVAL (op) == 0xffffffff || INTVAL (op) == 0xffffffff
|| INTVAL (op) == 0xffffffffffffffff
#endif #endif
)); ));
} }
...@@ -1263,6 +1270,587 @@ alpha_emit_conditional_move (cmp, mode) ...@@ -1263,6 +1270,587 @@ alpha_emit_conditional_move (cmp, mode)
return gen_rtx (cmov_code, VOIDmode, tem, CONST0_RTX (cmp_op_mode)); return gen_rtx (cmov_code, VOIDmode, tem, CONST0_RTX (cmp_op_mode));
} }
/* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
unaligned data:
unsigned: signed:
word: ldq_u r1,X(r11) ldq_u r1,X(r11)
ldq_u r2,X+1(r11) ldq_u r2,X+1(r11)
lda r3,X(r11) lda r3,X+2(r11)
extwl r1,r3,r1 extql r1,r3,r1
extwh r2,r3,r2 extqh r2,r3,r2
or r1.r2.r1 or r1,r2,r1
sra r1,48,r1
long: ldq_u r1,X(r11) ldq_u r1,X(r11)
ldq_u r2,X+3(r11) ldq_u r2,X+3(r11)
lda r3,X(r11) lda r3,X(r11)
extll r1,r3,r1 extll r1,r3,r1
extlh r2,r3,r2 extlh r2,r3,r2
or r1.r2.r1 addl r1,r2,r1
quad: ldq_u r1,X(r11)
ldq_u r2,X+7(r11)
lda r3,X(r11)
extql r1,r3,r1
extqh r2,r3,r2
or r1.r2.r1
*/
void
alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
rtx tgt, mem;
HOST_WIDE_INT size, ofs;
int sign;
{
rtx meml, memh, addr, extl, exth;
meml = gen_reg_rtx (DImode);
memh = gen_reg_rtx (DImode);
addr = gen_reg_rtx (DImode);
extl = gen_reg_rtx (DImode);
exth = gen_reg_rtx (DImode);
emit_move_insn (meml,
change_address (mem, DImode,
gen_rtx (AND, DImode,
plus_constant (XEXP (mem, 0), ofs),
GEN_INT (-8))));
emit_move_insn (memh,
change_address (mem, DImode,
gen_rtx (AND, DImode,
plus_constant (XEXP (mem, 0),
ofs + size - 1),
GEN_INT (-8))));
if (sign && size == 2)
{
emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs+2));
emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr));
emit_insn (gen_extqh (exth, memh, addr));
expand_binop (DImode, ior_optab, extl, exth, addr, 1, OPTAB_WIDEN);
expand_binop (DImode, ashr_optab, addr, GEN_INT (48), addr,
1, OPTAB_WIDEN);
emit_move_insn (tgt, addr);
return;
}
emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs));
emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr));
switch (size)
{
case 2:
emit_insn (gen_extwh (exth, memh, addr));
break;
case 4:
emit_insn (gen_extlh (exth, memh, addr));
break;
case 8:
emit_insn (gen_extqh (exth, memh, addr));
break;
}
expand_binop (DImode, ior_optab, extl, exth, tgt, sign, OPTAB_WIDEN);
}
/* Similarly, use ins and msk instructions to perform unaligned stores. */
void
alpha_expand_unaligned_store (dst, src, size, ofs)
rtx dst, src;
HOST_WIDE_INT size, ofs;
{
rtx dstl, dsth, addr, insl, insh, meml, memh;
dstl = gen_reg_rtx (DImode);
dsth = gen_reg_rtx (DImode);
insl = gen_reg_rtx (DImode);
insh = gen_reg_rtx (DImode);
meml = change_address (dst, DImode,
gen_rtx (AND, DImode,
plus_constant (XEXP (dst, 0), ofs),
GEN_INT (-8)));
memh = change_address (dst, DImode,
gen_rtx (AND, DImode,
plus_constant (XEXP (dst, 0), ofs+size-1),
GEN_INT (-8)));
emit_move_insn (dsth, memh);
emit_move_insn (dstl, meml);
addr = copy_addr_to_reg (plus_constant (XEXP (dst, 0), ofs));
if (src != const0_rtx)
{
emit_insn (gen_insxh (insh, src, GEN_INT (size*8), addr));
switch (size)
{
case 2:
emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr));
break;
case 4:
emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr));
break;
case 8:
emit_insn (gen_insql (insl, src, addr));
break;
}
}
emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
switch (size)
{
case 2:
emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffff), addr));
break;
case 4:
emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffffffff), addr));
break;
case 8:
{
#if HOST_BITS_PER_WIDE_INT == 32
rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
#else
rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode);
#endif
emit_insn (gen_mskxl (dstl, dstl, msk, addr));
}
break;
}
if (src != const0_rtx)
{
expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN);
expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN);
}
/* Must store high before low for degenerate case of aligned. */
emit_move_insn (memh, dsth);
emit_move_insn (meml, dstl);
}
/* Load an integral number of consecutive unaligned quadwords. */
#define MAX_MOVE_WORDS 4
static void
alpha_expand_unaligned_load_words (data_regs, src_addr, words)
rtx data_regs[MAX_MOVE_WORDS+1];
rtx src_addr;
HOST_WIDE_INT words;
{
rtx const im8 = GEN_INT (-8);
rtx const i64 = GEN_INT (64);
rtx ext_tmps[MAX_MOVE_WORDS];
rtx src_reg, and_reg;
HOST_WIDE_INT i;
/* Generate all the tmp registers we need. */
for (i = 0; i < words; ++i)
ext_tmps[i] = gen_reg_rtx(DImode);
/* Load up all of the source data. */
for (i = 0; i < words; ++i)
{
emit_move_insn (data_regs[i],
change_address (src_addr, DImode,
gen_rtx (AND, DImode,
plus_constant (XEXP(src_addr,0),
8*i),
im8)));
}
emit_move_insn (data_regs[words],
change_address (src_addr, DImode,
gen_rtx (AND, DImode,
plus_constant (XEXP(src_addr,0),
8*words - 1),
im8)));
/* Extract the half-word fragments. Unfortunately DEC decided to make
extxh with offset zero a noop instead of zeroing the register, so
we must take care of that edge condition ourselves with cmov. */
src_reg = copy_addr_to_reg (XEXP (src_addr, 0));
and_reg = expand_binop (DImode, and_optab, src_reg, GEN_INT (7), NULL,
1, OPTAB_WIDEN);
for (i = 0; i < words; ++i)
{
emit_insn (gen_extxl (data_regs[i], data_regs[i], i64, src_reg));
emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], src_reg));
emit_insn (gen_rtx (SET, VOIDmode, ext_tmps[i],
gen_rtx (IF_THEN_ELSE, DImode,
gen_rtx (EQ, DImode, and_reg, const0_rtx),
const0_rtx, ext_tmps[i])));
}
/* Merge the half-words into whole words. */
for (i = 0; i < words; ++i)
{
expand_binop (DImode, ior_optab, data_regs[i], ext_tmps[i],
data_regs[i], 1, OPTAB_WIDEN);
}
}
/* Store an integral number of consecutive unaligned quadwords. DATA_REGS
may be NULL to store zeros. */
static void
alpha_expand_unaligned_store_words (data_regs, dst_addr, words)
rtx *data_regs;
rtx dst_addr;
HOST_WIDE_INT words;
{
rtx const im8 = GEN_INT (-8);
rtx const i64 = GEN_INT (64);
#if HOST_BITS_PER_WIDE_INT == 32
rtx const im1 = immed_double_const (0xffffffff, 0xffffffff, DImode);
#else
rtx const im1 = immed_double_const (0xffffffffffffffff, 0, DImode);
#endif
rtx ins_tmps[MAX_MOVE_WORDS];
rtx st_tmp_1, st_tmp_2, dst_reg;
rtx st_addr_1, st_addr_2;
HOST_WIDE_INT i;
/* Generate all the tmp registers we need. */
if (data_regs != NULL)
for (i = 0; i < words; ++i)
ins_tmps[i] = gen_reg_rtx(DImode);
st_tmp_1 = gen_reg_rtx(DImode);
st_tmp_2 = gen_reg_rtx(DImode);
st_addr_2 = change_address (dst_addr, DImode,
gen_rtx (AND, DImode,
plus_constant (XEXP(dst_addr,0),
words*8 - 1),
im8));
st_addr_1 = change_address (dst_addr, DImode,
gen_rtx (AND, DImode,
XEXP (dst_addr, 0),
im8));
/* Load up the destination end bits. */
emit_move_insn (st_tmp_2, st_addr_2);
emit_move_insn (st_tmp_1, st_addr_1);
/* Shift the input data into place. */
dst_reg = copy_addr_to_reg (XEXP (dst_addr, 0));
if (data_regs != NULL)
{
for (i = words-1; i >= 0; --i)
{
emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dst_reg));
emit_insn (gen_insql (data_regs[i], data_regs[i], dst_reg));
}
for (i = words-1; i > 0; --i)
{
expand_binop (DImode, ior_optab, data_regs[i], ins_tmps[i-1],
ins_tmps[i-1], 1, OPTAB_WIDEN);
}
}
/* Split and merge the ends with the destination data. */
emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dst_reg));
emit_insn (gen_mskxl (st_tmp_1, st_tmp_1, im1, dst_reg));
if (data_regs != NULL)
{
expand_binop (DImode, ior_optab, st_tmp_2, ins_tmps[words-1],
st_tmp_2, 1, OPTAB_WIDEN);
expand_binop (DImode, ior_optab, st_tmp_1, data_regs[0],
st_tmp_1, 1, OPTAB_WIDEN);
}
/* Store it all. */
emit_move_insn (st_addr_2, st_tmp_2);
for (i = words-1; i > 0; --i)
{
emit_move_insn (change_address (dst_addr, DImode,
gen_rtx (AND, DImode,
plus_constant(XEXP (dst_addr,0),
i*8),
im8)),
data_regs ? ins_tmps[i-1] : const0_rtx);
}
emit_move_insn (st_addr_1, st_tmp_1);
}
/* Expand string/block move operations.
operands[0] is the pointer to the destination.
operands[1] is the pointer to the source.
operands[2] is the number of bytes to move.
operands[3] is the alignment. */
int
alpha_expand_block_move (operands)
rtx operands[];
{
rtx bytes_rtx = operands[2];
rtx align_rtx = operands[3];
HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
HOST_WIDE_INT align = INTVAL (align_rtx);
rtx orig_src = operands[1];
rtx orig_dst = operands[0];
rtx tmp = NULL_RTX;
rtx data_regs[2*MAX_MOVE_WORDS];
HOST_WIDE_INT i, words, ofs = 0;
if (bytes <= 0)
return 1;
if (bytes > MAX_MOVE_WORDS*8)
return 0;
/* Handle a block of contiguous words first. */
if (align >= 8 && bytes >= 8)
{
words = bytes / 8;
/* Make some data registers. */
for (i = 0; i < words; ++i)
data_regs[i] = gen_reg_rtx(DImode);
/* Move in aligned hunks. */
for (i = 0; i < words; ++i)
{
emit_move_insn (data_regs[i],
change_address(orig_src, DImode,
plus_constant (XEXP (orig_src, 0),
i*8)));
}
for (i = 0; i < words; ++i)
{
emit_move_insn (change_address(orig_dst, DImode,
plus_constant (XEXP (orig_dst, 0),
i*8)),
data_regs[i]);
}
bytes -= words * 8;
ofs = words * 8;
}
if (align >= 4 && bytes >= 4)
{
words = bytes / 4;
/* Make some data registers. */
for (i = 0; i < words; ++i)
data_regs[i] = gen_reg_rtx(SImode);
/* Move in aligned hunks. */
for (i = 0; i < words; ++i)
{
emit_move_insn (data_regs[i],
change_address(orig_src, SImode,
plus_constant (XEXP (orig_src, 0),
i*4)));
}
for (i = 0; i < words; ++i)
{
emit_move_insn (change_address(orig_dst, SImode,
plus_constant (XEXP (orig_dst, 0),
i*4)),
data_regs[i]);
}
bytes -= words * 4;
ofs = words * 4;
}
if (bytes >= 16)
{
words = bytes / 8;
/* Make some data registers. */
for (i = 0; i < words+1; ++i)
data_regs[i] = gen_reg_rtx(DImode);
/* Move in unaligned hunks. */
alpha_expand_unaligned_load_words (data_regs, orig_src, words);
alpha_expand_unaligned_store_words (data_regs, orig_dst, words);
bytes -= words * 8;
ofs = words * 8;
}
/* Next clean up any trailing pieces. We know from the contiguous
block move that there are no aligned SImode or DImode hunks left. */
if (!TARGET_BWX && bytes >= 8)
{
tmp = gen_reg_rtx (DImode);
alpha_expand_unaligned_load (tmp, orig_src, 8, ofs, 0);
alpha_expand_unaligned_store (orig_dst, tmp, 8, ofs);
bytes -= 8;
ofs += 8;
}
if (!TARGET_BWX && bytes >= 4)
{
tmp = gen_reg_rtx (DImode);
alpha_expand_unaligned_load (tmp, orig_src, 4, ofs, 0);
alpha_expand_unaligned_store (orig_dst, tmp, 4, ofs);
bytes -= 4;
ofs += 4;
}
if (bytes >= 2)
{
if (align >= 2)
{
do {
emit_move_insn (change_address (orig_dst, HImode,
plus_constant (XEXP (orig_dst, 0),
ofs)),
change_address (orig_src, HImode,
plus_constant (XEXP (orig_src, 0),
ofs)));
bytes -= 2;
ofs += 2;
} while (bytes >= 2);
}
else if (!TARGET_BWX)
{
tmp = gen_reg_rtx (DImode);
alpha_expand_unaligned_load (tmp, orig_src, 2, ofs, 0);
alpha_expand_unaligned_store (orig_dst, tmp, 2, ofs);
bytes -= 2;
ofs += 2;
}
}
while (bytes > 0)
{
emit_move_insn (change_address (orig_dst, QImode,
plus_constant (XEXP (orig_dst, 0),
ofs)),
change_address (orig_src, QImode,
plus_constant (XEXP (orig_src, 0),
ofs)));
bytes -= 1;
ofs += 1;
}
return 1;
}
int
alpha_expand_block_clear (operands)
rtx operands[];
{
rtx bytes_rtx = operands[1];
rtx align_rtx = operands[2];
HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
HOST_WIDE_INT align = INTVAL (align_rtx);
rtx orig_dst = operands[0];
HOST_WIDE_INT i, words, ofs = 0;
if (bytes <= 0)
return 1;
if (bytes > MAX_MOVE_WORDS*8)
return 0;
/* Handle a block of contiguous words first. */
if (align >= 8 && bytes >= 8)
{
words = bytes / 8;
for (i = 0; i < words; ++i)
{
emit_move_insn (change_address(orig_dst, DImode,
plus_constant (XEXP (orig_dst, 0),
i*8)),
const0_rtx);
}
bytes -= words * 8;
ofs = words * 8;
}
else if (align >= 4 && bytes >= 4)
{
words = bytes / 4;
for (i = 0; i < words; ++i)
{
emit_move_insn (change_address(orig_dst, SImode,
plus_constant (XEXP (orig_dst, 0),
i*4)),
const0_rtx);
}
bytes -= words * 4;
ofs = words * 4;
}
else if (bytes >= 16)
{
words = bytes / 8;
alpha_expand_unaligned_store_words (NULL, orig_dst, words);
bytes -= words * 8;
ofs = words * 8;
}
/* Next clean up any trailing pieces. We know from the contiguous
block move that there are no aligned SImode or DImode hunks left. */
if (!TARGET_BWX && bytes >= 8)
{
alpha_expand_unaligned_store (orig_dst, const0_rtx, 8, ofs);
bytes -= 8;
ofs += 8;
}
if (!TARGET_BWX && bytes >= 4)
{
alpha_expand_unaligned_store (orig_dst, const0_rtx, 4, ofs);
bytes -= 4;
ofs += 4;
}
if (bytes >= 2)
{
if (align >= 2)
{
do {
emit_move_insn (change_address (orig_dst, HImode,
plus_constant (XEXP (orig_dst, 0),
ofs)),
const0_rtx);
bytes -= 2;
ofs += 2;
} while (bytes >= 2);
}
else if (!TARGET_BWX)
{
alpha_expand_unaligned_store (orig_dst, const0_rtx, 2, ofs);
bytes -= 2;
ofs += 2;
}
}
while (bytes > 0)
{
emit_move_insn (change_address (orig_dst, QImode,
plus_constant (XEXP (orig_dst, 0),
ofs)),
const0_rtx);
bytes -= 1;
ofs += 1;
}
return 1;
}
/* Adjust the cost of a scheduling dependency. Return the new cost of /* Adjust the cost of a scheduling dependency. Return the new cost of
a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
...@@ -1667,13 +2255,17 @@ print_operand (file, x, code) ...@@ -1667,13 +2255,17 @@ print_operand (file, x, code)
break; break;
case 'M': case 'M':
/* 'b', 'w', or 'l' as the value of the constant. */ /* 'b', 'w', 'l', or 'q' as the value of the constant. */
if (GET_CODE (x) != CONST_INT if (GET_CODE (x) != CONST_INT
|| (INTVAL (x) != 8 && INTVAL (x) != 16 && INTVAL (x) != 32)) || (INTVAL (x) != 8 && INTVAL (x) != 16
&& INTVAL (x) != 32 && INTVAL (x) != 64))
output_operand_lossage ("invalid %%M value"); output_operand_lossage ("invalid %%M value");
fprintf (file, "%s", fprintf (file, "%s",
INTVAL (x) == 8 ? "b" : INTVAL (x) == 16 ? "w" : "l"); (INTVAL (x) == 8 ? "b"
: INTVAL (x) == 16 ? "w"
: INTVAL (x) == 32 ? "l"
: "q"));
break; break;
case 'U': case 'U':
...@@ -1687,9 +2279,19 @@ print_operand (file, x, code) ...@@ -1687,9 +2279,19 @@ print_operand (file, x, code)
&& CONST_DOUBLE_HIGH (x) == 0 && CONST_DOUBLE_HIGH (x) == 0
&& CONST_DOUBLE_LOW (x) == -1) && CONST_DOUBLE_LOW (x) == -1)
fprintf (file, "l"); fprintf (file, "l");
else if (GET_CODE (x) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (x) == -1
&& CONST_DOUBLE_LOW (x) == -1)
fprintf (file, "q");
#else #else
else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff) else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff)
fprintf (file, "l"); fprintf (file, "l");
else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffffffffffff)
fprintf (file, "q");
else if (GET_CODE (x) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (x) == 0
&& CONST_DOUBLE_LOW (x) == -1)
fprintf (file, "q");
#endif #endif
else else
output_operand_lossage ("invalid %%U value"); output_operand_lossage ("invalid %%U value");
......
...@@ -384,18 +384,22 @@ extern void override_options (); ...@@ -384,18 +384,22 @@ extern void override_options ();
??? Kludge this and the next macro for the moment by not doing anything if ??? Kludge this and the next macro for the moment by not doing anything if
we don't optimize and also if we are writing ECOFF symbols to work around we don't optimize and also if we are writing ECOFF symbols to work around
a bug in DEC's assembler. */ a bug in DEC's assembler. */
/* Aligning past 2**3 wastes insn cache lines, and doesn't buy much
issue-wise on average anyway. */
#define ASM_OUTPUT_LOOP_ALIGN(FILE) \ #define ASM_OUTPUT_LOOP_ALIGN(FILE) \
if (optimize > 0 && write_symbols != SDB_DEBUG) \ if (optimize > 0 && write_symbols != SDB_DEBUG) \
ASM_OUTPUT_ALIGN (FILE, 5) ASM_OUTPUT_ALIGN (FILE, 3)
/* This is how to align an instruction for optimal branching. /* This is how to align an instruction for optimal branching.
On Alpha we'll get better performance by aligning on a quadword On Alpha we'll get better performance by aligning on a quadword
boundary. */ boundary. */
/* Aligning past 2**3 wastes insn cache lines, and doesn't buy much
issue-wise on average anyway. */
#define ASM_OUTPUT_ALIGN_CODE(FILE) \ #define ASM_OUTPUT_ALIGN_CODE(FILE) \
if (optimize > 0 && write_symbols != SDB_DEBUG) \ if (optimize > 0 && write_symbols != SDB_DEBUG) \
ASM_OUTPUT_ALIGN ((FILE), 4) ASM_OUTPUT_ALIGN ((FILE), 3)
/* No data type wants to be aligned rounder than this. */ /* No data type wants to be aligned rounder than this. */
#define BIGGEST_ALIGNMENT 64 #define BIGGEST_ALIGNMENT 64
...@@ -406,8 +410,12 @@ extern void override_options (); ...@@ -406,8 +410,12 @@ extern void override_options ();
/* Align all constants and variables to at least a word boundary so /* Align all constants and variables to at least a word boundary so
we can pick up pieces of them faster. */ we can pick up pieces of them faster. */
/* ??? Only if block-move stuff knows about different source/destination
alignment. */
#if 0
#define CONSTANT_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD) #define CONSTANT_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
#define DATA_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD) #define DATA_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
#endif
/* Set this non-zero if move instructions will actually fail to work /* Set this non-zero if move instructions will actually fail to work
when given unaligned data. when given unaligned data.
...@@ -1509,6 +1517,12 @@ extern void alpha_init_expanders (); ...@@ -1509,6 +1517,12 @@ extern void alpha_init_expanders ();
#define MOVE_MAX 8 #define MOVE_MAX 8
/* Controls how many units are moved by expr.c before resorting to movstr.
Without byte/word accesses, we want no more than one; with, several single
byte accesses are better. */
#define MOVE_RATIO (TARGET_BWX ? 7 : 2)
/* Largest number of bytes of an object that can be placed in a register. /* Largest number of bytes of an object that can be placed in a register.
On the Alpha we have plenty of registers, so use TImode. */ On the Alpha we have plenty of registers, so use TImode. */
#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (TImode) #define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (TImode)
......
...@@ -1431,7 +1431,7 @@ ...@@ -1431,7 +1431,7 @@
"ext%M2l %r1,%s3,%0" "ext%M2l %r1,%s3,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "" (define_insn "extxl"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(match_operand:DI 2 "mode_width_operand" "n") (match_operand:DI 2 "mode_width_operand" "n")
...@@ -1441,7 +1441,7 @@ ...@@ -1441,7 +1441,7 @@
"ext%M2l %r1,%3,%0" "ext%M2l %r1,%3,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "" (define_insn "extqh"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (ashift:DI
(match_operand:DI 1 "reg_or_0_operand" "rJ") (match_operand:DI 1 "reg_or_0_operand" "rJ")
...@@ -1456,7 +1456,7 @@ ...@@ -1456,7 +1456,7 @@
"extqh %r1,%2,%0" "extqh %r1,%2,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "" (define_insn "extlh"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (ashift:DI
(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
...@@ -1472,7 +1472,7 @@ ...@@ -1472,7 +1472,7 @@
"extlh %r1,%2,%0" "extlh %r1,%2,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "" (define_insn "extwh"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (ashift:DI
(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
...@@ -1538,7 +1538,7 @@ ...@@ -1538,7 +1538,7 @@
"insll %1,%s2,%0" "insll %1,%s2,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "" (define_insn "insbl"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r")) (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
...@@ -1547,7 +1547,7 @@ ...@@ -1547,7 +1547,7 @@
"insbl %1,%2,%0" "insbl %1,%2,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "" (define_insn "inswl"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r")) (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
...@@ -1556,7 +1556,7 @@ ...@@ -1556,7 +1556,7 @@
"inswl %1,%2,%0" "inswl %1,%2,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "" (define_insn "insll"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
...@@ -1565,10 +1565,30 @@ ...@@ -1565,10 +1565,30 @@
"insll %1,%2,%0" "insll %1,%2,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
(define_insn "insql"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (match_operand:DI 1 "register_operand" "r")
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
""
"insql %1,%2,%0"
[(set_attr "type" "shift")])
;; We do not include the insXh insns because they are complex to express ;; We do not include the insXh insns because they are complex to express
;; and it does not appear that we would ever want to generate them. ;; and it does not appear that we would ever want to generate them.
;;
;; Since we need them for block moves, though, cop out and use unspec.
(define_insn "" (define_insn "insxh"
[(set (match_operand:DI 0 "register_operand" "=r")
(unspec [(match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "mode_width_operand" "n")
(match_operand:DI 3 "reg_or_8bit_operand" "rI")] 2))]
""
"ins%M2h %1,%3,%0"
[(set_attr "type" "shift")])
(define_insn "mskxl"
[(set (match_operand:DI 0 "register_operand" "=r") [(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (not:DI (ashift:DI (and:DI (not:DI (ashift:DI
(match_operand:DI 2 "mode_mask_operand" "n") (match_operand:DI 2 "mode_mask_operand" "n")
...@@ -1580,8 +1600,19 @@ ...@@ -1580,8 +1600,19 @@
"msk%U2l %r1,%3,%0" "msk%U2l %r1,%3,%0"
[(set_attr "type" "shift")]) [(set_attr "type" "shift")])
;; We do not include the mskXh insns because it does not appear we would ever ;; We do not include the mskXh insns because it does not appear we would
;; generate one. ;; ever generate one.
;;
;; Again, we do for block moves and we use unspec again.
(define_insn "mskxh"
[(set (match_operand:DI 0 "register_operand" "=r")
(unspec [(match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "mode_width_operand" "n")
(match_operand:DI 3 "reg_or_8bit_operand" "rI")] 3))]
""
"msk%M2h %1,%3,%0"
[(set_attr "type" "shift")])
;; Floating-point operations. All the double-precision insns can extend ;; Floating-point operations. All the double-precision insns can extend
;; from single, so indicate that. The exception are the ones that simply ;; from single, so indicate that. The exception are the ones that simply
...@@ -4781,6 +4812,122 @@ ...@@ -4781,6 +4812,122 @@
DONE; DONE;
}") }")
;; Bit field extract patterns which use ext[wlq][lh]
(define_expand "extv"
[(set (match_operand:DI 0 "register_operand" "")
(sign_extract:DI (match_operand:QI 1 "memory_operand" "")
(match_operand:DI 2 "immediate_operand" "")
(match_operand:DI 3 "immediate_operand" "")))]
""
"
{
/* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */
if (INTVAL (operands[3]) % 8 != 0
|| (INTVAL (operands[2]) != 16
&& INTVAL (operands[2]) != 32
&& INTVAL (operands[2]) != 64))
FAIL;
/* From mips.md: extract_bit_field doesn't verify that our source
matches the predicate, so we force it to be a MEM here. */
if (GET_CODE (operands[1]) != MEM)
FAIL;
alpha_expand_unaligned_load (operands[0], operands[1],
INTVAL (operands[2]) / 8,
INTVAL (operands[3]) / 8, 1);
DONE;
}")
(define_expand "extzv"
[(set (match_operand:DI 0 "register_operand" "")
(zero_extract:DI (match_operand:QI 1 "memory_operand" "")
(match_operand:DI 2 "immediate_operand" "")
(match_operand:DI 3 "immediate_operand" "")))]
""
"
{
/* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */
if (INTVAL (operands[3]) % 8 != 0
|| (INTVAL (operands[2]) != 16
&& INTVAL (operands[2]) != 32
&& INTVAL (operands[2]) != 64))
FAIL;
/* From mips.md: extract_bit_field doesn't verify that our source
matches the predicate, so we force it to be a MEM here. */
if (GET_CODE (operands[1]) != MEM)
FAIL;
alpha_expand_unaligned_load (operands[0], operands[1],
INTVAL (operands[2]) / 8,
INTVAL (operands[3]) / 8, 0);
DONE;
}")
(define_expand "insv"
[(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "")
(match_operand:DI 1 "immediate_operand" "")
(match_operand:DI 2 "immediate_operand" ""))
(match_operand:DI 3 "register_operand" ""))]
""
"
{
/* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */
if (INTVAL (operands[2]) % 8 != 0
|| (INTVAL (operands[1]) != 16
&& INTVAL (operands[1]) != 32
&& INTVAL (operands[1]) != 64))
FAIL;
/* From mips.md: store_bit_field doesn't verify that our source
matches the predicate, so we force it to be a MEM here. */
if (GET_CODE (operands[0]) != MEM)
FAIL;
alpha_expand_unaligned_store (operands[0], operands[3],
INTVAL (operands[1]) / 8,
INTVAL (operands[2]) / 8);
DONE;
}")
;; Block move/clear, see alpha.c for more details.
;; Argument 0 is the destination
;; Argument 1 is the source
;; Argument 2 is the length
;; Argument 3 is the alignment
(define_expand "movstrqi"
[(parallel [(set (match_operand:BLK 0 "general_operand" "")
(match_operand:BLK 1 "general_operand" ""))
(use (match_operand:DI 2 "immediate_operand" ""))
(use (match_operand:DI 3 "immediate_operand" ""))])]
""
"
{
if (alpha_expand_block_move (operands))
DONE;
else
FAIL;
}")
(define_expand "clrstrqi"
[(parallel [(set (match_operand:BLK 0 "general_operand" "")
(const_int 0))
(use (match_operand:DI 1 "immediate_operand" ""))
(use (match_operand:DI 2 "immediate_operand" ""))])]
""
"
{
if (alpha_expand_block_clear (operands))
DONE;
else
FAIL;
}")
;; Subroutine of stack space allocation. Perform a stack probe. ;; Subroutine of stack space allocation. Perform a stack probe.
(define_expand "probe_stack" (define_expand "probe_stack"
[(set (match_dup 1) (match_operand:DI 0 "const_int_operand" ""))] [(set (match_dup 1) (match_operand:DI 0 "const_int_operand" ""))]
......
...@@ -9036,7 +9036,7 @@ expand_builtin (exp, target, subtarget, mode, ignore) ...@@ -9036,7 +9036,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|| (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
!= INTEGER_TYPE) != INTEGER_TYPE)
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0 || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
|| (INTEGER_CST || (INTEGER_TYPE
!= (TREE_CODE (TREE_TYPE != (TREE_CODE (TREE_TYPE
(TREE_VALUE (TREE_VALUE
(TREE_CHAIN (TREE_CHAIN (arglist)))))))) (TREE_CHAIN (TREE_CHAIN (arglist))))))))
...@@ -9061,10 +9061,15 @@ expand_builtin (exp, target, subtarget, mode, ignore) ...@@ -9061,10 +9061,15 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx) if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
break; break;
/* If LEN does not expand to a constant, don't do this
operation in-line. */
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
if (GET_CODE (len_rtx) != CONST_INT)
break;
dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM); dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM);
dest_mem = gen_rtx (MEM, BLKmode, dest_mem = gen_rtx (MEM, BLKmode,
memory_address (BLKmode, dest_rtx)); memory_address (BLKmode, dest_rtx));
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
/* Just check DST is writable and mark it as readable. */ /* Just check DST is writable and mark it as readable. */
if (flag_check_memory_usage) if (flag_check_memory_usage)
...@@ -9074,7 +9079,6 @@ expand_builtin (exp, target, subtarget, mode, ignore) ...@@ -9074,7 +9079,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
GEN_INT (MEMORY_USE_WO), GEN_INT (MEMORY_USE_WO),
TYPE_MODE (integer_type_node)); TYPE_MODE (integer_type_node));
/* There could be a void* cast on top of the object. */ /* There could be a void* cast on top of the object. */
while (TREE_CODE (dest) == NOP_EXPR) while (TREE_CODE (dest) == NOP_EXPR)
dest = TREE_OPERAND (dest, 0); dest = TREE_OPERAND (dest, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment