From 5f1ec3e625e734ce2d9f8d9f91c458c7766102eb Mon Sep 17 00:00:00 2001 From: James Van Artsdalen Date: Sun, 3 Oct 1993 23:54:14 +0000 Subject: [PATCH] (output_op_from_reg): Handle 3-word XFmode values. (output_to_reg): Likewise. (output_move_double): Handle XFmode operands. (output_move_const_single): Use REAL_VALUE_TO_TARGET_SINGLE. (print_operand): Add letter `T', size `12'. Use REAL_VALUE macros to convert floating point operands. (convert_387_op): Add XFmode to case FLOAT_EXTEND. From-SVN: r5571 --- gcc/config/i386/i386.c | 276 +++++++++++++++++++++++++++++++++-------- 1 file changed, 221 insertions(+), 55 deletions(-) diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index d0b11961b7b..a05ca94d07c 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -98,15 +98,22 @@ output_op_from_reg (src, template) char *template; { rtx xops[4]; + int size = GET_MODE_SIZE (GET_MODE (src)); xops[0] = src; xops[1] = AT_SP (Pmode); - xops[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (src))); + xops[2] = GEN_INT (size); xops[3] = stack_pointer_rtx; - if (GET_MODE_SIZE (GET_MODE (src)) > UNITS_PER_WORD) + if (size > UNITS_PER_WORD) { - rtx high = gen_rtx (REG, SImode, REGNO (src) + 1); + rtx high; + if (size > 2 * UNITS_PER_WORD) + { + high = gen_rtx (REG, SImode, REGNO (src) + 2); + output_asm_insn (AS1 (push%L0,%0), &high); + } + high = gen_rtx (REG, SImode, REGNO (src) + 1); output_asm_insn (AS1 (push%L0,%0), &high); } output_asm_insn (AS1 (push%L0,%0), &src); @@ -127,10 +134,11 @@ output_to_reg (dest, dies) int dies; { rtx xops[4]; + int size = GET_MODE_SIZE (GET_MODE (dest)); xops[0] = AT_SP (Pmode); xops[1] = stack_pointer_rtx; - xops[2] = GEN_INT (GET_MODE_SIZE (GET_MODE (dest))); + xops[2] = GEN_INT (size); xops[3] = dest; output_asm_insn (AS2 (sub%L1,%2,%1), xops); @@ -147,17 +155,27 @@ output_to_reg (dest, dies) if (dies) output_asm_insn (AS1 (fstp%z3,%y0), xops); else - output_asm_insn (AS1 (fst%z3,%y0), xops); + { + if (GET_MODE (dest) == XFmode) + abort (); + else + output_asm_insn (AS1 (fst%z3,%y0), xops); + } } else abort (); output_asm_insn (AS1 (pop%L0,%0), &dest); - if (GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD) + if (size > UNITS_PER_WORD) { dest = gen_rtx (REG, SImode, REGNO (dest) + 1); output_asm_insn (AS1 (pop%L0,%0), &dest); + if (size > 2 * UNITS_PER_WORD) + { + dest = gen_rtx (REG, SImode, REGNO (dest) + 1); + output_asm_insn (AS1 (pop%L0,%0), &dest); + } } } @@ -243,8 +261,14 @@ output_move_double (operands) { enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; + rtx middlehalf[2]; + rtx xops[2]; rtx addreg0 = 0, addreg1 = 0; int dest_overlapped_low = 0; + int size = GET_MODE_SIZE (GET_MODE (operands[1])); + + middlehalf[0] = 0; + middlehalf[1] = 0; /* First classify both operands. */ @@ -289,16 +313,29 @@ output_move_double (operands) if (optype0 == PUSHOP && optype1 == POPOP) { + /* ??? Can this ever happen on i386? */ operands[0] = XEXP (XEXP (operands[0], 0), 0); - asm_add (-8, operands[0]); - operands[0] = gen_rtx (MEM, DImode, operands[0]); + asm_add (-size, operands[0]); + if (GET_MODE (operands[1]) == XFmode) + operands[0] = gen_rtx (MEM, XFmode, operands[0]); + else if (GET_MODE (operands[0]) == DFmode) + operands[0] = gen_rtx (MEM, DFmode, operands[0]); + else + operands[0] = gen_rtx (MEM, DImode, operands[0]); optype0 = OFFSOP; } + if (optype0 == POPOP && optype1 == PUSHOP) { + /* ??? Can this ever happen on i386? */ operands[1] = XEXP (XEXP (operands[1], 0), 0); - asm_add (-8, operands[1]); - operands[1] = gen_rtx (MEM, DImode, operands[1]); + asm_add (-size, operands[1]); + if (GET_MODE (operands[1]) == XFmode) + operands[1] = gen_rtx (MEM, XFmode, operands[1]); + else if (GET_MODE (operands[1]) == DFmode) + operands[1] = gen_rtx (MEM, DFmode, operands[1]); + else + operands[1] = gen_rtx (MEM, DImode, operands[1]); optype1 = OFFSOP; } @@ -320,31 +357,87 @@ output_move_double (operands) for the high-numbered word and in some cases alter the operands in OPERANDS to be suitable for the low-numbered word. */ - if (optype0 == REGOP) - latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); - else if (optype0 == OFFSOP) - latehalf[0] = adj_offsettable_operand (operands[0], 4); - else - latehalf[0] = operands[0]; + if (size == 12) + { + if (optype0 == REGOP) + { + middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2); + } + else if (optype0 == OFFSOP) + { + middlehalf[0] = adj_offsettable_operand (operands[0], 4); + latehalf[0] = adj_offsettable_operand (operands[0], 8); + } + else + { + middlehalf[0] = operands[0]; + latehalf[0] = operands[0]; + } + + if (optype1 == REGOP) + { + middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2); + } + else if (optype1 == OFFSOP) + { + middlehalf[1] = adj_offsettable_operand (operands[1], 4); + latehalf[1] = adj_offsettable_operand (operands[1], 8); + } + else if (optype1 == CNSTOP) + { + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + REAL_VALUE_TYPE r; long l[3]; - if (optype1 == REGOP) - latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); - else if (optype1 == OFFSOP) - latehalf[1] = adj_offsettable_operand (operands[1], 4); - else if (optype1 == CNSTOP) + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); + operands[1] = GEN_INT (l[0]); + middlehalf[1] = GEN_INT (l[1]); + latehalf[1] = GEN_INT (l[2]); + } + else if (CONSTANT_P (operands[1])) + /* No non-CONST_DOUBLE constant should ever appear here. */ + abort (); + } + else + { + middlehalf[1] = operands[1]; + latehalf[1] = operands[1]; + } + } + else /* size is not 12: */ { - if (GET_CODE (operands[1]) == CONST_DOUBLE) - split_double (operands[1], &operands[1], &latehalf[1]); - else if (CONSTANT_P (operands[1])) + if (optype0 == REGOP) + latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + else if (optype0 == OFFSOP) + latehalf[0] = adj_offsettable_operand (operands[0], 4); + else + latehalf[0] = operands[0]; + + if (optype1 == REGOP) + latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); + else if (optype1 == OFFSOP) + latehalf[1] = adj_offsettable_operand (operands[1], 4); + else if (optype1 == CNSTOP) { - if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0) - latehalf[1] = constm1_rtx; - else - latehalf[1] = const0_rtx; + if (GET_CODE (operands[1]) == CONST_DOUBLE) + split_double (operands[1], &operands[1], &latehalf[1]); + else if (CONSTANT_P (operands[1])) + { + /* ??? jrv: Can this really happen? A DImode constant + that isn't a CONST_DOUBLE? */ + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 0) + latehalf[1] = constm1_rtx; + else + latehalf[1] = const0_rtx; + } } + else + latehalf[1] = operands[1]; } - else - latehalf[1] = operands[1]; /* If insn is effectively movd N (sp),-(sp) then we will do the high word first. We should use the adjusted operand 1 (which is N+4 (sp)) @@ -367,12 +460,40 @@ output_move_double (operands) { /* If both halves of dest are used in the src memory address, compute the address into latehalf of dest. */ - rtx xops[2]; +compadr: xops[0] = latehalf[0]; xops[1] = XEXP (operands[1], 0); output_asm_insn (AS2 (lea%L0,%a1,%0), xops); - operands[1] = gen_rtx (MEM, DImode, latehalf[0]); - latehalf[1] = adj_offsettable_operand (operands[1], 4); + if( GET_MODE (operands[1]) == XFmode ) + { +/* abort (); */ + operands[1] = gen_rtx (MEM, XFmode, latehalf[0]); + middlehalf[1] = adj_offsettable_operand (operands[1], size-8); + latehalf[1] = adj_offsettable_operand (operands[1], size-4); + } + else + { + operands[1] = gen_rtx (MEM, DImode, latehalf[0]); + latehalf[1] = adj_offsettable_operand (operands[1], size-4); + } + } + else if (size == 12 + && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0))) + { + /* Check for two regs used by both source and dest. */ + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) + || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + goto compadr; + + /* JRV says this can't happen: */ + if (addreg0 || addreg1) + abort(); + + /* Only the middle reg conflicts; simply put it last. */ + output_asm_insn (singlemove_string (operands), operands); + output_asm_insn (singlemove_string (latehalf), latehalf); + output_asm_insn (singlemove_string (middlehalf), middlehalf); + return ""; } else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))) /* If the low half of dest is mentioned in the source memory @@ -388,16 +509,23 @@ output_move_double (operands) such overlap can't happen in memory unless the user explicitly sets it up, and that is an undefined circumstance. */ +/* if (optype0 == PUSHOP || optype1 == PUSHOP || (optype0 == REGOP && optype1 == REGOP && REGNO (operands[0]) == REGNO (latehalf[1])) || dest_overlapped_low) +*/ + if (optype0 == PUSHOP || optype1 == PUSHOP + || (optype0 == REGOP && optype1 == REGOP + && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1])) + || REGNO (operands[0]) == REGNO (latehalf[1]))) + || dest_overlapped_low) { /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) - asm_add (4, addreg0); + asm_add (size-4, addreg0); if (addreg1) - asm_add (4, addreg1); + asm_add (size-4, addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); @@ -408,6 +536,15 @@ output_move_double (operands) if (addreg1) asm_add (-4, addreg1); + if (size == 12) + { + output_asm_insn (singlemove_string (middlehalf), middlehalf); + if (addreg0) + asm_add (-4, addreg0); + if (addreg1) + asm_add (-4, addreg1); + } + /* Do low-numbered word. */ return singlemove_string (operands); } @@ -416,6 +553,17 @@ output_move_double (operands) output_asm_insn (singlemove_string (operands), operands); + /* Do the middle one of the three words for long double */ + if (size == 12) + { + if (addreg0) + asm_add (4, addreg0); + if (addreg1) + asm_add (4, addreg1); + + output_asm_insn (singlemove_string (middlehalf), middlehalf); + } + /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) asm_add (4, addreg0); @@ -427,9 +575,9 @@ output_move_double (operands) /* Undo the adds we just did. */ if (addreg0) - asm_add (-4, addreg0); + asm_add (4-size, addreg0); if (addreg1) - asm_add (-4, addreg1); + asm_add (4-size, addreg1); return ""; } @@ -482,12 +630,14 @@ output_move_const_single (operands) } if (GET_CODE (operands[1]) == CONST_DOUBLE) { - union { int i[2]; double d;} u1; - union { int i; float f;} u2; - u1.i[0] = CONST_DOUBLE_LOW (operands[1]); - u1.i[1] = CONST_DOUBLE_HIGH (operands[1]); - u2.f = u1.d; - operands[1] = GEN_INT (u2.i); + REAL_VALUE_TYPE r; long l; + + if (GET_MODE (operands[1]) == XFmode) + abort (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (r, l); + operands[1] = GEN_INT (l); } return singlemove_string (operands); } @@ -1045,6 +1195,10 @@ print_operand (file, x, code) PUT_OP_SIZE (code, 's', file); return; + case 'T': + PUT_OP_SIZE (code, 't', file); + return; + case 'z': /* 387 opcodes don't get size suffixes if the operands are registers. */ @@ -1073,6 +1227,10 @@ print_operand (file, x, code) PUT_OP_SIZE ('L', 'l', file); return; + case 12: + PUT_OP_SIZE ('T', 't', file); + return; + case 8: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) { @@ -1124,20 +1282,26 @@ print_operand (file, x, code) } else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) { - union { double d; int i[2]; } u; - union { float f; int i; } u1; - u.i[0] = CONST_DOUBLE_LOW (x); - u.i[1] = CONST_DOUBLE_HIGH (x); - u1.f = u.d; + REAL_VALUE_TYPE r; long l; + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + REAL_VALUE_TO_TARGET_SINGLE (r, l); PRINT_IMMED_PREFIX (file); - fprintf (file, "0x%x", u1.i); + fprintf (file, "0x%x", l); + } + /* These float cases don't actually occur as immediate operands. */ + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) + { + REAL_VALUE_TYPE r; char dstr[30]; + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); + fprintf (file, "%s", dstr); } - else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode) { - union { double d; int i[2]; } u; - u.i[0] = CONST_DOUBLE_LOW (x); - u.i[1] = CONST_DOUBLE_HIGH (x); - fprintf (file, "%.22e", u.d); + REAL_VALUE_TYPE r; char dstr[30]; + REAL_VALUE_FROM_CONST_DOUBLE (r, x); + REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); + fprintf (file, "%s", dstr); } else { @@ -1500,7 +1664,9 @@ convert_387_op (op, mode) return GET_MODE (XEXP (op, 0)) == SImode; case FLOAT_EXTEND: - return mode == DFmode && GET_MODE (XEXP (op, 0)) == SFmode; + return ((mode == DFmode && GET_MODE (XEXP (op, 0)) == SFmode) + || (mode == XFmode && GET_MODE (XEXP (op, 0)) == DFmode) + || (mode == XFmode && GET_MODE (XEXP (op, 0)) == SFmode)); default: return 0; -- 2.30.2