diff options
author | Alan Modra <alan@linuxcare.com.au> | 2000-03-27 22:10:09 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2000-03-27 22:10:09 -0800 |
commit | e3c2afabd3df995899ecf565616a410aa85e95a3 (patch) | |
tree | f3abf000592340351103d15a17ce92c8cc2b2ac8 | |
parent | 161897403ed49d37f05034008193379c8a2bc897 (diff) | |
download | gcc-e3c2afabd3df995899ecf565616a410aa85e95a3.zip gcc-e3c2afabd3df995899ecf565616a410aa85e95a3.tar.gz gcc-e3c2afabd3df995899ecf565616a410aa85e95a3.tar.bz2 |
Alan Modra <alan@linuxcare.com.au>
* config/i386/i386.c (output_387_binary_op): Correct intel
mode assembly output, and add spaces after commas in AT&T
output. Correct Unixware assembler comment. Document input
constraints. Comment fp operations. Reduce profligate buffer
size. Remove extraneous abort. Localize temp var.
(SYSV386_COMPAT): Define. Add !SYSV386_COMPAT code.
(output_fix_trunc): Add spaces after commas in assembly output.
From-SVN: r32778
-rw-r--r-- | gcc/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 104 |
2 files changed, 96 insertions, 26 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4f72a1b..c223a64 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2000-03-27 Alan Modra <alan@linuxcare.com.au> + + * config/i386/i386.c (output_387_binary_op): Correct intel + mode assembly output, and add spaces after commas in AT&T + output. Correct Unixware assembler comment. Document input + constraints. Comment fp operations. Reduce profligate buffer + size. Remove extraneous abort. Localize temp var. + (SYSV386_COMPAT): Define. Add !SYSV386_COMPAT code. + (output_fix_trunc): Add spaces after commas in assembly output. + 2000-03-27 Richard Henderson <rth@cygnus.com> * i386-protos.h (ix86_match_ccmode): Declare. @@ -575,8 +585,8 @@ Thu Mar 23 11:34:39 2000 Jim Wilson <wilson@cygnus.com> Thu Mar 23 16:04:40 2000 Andrew Haley <aph@cygnus.com> - * config/mips/mips.md (movdf_internal1a): Delete (set 'f', 'F') - alternative when using -fp64 -gp32. + * config/mips/mips.md (movdf_internal1a): Delete (set 'f', 'F') + alternative when using -fp64 -gp32. 2000-03-22 Jason Merrill <jason@casey.cygnus.com> @@ -594,7 +604,7 @@ Thu Mar 23 16:04:40 2000 Andrew Haley <aph@cygnus.com> 2000-03-22 Theodore Papadopoulo <Theodore.Papadopoulo@sophia.inria.fr> - * builtin.c (get_pointer_alignment): Use DECL_P and TYPE_P macros. + * builtin.c (get_pointer_alignment): Use DECL_P and TYPE_P macros. * c-common.c (decl_attributes,check_format_info,truthvalue_conversion, c_get_alias_set): Likewise. * c-decl.c (duplicate_decls): Likewise. @@ -679,7 +689,7 @@ Wed Mar 22 11:44:50 MET 2000 Jan Hubicka <jh@suse.cz> 2000-03-21 Richard Henderson <rth@cygnus.com> - * flow.c (delete_block): Fix typo last change. + * flow.c (delete_block): Fix typo last change. 2000-03-21 Mark Mitchell <mark@codesourcery.com> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9c755a5..d3f3a65 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -3434,15 +3434,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 +3513,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 +3529,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 +3562,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|rp\t%2, %0}"; + else + p = "{rp\t%2, %0|p\t%0, %2}"; +#else if (STACK_TOP_P (operands[0])) - p = "p\t%0,%2"; + /* 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 = "rp\t%2,%0"; + 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 +3688,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 ""; |