--- gcc/config/i386/i386.c 2018/04/24 18:10:27 1.1 +++ gcc/config/i386/i386.c 2018/04/24 18:16:53 1.1.1.2 @@ -31,6 +31,7 @@ the Free Software Foundation, 675 Mass A #include "insn-attr.h" #include "tree.h" #include "flags.h" +#include "function.h" #ifdef EXTRA_CONSTRAINT /* If EXTRA_CONSTRAINT is defined, then the 'S' @@ -98,15 +99,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 +135,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 +156,30 @@ 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) + { + output_asm_insn (AS1 (fstp%z3,%y0), xops); + output_asm_insn (AS1 (fld%z3,%y0), xops); + } + 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 +265,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 +317,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,39 +361,97 @@ 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) - { - if (GET_CODE (operands[1]) == CONST_DOUBLE) - split_double (operands[1], &operands[1], &latehalf[1]); - else if (CONSTANT_P (operands[1])) + 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 { - if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0) - latehalf[1] = constm1_rtx; - else - latehalf[1] = const0_rtx; + middlehalf[1] = operands[1]; + latehalf[1] = operands[1]; } } - else - latehalf[1] = operands[1]; + else /* size is not 12: */ + { + 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_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]; + } /* 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)) - for the low word as well, to compensate for the first decrement of sp. */ + high word first. We should use the adjusted operand 1 + (which is N+4 (sp) or N+8 (sp)) + for the low word and middle word as well, + to compensate for the first decrement of sp. */ if (optype0 == PUSHOP && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) - operands[1] = latehalf[1]; + middlehalf[1] = operands[1] = latehalf[1]; /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)), if the upper part of reg N does not appear in the MEM, arrange to @@ -367,12 +466,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 +515,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 +542,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 +559,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 +581,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 +636,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 +1201,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 +1233,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 +1288,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); } - else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) + /* These float cases don't actually occur as immediate operands. */ + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) { - 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 if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode) + { + 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 +1670,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; @@ -1883,9 +2055,37 @@ output_fp_cc0_set (insn) static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; +/* Define the structure for the machine field in struct function. */ +struct machine_function +{ + rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; +}; + +/* Functions to save and restore i386_stack_locals. + These will be called, via pointer variables, + from push_function_context and pop_function_context. */ + +void +save_386_machine_status (p) + struct function *p; +{ + p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals); + bcopy (i386_stack_locals, p->machine->i386_stack_locals, + sizeof i386_stack_locals); +} + +void +restore_386_machine_status (p) + struct function *p; +{ + bcopy (p->machine->i386_stack_locals, i386_stack_locals, + sizeof i386_stack_locals); + free (p->machine); +} + /* Clear stack slot assignments remembered from previous functions. This is called from INIT_EXPANDERS once before RTL is emitted for each - function. */ + function. */ void clear_386_stack_locals () @@ -1897,6 +2097,10 @@ clear_386_stack_locals () mode = (enum machine_mode) ((int) mode + 1)) for (n = 0; n < MAX_386_STACK_LOCALS; n++) i386_stack_locals[(int) mode][n] = NULL_RTX; + + /* Arrange to save and restore i386_stack_locals around nested functions. */ + save_machine_status = save_386_machine_status; + restore_machine_status = restore_386_machine_status; } /* Return a MEM corresponding to a stack slot with mode MODE.