--- gcc/config/sparc/sparc.c 2018/04/24 18:10:25 1.1 +++ gcc/config/sparc/sparc.c 2018/04/24 18:15:12 1.1.1.2 @@ -1,5 +1,5 @@ /* Subroutines for insn-output.c for Sun SPARC. - Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc. + Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. @@ -62,6 +62,7 @@ char leaf_reg_remap[] = 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; +#if 0 /* not used anymore */ char leaf_reg_backmap[] = { 0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 28, 29, 14, 31, @@ -73,12 +74,13 @@ char leaf_reg_backmap[] = 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; #endif +#endif /* Global variables set by FUNCTION_PROLOGUE. */ /* Size of frame. Need to know this to emit return insns from leaf procedures. */ -int apparent_fsize; -int actual_fsize; +static int apparent_fsize; +static int actual_fsize; /* Name of where we pretend to think the frame pointer points. Normally, this is "%fp", but if we are in a leaf procedure, @@ -96,13 +98,28 @@ reg_or_0_operand (op, mode) { if (op == const0_rtx || register_operand (op, mode)) return 1; - if (GET_CODE (op) == CONST_DOUBLE + if (GET_MODE (op) == DImode && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0) return 1; + if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT + && GET_CODE (op) == CONST_DOUBLE + && fp_zero_operand (op)) + return 1; return 0; } +/* Nonzero if OP is a floating point value with value 0.0. */ +int +fp_zero_operand (op) + rtx op; +{ + REAL_VALUE_TYPE r; + + REAL_VALUE_FROM_CONST_DOUBLE (r, op); + return REAL_VALUES_EQUAL (r, dconst0); +} + /* Nonzero if OP can appear as the dest of a RESTORE insn. */ int restore_operand (op, mode) @@ -256,46 +273,6 @@ move_pic_label (op, mode) return 1; return 0; } - -/* The rtx for the global offset table which is a special form - that *is* a position independent symbolic constant. */ -rtx pic_pc_rtx; - -/* Ensure that we are not using patterns that are not OK with PIC. */ - -int -check_pic (i) - int i; -{ - switch (flag_pic) - { - case 1: - if (GET_CODE (recog_operand[i]) == SYMBOL_REF - || (GET_CODE (recog_operand[i]) == CONST - && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) - abort (); - case 2: - default: - return 1; - } -} - -/* Return true if X is an address which needs a temporary register when - reloaded while generating PIC code. */ - -int -pic_address_needs_scratch (x) - rtx x; -{ - /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ - if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT - && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) - return 1; - - return 0; -} int memop (op, mode) @@ -444,6 +421,36 @@ small_int (op, mode) return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); } +/* Recognize operand values for the umul instruction. That instruction sign + extends immediate values just like all other sparc instructions, but + interprets the extended result as an unsigned number. */ + +int +uns_small_int (op, mode) + rtx op; + enum machine_mode mode; +{ +#if HOST_BITS_PER_WIDE_INT > 32 + /* All allowed constants will fit a CONST_INT. */ + return (GET_CODE (op) == CONST_INT + && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000) + || (INTVAL (op) >= 0xFFFFF000 && INTVAL (op) < 0x100000000L))); +#else + return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000) + || (GET_CODE (op) == CONST_DOUBLE + && CONST_DOUBLE_HIGH (op) == 0 + && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000)); +#endif +} + +int +uns_arith_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + return register_operand (op, mode) || uns_small_int (op, mode); +} + /* Return truth value of statement that OP is a call-clobbered register. */ int clobbered_register (op, mode) @@ -593,18 +600,56 @@ reg_unused_after (reg, insn) return 1; } +/* The rtx for the global offset table which is a special form + that *is* a position independent symbolic constant. */ +static rtx pic_pc_rtx; + +/* Ensure that we are not using patterns that are not OK with PIC. */ + +int +check_pic (i) + int i; +{ + switch (flag_pic) + { + case 1: + if (GET_CODE (recog_operand[i]) == SYMBOL_REF + || (GET_CODE (recog_operand[i]) == CONST + && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) + abort (); + case 2: + default: + return 1; + } +} + +/* Return true if X is an address which needs a temporary register when + reloaded while generating PIC code. */ + +int +pic_address_needs_scratch (x) + rtx x; +{ + /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ + if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT + && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) + return 1; + + return 0; +} + /* Legitimize PIC addresses. If the address is already position-independent, we return ORIG. Newly generated position-independent addresses go into a reg. This is REG if non zero, otherwise we allocate register(s) as - necessary. If this is called during reload, and we need a second temp - register, then we use SCRATCH, which is provided via the - SECONDARY_INPUT_RELOAD_CLASS mechanism. */ + necessary. */ rtx -legitimize_pic_address (orig, mode, reg, scratch) +legitimize_pic_address (orig, mode, reg) rtx orig; enum machine_mode mode; - rtx reg, scratch; + rtx reg; { if (GET_CODE (orig) == SYMBOL_REF) { @@ -676,10 +721,9 @@ legitimize_pic_address (orig, mode, reg, if (GET_CODE (XEXP (orig, 0)) == PLUS) { - base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, - reg, 0); + base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, - base == reg ? 0 : reg, 0); + base == reg ? 0 : reg); } else abort (); @@ -690,17 +734,8 @@ legitimize_pic_address (orig, mode, reg, return plus_constant_for_output (base, INTVAL (offset)); else if (! reload_in_progress && ! reload_completed) offset = force_reg (Pmode, offset); - /* We can't create any new registers during reload, so use the - SCRATCH reg provided by the reload_insi pattern. */ - else if (scratch) - { - emit_move_insn (scratch, offset); - offset = scratch; - } else - /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS - macro needs to be adjusted so that a scratch reg is provided - for this address. */ + /* If we reach here, then something is seriously wrong. */ abort (); } return gen_rtx (PLUS, Pmode, base, offset); @@ -823,20 +858,20 @@ sparc_address_cost (X) Return 1 if we have written out everything that needs to be done to do the move. Otherwise, return 0 and the caller will emit the move - normally. - - SCRATCH_REG if non zero can be used as a scratch register for the move - operation. It is provided by a SECONDARY_RELOAD_* macro if needed. */ + normally. */ int -emit_move_sequence (operands, mode, scratch_reg) +emit_move_sequence (operands, mode) rtx *operands; enum machine_mode mode; - rtx scratch_reg; { register rtx operand0 = operands[0]; register rtx operand1 = operands[1]; + if (CONSTANT_P (operand1) && flag_pic + && pic_address_needs_scratch (operand1)) + operands[1] = operand1 = legitimize_pic_address (operand1, mode, 0); + /* Handle most common case first: storing into a register. */ if (register_operand (operand0, mode)) { @@ -877,8 +912,7 @@ emit_move_sequence (operands, mode, scra { rtx temp_reg = reload_in_progress ? operand0 : 0; - operands[1] = legitimize_pic_address (operand1, mode, temp_reg, - scratch_reg); + operands[1] = legitimize_pic_address (operand1, mode, temp_reg); } else if (GET_CODE (operand1) == CONST_INT ? (! SMALL_INT (operand1) @@ -946,18 +980,15 @@ singlemove_string (operands) return "ld %1,%0"; else if (GET_CODE (operands[1]) == CONST_DOUBLE) { - int i; - union real_extract u; - union float_extract { float f; int i; } v; + REAL_VALUE_TYPE r; + long i; /* Must be SFmode, otherwise this doesn't make sense. */ if (GET_MODE (operands[1]) != SFmode) abort (); - bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u); - v.f = REAL_VALUE_TRUNCATE (SFmode, u.d); - i = v.i; - + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (r, i); operands[1] = gen_rtx (CONST_INT, VOIDmode, i); if (CONST_OK_FOR_LETTER_P (i, 'I')) @@ -1061,6 +1092,8 @@ output_move_double (operands) rtx latehalf[2]; rtx addreg0 = 0; rtx addreg1 = 0; + int highest_first = 0; + int no_addreg1_decrement = 0; /* First classify both operands. */ @@ -1156,17 +1189,40 @@ output_move_double (operands) else if (optype0 == REGOP && optype1 != REGOP && reg_overlap_mentioned_p (op0, op1)) { - /* ??? This fails if the address is a double register address, each - of which is clobbered by operand 0. */ - /* Do the late half first. */ - output_asm_insn (singlemove_string (latehalf), latehalf); - /* Then clobber. */ - return singlemove_string (operands); + /* If both halves of dest are used in the src memory address, + add the two regs and put them in the low reg (op0). + Then it works to load latehalf first. */ + if (reg_mentioned_p (op0, XEXP (op1, 0)) + && reg_mentioned_p (latehalf[0], XEXP (op1, 0))) + { + rtx xops[2]; + xops[0] = latehalf[0]; + xops[1] = op0; + output_asm_insn ("add %1,%0,%1", xops); + operands[1] = gen_rtx (MEM, DImode, op0); + latehalf[1] = adj_offsettable_operand (operands[1], 4); + addreg1 = 0; + highest_first = 1; + } + /* Only one register in the dest is used in the src memory address, + and this is the first register of the dest, so we want to do + the late half first here also. */ + else if (! reg_mentioned_p (latehalf[0], XEXP (op1, 0))) + highest_first = 1; + /* Only one register in the dest is used in the src memory address, + and this is the second register of the dest, so we want to do + the late half last. If addreg1 is set, and addreg1 is the same + register as latehalf, then we must suppress the trailing decrement, + because it would clobber the value just loaded. */ + else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0])) + no_addreg1_decrement = 1; } - /* Normal case: do the two words, low-numbered first. */ + /* Normal case: do the two words, low-numbered first. + Overlap case (highest_first set): do high-numbered word first. */ - output_asm_insn (singlemove_string (operands), operands); + if (! highest_first) + output_asm_insn (singlemove_string (operands), operands); /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) @@ -1180,9 +1236,12 @@ output_move_double (operands) /* Undo the adds we just did. */ if (addreg0) output_asm_insn ("add %0,-0x4,%0", &addreg0); - if (addreg1) + if (addreg1 && ! no_addreg1_decrement) output_asm_insn ("add %0,-0x4,%0", &addreg1); + if (highest_first) + output_asm_insn (singlemove_string (operands), operands); + return ""; } @@ -1282,15 +1341,20 @@ output_move_quad (operands) } else if (optype1 == CNSTOP) { - /* This case isn't implemented yet, because there is no internal - representation for quad-word constants, and there is no split_quad - function. */ -#if 0 - split_quad (op1, &wordpart[0][1], &wordpart[1][1], - &wordpart[2][1], &wordpart[3][1]); -#else - abort (); -#endif + REAL_VALUE_TYPE r; + long l[4]; + + /* This only works for TFmode floating point constants. */ + if (GET_CODE (op1) != CONST_DOUBLE || GET_MODE (op1) != TFmode) + abort (); + + REAL_VALUE_FROM_CONST_DOUBLE (r, op1); + REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); + + wordpart[0][1] = GEN_INT (l[0]); + wordpart[1][1] = GEN_INT (l[1]); + wordpart[2][1] = GEN_INT (l[2]); + wordpart[3][1] = GEN_INT (l[3]); } else { @@ -1481,6 +1545,8 @@ find_addr_reg (addr) abort (); } +#if 0 /* not currently used */ + void output_sized_memop (opname, mode, signedp) char *opname; @@ -1515,6 +1581,7 @@ output_move_with_extension (operands) else abort (); } +#endif /* not currently used */ #if 0 /* ??? These are only used by the movstrsi pattern, but we get better code @@ -2889,6 +2956,14 @@ sparc_type_code (type) return (qualifiers | 16); case INTEGER_TYPE: + /* If this is a range type, consider it to be the underlying + type. */ + if (TREE_TYPE (type) != 0) + { + type = TREE_TYPE (type); + break; + } + /* Carefully distinguish all the standard types of C, without messing up if the language is not C. Note that we check only for the names that contain spaces; @@ -2972,9 +3047,10 @@ sparc_type_code (type) case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */ case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */ case FILE_TYPE: /* GNU Pascal FILE type. */ - case STRING_TYPE: /* GNU Fortran STRING type. */ + case STRING_TYPE: /* GNU Fortran STRING type. */ + case SET_TYPE: /* GNU Pascal SET type. */ case LANG_TYPE: /* ? */ - abort (); + return qualifiers; default: abort (); /* Not a type! */ @@ -3224,7 +3300,7 @@ sparc_frw_save_restore (file, word_op, d if ((mask & (1L << regno)) != 0 || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)) { - if ((regno & 0x1) == 0 && ((mask & (1L << regno+1)) != 0)) + if ((regno & 0x1) == 0 && ((mask & (1L << (regno+1))) != 0)) { if (gp_offset % 8 != 0) gp_offset += UNITS_PER_WORD;