aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/i386/i386.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/i386/i386.c')
-rw-r--r--gcc/config/i386/i386.c205
1 files changed, 156 insertions, 49 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 9fc4425eba1..9eb13ea3559 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1373,7 +1373,7 @@ memory_displacement_operand (op, mode)
return parts.disp != NULL_RTX;
}
-/* To avoid problems when jump re-emits comparisons like testqi_ext_0,
+/* To avoid problems when jump re-emits comparisons like testqi_ext_ccno_0,
re-recognize the operand to avoid a copy_to_mode_reg that will fail.
??? It seems likely that this will only work because cmpsi is an
@@ -1449,12 +1449,12 @@ aligned_operand (op, mode)
if (parts.index)
{
if (parts.scale < 4
- && REGNO_POINTER_ALIGN (REGNO (parts.index)) < 4)
+ && REGNO_POINTER_ALIGN (REGNO (parts.index)) < 32)
return 0;
}
if (parts.base)
{
- if (REGNO_POINTER_ALIGN (REGNO (parts.base)) < 4)
+ if (REGNO_POINTER_ALIGN (REGNO (parts.base)) < 32)
return 0;
}
if (parts.disp)
@@ -1797,6 +1797,9 @@ ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2)
offset += nregs * UNITS_PER_WORD;
+ if (ACCUMULATE_OUTGOING_ARGS)
+ total_size += current_function_outgoing_args_size;
+
total_size += offset;
/* Align start of frame for local function. */
@@ -1808,6 +1811,9 @@ ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2)
padding2 = ((total_size + preferred_alignment - 1)
& -preferred_alignment) - total_size;
+ if (ACCUMULATE_OUTGOING_ARGS)
+ padding2 += current_function_outgoing_args_size;
+
if (nregs_on_stack)
*nregs_on_stack = nregs;
if (rpadding1)
@@ -3103,12 +3109,10 @@ print_operand (file, x, code)
/* this is the size of op from size of operand */
switch (GET_MODE_SIZE (GET_MODE (x)))
{
- case 1:
- putc ('b', file);
- return;
-
case 2:
- putc ('w', file);
+#ifdef HAVE_GAS_FILDS_FISTS
+ putc ('s', file);
+#endif
return;
case 4:
@@ -3138,6 +3142,9 @@ print_operand (file, x, code)
else
putc ('l', file);
return;
+
+ default:
+ abort ();
}
case 'b':
@@ -3434,15 +3441,39 @@ split_di (operands, num, lo_half, hi_half)
There is no guarantee that the operands are the same mode, as they
might be within FLOAT or FLOAT_EXTEND expressions. */
+#ifndef SYSV386_COMPAT
+/* Set to 1 for compatibility with brain-damaged assemblers. No-one
+ wants to fix the assemblers because that causes incompatibility
+ with gcc. No-one wants to fix gcc because that causes
+ incompatibility with assemblers... You can use the option of
+ -DSYSV386_COMPAT=0 if you recompile both gcc and gas this way. */
+#define SYSV386_COMPAT 1
+#endif
+
const char *
output_387_binary_op (insn, operands)
rtx insn;
rtx *operands;
{
- static char buf[100];
- rtx temp;
+ static char buf[30];
const char *p;
+#ifdef ENABLE_CHECKING
+ /* Even if we do not want to check the inputs, this documents input
+ constraints. Which helps in understanding the following code. */
+ if (STACK_REG_P (operands[0])
+ && ((REG_P (operands[1])
+ && REGNO (operands[0]) == REGNO (operands[1])
+ && (STACK_REG_P (operands[2]) || GET_CODE (operands[2]) == MEM))
+ || (REG_P (operands[2])
+ && REGNO (operands[0]) == REGNO (operands[2])
+ && (STACK_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM)))
+ && (STACK_TOP_P (operands[1]) || STACK_TOP_P (operands[2])))
+ ; /* ok */
+ else
+ abort ();
+#endif
+
switch (GET_CODE (operands[3]))
{
case PLUS:
@@ -3489,11 +3520,13 @@ output_387_binary_op (insn, operands)
case PLUS:
if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
{
- temp = operands[2];
+ rtx temp = operands[2];
operands[2] = operands[1];
operands[1] = temp;
}
+ /* know operands[0] == operands[1]. */
+
if (GET_CODE (operands[2]) == MEM)
{
p = "%z2\t%2";
@@ -3503,16 +3536,23 @@ output_387_binary_op (insn, operands)
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
{
if (STACK_TOP_P (operands[0]))
- p = "p\t{%0,%2|%2, %0}";
+ /* How is it that we are storing to a dead operand[2]?
+ Well, presumably operands[1] is dead too. We can't
+ store the result to st(0) as st(0) gets popped on this
+ instruction. Instead store to operands[2] (which I
+ think has to be st(1)). st(1) will be popped later.
+ gcc <= 2.8.1 didn't have this check and generated
+ assembly code that the Unixware assembler rejected. */
+ p = "p\t{%0, %2|%2, %0}"; /* st(1) = st(0) op st(1); pop */
else
- p = "p\t{%2,%0|%0, %2}";
+ p = "p\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0); pop */
break;
}
if (STACK_TOP_P (operands[0]))
- p = "\t{%y2,%0|%0, %y2}";
+ p = "\t{%y2, %0|%0, %y2}"; /* st(0) = st(0) op st(r2) */
else
- p = "\t{%2,%0|%0, %2}";
+ p = "\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0) */
break;
case MINUS:
@@ -3529,42 +3569,69 @@ output_387_binary_op (insn, operands)
break;
}
- if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
- abort ();
-
- /* Note that the Unixware assembler, and the AT&T assembler before
- that, are confusingly not reversed from Intel syntax in this
- area. */
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
{
+#if SYSV386_COMPAT
+ /* The SystemV/386 SVR3.2 assembler, and probably all AT&T
+ derived assemblers, confusingly reverse the direction of
+ the operation for fsub{r} and fdiv{r} when the
+ destination register is not st(0). The Intel assembler
+ doesn't have this brain damage. Read !SYSV386_COMPAT to
+ figure out what the hardware really does. */
if (STACK_TOP_P (operands[0]))
- p = "p\t%0,%2";
+ p = "{p\t%0, %2|rp\t%2, %0}";
else
- p = "rp\t%2,%0";
+ p = "{rp\t%2, %0|p\t%0, %2}";
+#else
+ if (STACK_TOP_P (operands[0]))
+ /* As above for fmul/fadd, we can't store to st(0). */
+ p = "rp\t{%0, %2|%2, %0}"; /* st(1) = st(0) op st(1); pop */
+ else
+ p = "p\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0); pop */
+#endif
break;
}
if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
{
+#if SYSV386_COMPAT
if (STACK_TOP_P (operands[0]))
- p = "rp\t%0,%1";
+ p = "{rp\t%0, %1|p\t%1, %0}";
else
- p = "p\t%1,%0";
+ p = "{p\t%1, %0|rp\t%0, %1}";
+#else
+ if (STACK_TOP_P (operands[0]))
+ p = "p\t{%0, %1|%1, %0}"; /* st(1) = st(1) op st(0); pop */
+ else
+ p = "rp\t{%1, %0|%0, %1}"; /* st(r2) = st(0) op st(r2); pop */
+#endif
break;
}
if (STACK_TOP_P (operands[0]))
{
if (STACK_TOP_P (operands[1]))
- p = "\t%y2,%0";
+ p = "\t{%y2, %0|%0, %y2}"; /* st(0) = st(0) op st(r2) */
else
- p = "r\t%y1,%0";
+ p = "r\t{%y1, %0|%0, %y1}"; /* st(0) = st(r1) op st(0) */
break;
}
else if (STACK_TOP_P (operands[1]))
- p = "\t%1,%0";
+ {
+#if SYSV386_COMPAT
+ p = "{\t%1, %0|r\t%0, %1}";
+#else
+ p = "r\t{%1, %0|%0, %1}"; /* st(r2) = st(0) op st(r2) */
+#endif
+ }
else
- p = "r\t%2,%0";
+ {
+#if SYSV386_COMPAT
+ p = "{r\t%2, %0|\t%0, %2}";
+#else
+ p = "\t{%2, %0|%0, %2}"; /* st(r1) = st(r1) op st(0) */
+#endif
+ }
break;
default:
@@ -3628,7 +3695,7 @@ output_fix_trunc (insn, operands)
output_asm_insn ("mov{l}\t{%3, %1|%1, %3}", xops);
}
else
- output_asm_insn ("mov{l}\t{%3,%0|%0, %3}", operands);
+ output_asm_insn ("mov{l}\t{%3, %0|%0, %3}", operands);
}
return "";
@@ -4252,6 +4319,45 @@ ix86_unary_operator_ok (code, mode, operands)
return TRUE;
}
+/* Return TRUE or FALSE depending on whether the first SET in INSN
+ has source and destination with matching CC modes, and that the
+ CC mode is at least as constrained as REQ_MODE. */
+
+int
+ix86_match_ccmode (insn, req_mode)
+ rtx insn;
+ enum machine_mode req_mode;
+{
+ rtx set;
+ enum machine_mode set_mode;
+
+ set = PATTERN (insn);
+ if (GET_CODE (set) == PARALLEL)
+ set = XVECEXP (set, 0, 0);
+ if (GET_CODE (set) != SET)
+ abort ();
+
+ set_mode = GET_MODE (SET_DEST (set));
+ switch (set_mode)
+ {
+ case CCmode:
+ if (req_mode == CCNOmode)
+ return 0;
+ /* FALLTHRU */
+ case CCNOmode:
+ if (req_mode == CCZmode)
+ return 0;
+ /* FALLTHRU */
+ case CCZmode:
+ break;
+
+ default:
+ abort ();
+ }
+
+ return (GET_MODE (SET_SRC (set)) == set_mode);
+}
+
/* Produce an unsigned comparison for a given signed comparison. */
static enum rtx_code
@@ -4455,7 +4561,7 @@ ix86_expand_fp_compare (code, op0, op1, unordered)
abort ();
}
- emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (mask)));
+ emit_insn (gen_testqi_ext_ccno_0 (tmp, GEN_INT (mask)));
intcmp_mode = CCNOmode;
}
}
@@ -4470,7 +4576,7 @@ ix86_expand_fp_compare (code, op0, op1, unordered)
switch (code)
{
case GT:
- emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (0x45)));
+ emit_insn (gen_testqi_ext_ccno_0 (tmp, GEN_INT (0x45)));
code = EQ;
break;
case LT:
@@ -4480,7 +4586,7 @@ ix86_expand_fp_compare (code, op0, op1, unordered)
code = EQ;
break;
case GE:
- emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (0x05)));
+ emit_insn (gen_testqi_ext_ccno_0 (tmp, GEN_INT (0x05)));
code = EQ;
break;
case LE:
@@ -5490,7 +5596,8 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
rtx align_4_label = gen_label_rtx ();
rtx end_0_label = gen_label_rtx ();
rtx mem;
- rtx flags = gen_rtx_REG (CCNOmode, FLAGS_REG);
+ rtx no_flags = gen_rtx_REG (CCNOmode, FLAGS_REG);
+ rtx z_flags = gen_rtx_REG (CCNOmode, FLAGS_REG);
rtx tmpreg = gen_reg_rtx (SImode);
align = 0;
@@ -5512,25 +5619,25 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
align_rtx = expand_binop (SImode, and_optab, scratch, GEN_INT (3),
NULL_RTX, 0, OPTAB_WIDEN);
- emit_insn (gen_cmpsi_0 (align_rtx, const0_rtx));
+ emit_insn (gen_cmpsi_ccz_1 (align_rtx, const0_rtx));
- tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_EQ (VOIDmode, z_flags, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode,
align_4_label),
pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
- emit_insn (gen_cmpsi_1 (align_rtx, GEN_INT (2)));
+ emit_insn (gen_cmpsi_ccno_1 (align_rtx, GEN_INT (2)));
- tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_EQ (VOIDmode, no_flags, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode,
align_2_label),
pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
- tmp = gen_rtx_GTU (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_GTU (VOIDmode, no_flags, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode,
align_3_label),
@@ -5545,9 +5652,9 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
align_rtx = expand_binop (SImode, and_optab, scratch, GEN_INT (2),
NULL_RTX, 0, OPTAB_WIDEN);
- emit_insn (gen_cmpsi_0 (align_rtx, const0_rtx));
+ emit_insn (gen_cmpsi_ccz_1 (align_rtx, const0_rtx));
- tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_EQ (VOIDmode, z_flags, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode,
align_4_label),
@@ -5560,9 +5667,9 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
/* Now compare the bytes. */
/* Compare the first n unaligned byte on a byte per byte basis. */
- emit_insn (gen_cmpqi_0 (mem, const0_rtx));
+ emit_insn (gen_cmpqi_ccz_1 (mem, const0_rtx));
- tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_EQ (VOIDmode, z_flags, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode, end_0_label),
pc_rtx);
@@ -5576,9 +5683,9 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
{
emit_label (align_2_label);
- emit_insn (gen_cmpqi_0 (mem, const0_rtx));
+ emit_insn (gen_cmpqi_ccz_1 (mem, const0_rtx));
- tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_EQ (VOIDmode, z_flags, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode,
end_0_label),
@@ -5590,9 +5697,9 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
emit_label (align_3_label);
}
- emit_insn (gen_cmpqi_0 (mem, const0_rtx));
+ emit_insn (gen_cmpqi_ccz_1 (mem, const0_rtx));
- tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx);
+ tmp = gen_rtx_EQ (VOIDmode, z_flags, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode, end_0_label),
pc_rtx);
@@ -5626,7 +5733,7 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
emit_insn (gen_lshrsi3 (reg, reg, GEN_INT (16)));
/* If zero is not in the first two bytes, move two bytes forward. */
- emit_insn (gen_testsi_1 (tmpreg, GEN_INT (0x8080)));
+ emit_insn (gen_testsi_ccno_1 (tmpreg, GEN_INT (0x8080)));
tmp = gen_rtx_REG (CCNOmode, FLAGS_REG);
tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
emit_insn (gen_rtx_SET (VOIDmode, tmpreg,
@@ -5650,7 +5757,7 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch)
rtx end_2_label = gen_label_rtx ();
/* Is zero in the first two bytes? */
- emit_insn (gen_testsi_1 (tmpreg, GEN_INT (0x8080)));
+ emit_insn (gen_testsi_ccno_1 (tmpreg, GEN_INT (0x8080)));
tmp = gen_rtx_REG (CCNOmode, FLAGS_REG);
tmp = gen_rtx_NE (VOIDmode, tmp, const0_rtx);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,