* i386.c (split_ti): New function.
(ix86_split_to_parts): Support TImodes.
* i386.h (VALID_INT_MODE_P): Add TImode.
* i386.md (movdi splitter): Fix.
(movti): Support 64bit integer registers.
(movti_rex64): New function and splitter.
* i386.c (*_cost): Add movsx/movzx cost.
* i386.h (struct processor_costs): Add movsx/movzx fields.
(RTX_COSTS): Handle zero/sign extend + avoid believing that
64bit operations require split on 64bit machine.
(CONST_COST): Make large 64bit constants expensive on 64bit compilation.
* i386.c (ix86_setup_incomming_varargs): Fix mode of PLUS.
(ix86_expand_move): Avoid pushes of memory if size does not match;
move long constants to register.
(x86_initialize_trampoline): Fix mode.
* i386.h (ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT):
Use ASM_QUAD on 64bit.
* i386.md (test pattern): Disallow impossible constants.
(tablejump PIC expander): Fix emitting of sum.
(movdicc_rex64): Rename to movdicc.
* linux64.h (LINK_SPEC): Add missing '%'.
From-SVN: r46296
+Wed Oct 17 00:01:02 CEST 2001 Jan Hubicka <jh@suse.cz>
+
+ * i386.c (split_ti): New function.
+ (ix86_split_to_parts): Support TImodes.
+ * i386.h (VALID_INT_MODE_P): Add TImode.
+ * i386.md (movdi splitter): Fix.
+ (movti): Support 64bit integer registers.
+ (movti_rex64): New function and splitter.
+
+ * i386.c (*_cost): Add movsx/movzx cost.
+ * i386.h (struct processor_costs): Add movsx/movzx fields.
+ (RTX_COSTS): Handle zero/sign extend + avoid believing that
+ 64bit operations require split on 64bit machine.
+ (CONST_COST): Make large 64bit constants expensive on 64bit compilation.
+
+ * i386.c (ix86_setup_incomming_varargs): Fix mode of PLUS.
+ (ix86_expand_move): Avoid pushes of memory if size does not match;
+ move long constants to register.
+ (x86_initialize_trampoline): Fix mode.
+ * i386.h (ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT):
+ Use ASM_QUAD on 64bit.
+ * i386.md (test pattern): Disallow impossible constants.
+ (tablejump PIC expander): Fix emitting of sum.
+ (movdicc_rex64): Rename to movdicc.
+ * linux64.h (LINK_SPEC): Add missing '%'.
+
2001-10-16 Alexandre Oliva <aoliva@redhat.com>
* tree-inline.c (inlinable_function_p): Leave it up to the
3, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
3, /* cost of a divide/mod */
+ 3, /* cost of movsx */
+ 3, /* cost of movzx */
0, /* "large" insn */
2, /* MOVE_RATIO */
2, /* cost for loading QImode using movzbl */
6, /* cost of starting a multiply */
1, /* cost of multiply per each bit set */
23, /* cost of a divide/mod */
+ 3, /* cost of movsx */
+ 2, /* cost of movzx */
15, /* "large" insn */
3, /* MOVE_RATIO */
4, /* cost for loading QImode using movzbl */
12, /* cost of starting a multiply */
1, /* cost of multiply per each bit set */
40, /* cost of a divide/mod */
+ 3, /* cost of movsx */
+ 2, /* cost of movzx */
15, /* "large" insn */
3, /* MOVE_RATIO */
4, /* cost for loading QImode using movzbl */
11, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
25, /* cost of a divide/mod */
+ 3, /* cost of movsx */
+ 2, /* cost of movzx */
8, /* "large" insn */
6, /* MOVE_RATIO */
6, /* cost for loading QImode using movzbl */
4, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
17, /* cost of a divide/mod */
+ 1, /* cost of movsx */
+ 1, /* cost of movzx */
8, /* "large" insn */
6, /* MOVE_RATIO */
2, /* cost for loading QImode using movzbl */
3, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
18, /* cost of a divide/mod */
+ 2, /* cost of movsx */
+ 2, /* cost of movzx */
8, /* "large" insn */
4, /* MOVE_RATIO */
3, /* cost for loading QImode using movzbl */
5, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
42, /* cost of a divide/mod */
+ 1, /* cost of movsx */
+ 1, /* cost of movzx */
8, /* "large" insn */
9, /* MOVE_RATIO */
4, /* cost for loading QImode using movzbl */
30, /* cost of starting a multiply */
0, /* cost of multiply per each bit set */
112, /* cost of a divide/mod */
+ 1, /* cost of movsx */
+ 1, /* cost of movzx */
16, /* "large" insn */
6, /* MOVE_RATIO */
2, /* cost for loading QImode using movzbl */
nsse_reg = gen_reg_rtx (Pmode);
emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, 0)));
emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
- gen_rtx_MULT (VOIDmode, nsse_reg,
+ gen_rtx_MULT (Pmode, nsse_reg,
GEN_INT (4))));
if (next_cum.sse_regno)
emit_move_insn
abort ();
}
}
+/* Split one or more TImode RTL references into pairs of SImode
+ references. The RTL can be REG, offsettable MEM, integer constant, or
+ CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
+ split and "num" is its length. lo_half and hi_half are output arrays
+ that parallel "operands". */
+
+void
+split_ti (operands, num, lo_half, hi_half)
+ rtx operands[];
+ int num;
+ rtx lo_half[], hi_half[];
+{
+ while (num--)
+ {
+ rtx op = operands[num];
+ if (CONSTANT_P (op))
+ {
+ if (GET_CODE (op) == CONST_INT)
+ {
+ lo_half[num] = GEN_INT (trunc_int_for_mode (INTVAL (op), SImode));
+ hi_half[num] = (1 << (HOST_BITS_PER_WIDE_INT -1)) != 0 ? constm1_rtx : const0_rtx;
+ }
+ else if (GET_CODE (op) == CONST_DOUBLE && HOST_BITS_PER_WIDE_INT == 64)
+ {
+ lo_half[num] = GEN_INT (trunc_int_for_mode (CONST_DOUBLE_LOW (op), SImode));
+ hi_half[num] = GEN_INT (trunc_int_for_mode (CONST_DOUBLE_HIGH (op), SImode));
+ }
+ else
+ abort ();
+ }
+ else if (! reload_completed)
+ {
+ lo_half[num] = gen_lowpart (DImode, op);
+ hi_half[num] = gen_highpart (DImode, op);
+ }
+ else if (GET_CODE (op) == REG)
+ {
+ if (TARGET_64BIT)
+ abort();
+ lo_half[num] = gen_rtx_REG (DImode, REGNO (op));
+ hi_half[num] = gen_rtx_REG (DImode, REGNO (op) + 1);
+ }
+ else if (offsettable_memref_p (op))
+ {
+ lo_half[num] = adjust_address (op, DImode, 0);
+ hi_half[num] = adjust_address (op, DImode, 8);
+ }
+ else
+ abort ();
+ }
+}
\f
/* Output code to perform a 387 binary operation in INSN, one of PLUS,
MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3]
else
{
if (GET_CODE (operands[0]) == MEM
- && (GET_MODE (operands[0]) == QImode
+ && (PUSH_ROUNDING (GET_MODE_SIZE (mode)) != GET_MODE_SIZE (mode)
|| !push_operand (operands[0], mode))
&& GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (mode, operands[1]);
&& ! general_no_elim_operand (operands[1], mode))
operands[1] = copy_to_mode_reg (mode, operands[1]);
+ /* Force large constants in 64bit compilation into register
+ to get them CSEed. */
+ if (TARGET_64BIT && mode == DImode
+ && immediate_operand (operands[1], mode)
+ && !x86_64_zero_extended_value (operands[1])
+ && !register_operand (operands[0], mode)
+ && optimize && !reload_completed && !reload_in_progress)
+ operands[1] = copy_to_mode_reg (mode, operands[1]);
+
if (FLOAT_MODE_P (mode))
{
/* If we are loading a floating point constant to a register,
}
else
{
+ if (mode == TImode)
+ split_ti (&operand, 1, &parts[0], &parts[1]);
if (mode == XFmode || mode == TFmode)
{
if (REG_P (operand))
/* Do not use shift by 32 to avoid warning on 32bit systems. */
if (HOST_BITS_PER_WIDE_INT >= 64)
parts[0]
- = GEN_INT (trunc_int_for_mode (l[0] + ((l[1] << 31) << 1),
- SImode));
+ = GEN_INT (trunc_int_for_mode
+ ((l[0] & (((HOST_WIDE_INT) 2 << 31) - 1))
+ + ((((HOST_WIDE_INT)l[1]) << 31) << 1),
+ DImode));
else
parts[0] = immed_double_const (l[0], l[1], DImode);
parts[1] = GEN_INT (trunc_int_for_mode (l[2], SImode));
emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)),
GEN_INT (trunc_int_for_mode (0xff49, HImode)));
emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, offset+2)),
- GEN_INT (trunc_int_for_mode (0xe3, HImode)));
+ GEN_INT (trunc_int_for_mode (0xe3, QImode)));
offset += 3;
if (offset > TRAMPOLINE_SIZE)
abort();
const int mult_init; /* cost of starting a multiply */
const int mult_bit; /* cost of multiply per each bit set */
const int divide; /* cost of a divide/mod */
+ int movsx; /* The cost of movsx operation. */
+ int movzx; /* The cost of movzx operation. */
const int large_insn; /* insns larger than this cost more */
const int move_ratio; /* The threshold of number of scalar
memory-to-memory move insns. */
((mode) == QImode || (mode) == HImode || (mode) == SImode \
|| (mode) == DImode \
|| (mode) == CQImode || (mode) == CHImode || (mode) == CSImode \
- || (mode) == CDImode)
+ || (mode) == CDImode \
+ || (TARGET_64BIT && ((mode) == TImode || (mode) == CTImode)))
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
+ if (TARGET_64BIT && !x86_64_sign_extended_value (RTX)) \
+ return 3; \
+ if (TARGET_64BIT && !x86_64_zero_extended_value (RTX)) \
+ return 2; \
return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0; \
\
case CONST_DOUBLE: \
assumptions are adequate for the target machine. */
#define RTX_COSTS(X,CODE,OUTER_CODE) \
+ case ZERO_EXTEND: \
+ /* The zero extensions is often completely free on x86_64, so make \
+ it as cheap as possible. */ \
+ if (TARGET_64BIT && GET_MODE (X) == DImode \
+ && GET_MODE (XEXP (X, 0)) == SImode) \
+ { \
+ total = 1; goto egress_rtx_costs; \
+ } \
+ else \
+ TOPLEVEL_COSTS_N_INSNS (TARGET_ZERO_EXTEND_WITH_AND ? \
+ ix86_cost->add : ix86_cost->movzx); \
+ break; \
+ case SIGN_EXTEND: \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->movsx); \
+ break; \
case ASHIFT: \
if (GET_CODE (XEXP (X, 1)) == CONST_INT \
- && GET_MODE (XEXP (X, 0)) == SImode) \
+ && (GET_MODE (XEXP (X, 0)) != DImode || TARGET_64BIT)) \
{ \
HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \
if (value == 1) \
case ASHIFTRT: \
case LSHIFTRT: \
case ROTATERT: \
- if (GET_MODE (XEXP (X, 0)) == DImode) \
+ if (!TARGET_64BIT && GET_MODE (XEXP (X, 0)) == DImode) \
{ \
if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
{ \
case IOR: \
case XOR: \
case MINUS: \
- if (GET_MODE (X) == DImode) \
+ if (!TARGET_64BIT && GET_MODE (X) == DImode) \
return (COSTS_N_INSNS (ix86_cost->add) * 2 \
+ (rtx_cost (XEXP (X, 0), OUTER_CODE) \
<< (GET_MODE (XEXP (X, 0)) != DImode)) \
/* fall through */ \
case NEG: \
case NOT: \
- if (GET_MODE (X) == DImode) \
+ if (!TARGET_64BIT && GET_MODE (X) == DImode) \
TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2); \
TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \
\
*/
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
- fprintf (FILE, "%s%s%d\n", ASM_LONG, LPREFIX, VALUE)
+ fprintf (FILE, "%s%s%d\n", TARGET_64BIT ? ASM_QUAD : ASM_LONG, LPREFIX, VALUE)
/* This is how to output an element of a case-vector that is relative.
We don't use these on the 386 yet, because the ATT assembler can't do
(const_int 0)))]
"TARGET_64BIT
&& ix86_match_ccmode (insn, CCNOmode)
+ /* The code bellow cannot deal with constants outside HOST_WIDE_INT. */
+ && INTVAL (operands[1]) + INTVAL (operands[2]) < HOST_BITS_PER_WIDE_INT
+ /* Ensure that resulting mask is zero or sign extended operand. */
+ && (INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
+ || (INTVAL (operands[1]) + INTVAL (operands[2]) == 64
+ && INTVAL (operands[1]) > 32))
&& (GET_MODE (operands[0]) == SImode
|| GET_MODE (operands[0]) == DImode
|| GET_MODE (operands[0]) == HImode
{
if (TARGET_64BIT)
operands[0] = expand_simple_binop (Pmode, PLUS, operands[0],
- operands[1], NULL_RTX, 0,
+ gen_rtx_LABEL_REF (Pmode, operands[1]),
+ NULL_RTX, 0,
OPTAB_DIRECT);
else
{
\f
;; Conditional move instructions.
-(define_expand "movdicc_rex64"
+(define_expand "movdicc"
[(set (match_operand:DI 0 "register_operand" "")
(if_then_else:DI (match_operand 1 "comparison_operator" "")
- (match_operand:DI 2 "x86_64_general_operand" "")
- (match_operand:DI 3 "x86_64_general_operand" "")))]
+ (match_operand:DI 2 "general_operand" "")
+ (match_operand:DI 3 "general_operand" "")))]
"TARGET_64BIT"
"if (!ix86_expand_int_movcc (operands)) FAIL; DONE;")
(define_expand "movti"
[(set (match_operand:TI 0 "general_operand" "")
(match_operand:TI 1 "general_operand" ""))]
- "TARGET_SSE"
+ "TARGET_SSE || TARGET_64BIT"
{
+ if (TARGET_64BIT)
+ {
+ ix86_expand_move (TImode, operands);
+ DONE;
+ }
/* For constants other than zero into memory. We do not know how the
instructions used to build constants modify the upper 64 bits
of the register, once we have that information we may be able
(define_insn "movti_internal"
[(set (match_operand:TI 0 "nonimmediate_operand" "=x,m")
(match_operand:TI 1 "general_operand" "xm,x"))]
- "TARGET_SSE"
+ "TARGET_SSE && !TARGET_64BIT"
"@
movaps\t{%1, %0|%0, %1}
movaps\t{%1, %0|%0, %1}"
[(set_attr "type" "sse")])
+(define_insn "*movti_rex64"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,mx,x")
+ (match_operand:DI 1 "general_operand" "riFo,riF,x,m"))]
+ "TARGET_64BIT
+ && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+ "@
+ #
+ #
+ movaps\\t{%1, %0|%0, %1}
+ movaps\\t{%1, %0|%0, %1}"
+ [(set_attr "type" "*,*,sse,sse")
+ (set_attr "mode" "TI")])
+
+(define_split
+ [(set (match_operand:TI 0 "nonimmediate_operand" "")
+ (match_operand:TI 1 "general_operand" ""))]
+ "reload_completed && GENERAL_REG_P (operands[0])
+ && GENERAL_REG_P (operands[1])"
+ [(const_int 0)]
+ "ix86_split_long_move (operands); DONE;")
+
;; These two patterns are useful for specifying exactly whether to use
;; movaps or movups
(define_insn "sse_movaps"
done. */
#undef LINK_SPEC
-#define LINK_SPEC "%{!m32:-m elf_x86_64} %{m32:-m elf_i386} {shared:-shared} \
+#define LINK_SPEC "%{!m32:-m elf_x86_64} %{m32:-m elf_i386} %{shared:-shared} \
%{!shared: \
%{!static: \
%{rdynamic:-export-dynamic} \