--- gcc/config/ns32k/ns32k.c 2018/04/24 18:10:24 1.1 +++ gcc/config/ns32k/ns32k.c 2018/04/24 18:28:42 1.1.1.4 @@ -1,5 +1,5 @@ /* Subroutines for assembler code output on the NS32000. - Copyright (C) 1988 Free Software Foundation, Inc. + Copyright (C) 1988, 1994, 1995 Free Software Foundation, Inc. This file is part of GNU CC. @@ -15,7 +15,8 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Some output-actions in ns32k.md need these. */ #include @@ -202,7 +203,7 @@ gen_indexed_expr (base, index, scale) { rtx addr; - /* This generates an illegal addressing mode, if BASE is + /* This generates an invalid addressing mode, if BASE is fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */ if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT) base = gen_rtx (MEM, SImode, base); @@ -244,7 +245,7 @@ char * output_move_double (operands) rtx *operands; { - enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; /* First classify both operands. */ @@ -254,19 +255,19 @@ output_move_double (operands) else if (offsettable_memref_p (operands[0])) optype0 = OFFSOP; else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) - optype0 = POPOP; + optype0 = PUSHOP; else optype0 = RNDOP; if (REG_P (operands[1])) optype1 = REGOP; - else if (CONSTANT_ADDRESS_P (operands[1]) + else if (CONSTANT_P (operands[1]) || GET_CODE (operands[1]) == CONST_DOUBLE) optype1 = CNSTOP; else if (offsettable_memref_p (operands[1])) optype1 = OFFSOP; else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) - optype1 = POPOP; + optype1 = PUSHOP; else optype1 = RNDOP; @@ -298,25 +299,70 @@ output_move_double (operands) else if (optype1 == OFFSOP) latehalf[1] = adj_offsettable_operand (operands[1], 4); else if (optype1 == CNSTOP) - { - if (CONSTANT_ADDRESS_P (operands[1])) - latehalf[1] = const0_rtx; - else if (GET_CODE (operands[1]) == CONST_DOUBLE) - split_double (operands[1], &operands[1], &latehalf[1]); - } + split_double (operands[1], &operands[1], &latehalf[1]); else latehalf[1] = operands[1]; + /* If insn is effectively movd N(sp),tos 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. + Given this, it doesn't matter which half we do "first". */ + 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]; + /* If one or both operands autodecrementing, do the two words, high-numbered first. */ + else if (optype0 == PUSHOP || optype1 == PUSHOP) + { + output_asm_insn (singlemove_string (latehalf), latehalf); + return singlemove_string (operands); + } - if (optype0 == POPOP || optype1 == POPOP) + /* If the first move would clobber the source of the second one, + do them in the other order. */ + + /* Overlapping registers. */ + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) { + /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); + /* Do low-numbered word. */ return singlemove_string (operands); } + /* Loading into a register which overlaps a register used in the address. */ + else if (optype0 == REGOP && optype1 != REGOP + && reg_overlap_mentioned_p (operands[0], operands[1])) + { + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) + && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + { + /* If both halves of dest are used in the src memory address, + load the destination address into the low reg (operands[0]). + Then it works to load latehalf first. */ + rtx xops[2]; + xops[0] = XEXP (operands[1], 0); + xops[1] = operands[0]; + output_asm_insn ("addr %a0,%1", xops); + operands[1] = gen_rtx (MEM, DImode, operands[0]); + latehalf[1] = adj_offsettable_operand (operands[1], 4); + /* The first half has the overlap, Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))) + { + /* The first half has the overlap, Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + } - /* Not autodecrementing. Do the two words, low-numbered first. */ + /* Normal case. Do the two words, low-numbered first. */ output_asm_insn (singlemove_string (operands), operands); @@ -346,6 +392,46 @@ check_reg (oper, reg) } return 0; } + +/* Returns 1 if OP contains a global symbol reference */ + +int +global_symbolic_reference_mentioned_p (op, f) + rtx op; + int f; +{ + register char *fmt; + register int i; + + if (GET_CODE (op) == SYMBOL_REF) + { + if (! SYMBOL_REF_FLAG (op)) + return 1; + else + return 0; + } + else if (f && GET_CODE (op) != CONST) + return 0; + + fmt = GET_RTX_FORMAT (GET_CODE (op)); + for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (op, i) - 1; j >= 0; j--) + if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0)) + return 1; + } + else if (fmt[i] == 'e' + && global_symbolic_reference_mentioned_p (XEXP (op, i), 0)) + return 1; + } + + return 0; +} + /* PRINT_OPERAND is defined to call this function, which is easier to debug than putting all the code in @@ -366,23 +452,9 @@ print_operand (file, x, code) else if (GET_CODE (x) == MEM) { rtx tmp = XEXP (x, 0); -#if ! (defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)) - if (GET_CODE (tmp) != CONST_INT) - { - char *out = XSTR (tmp, 0); - if (out[0] == '*') - { - PUT_ABSOLUTE_PREFIX (file); - fprintf (file, "%s", &out[1]); - } - else - ASM_OUTPUT_LABELREF (file, out); - } - else -#endif - output_address (XEXP (x, 0)); + output_address (XEXP (x, 0)); } - else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode) + else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode) { if (GET_MODE (x) == DFmode) { @@ -447,6 +519,7 @@ print_operand_address (file, addr) static char scales[] = { 'b', 'w', 'd', 0, 'q', }; rtx offset, base, indexexp, tmp; int scale; + extern int flag_pic; if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC) { @@ -510,9 +583,65 @@ print_operand_address (file, addr) case MULT: indexexp = tmp; break; + case SYMBOL_REF: + if (flag_pic && ! CONSTANT_POOL_ADDRESS_P (tmp) + && ! SYMBOL_REF_FLAG (tmp)) + { + if (base) + { + if (indexexp) + abort (); + indexexp = base; + } + base = tmp; + break; + } case CONST: + if (flag_pic && GET_CODE (tmp) == CONST) + { + rtx sym, off, tmp1; + tmp1 = XEXP (tmp,0); + if (GET_CODE (tmp1) != PLUS) + abort (); + + sym = XEXP (tmp1,0); + if (GET_CODE (sym) != SYMBOL_REF) + { + off = sym; + sym = XEXP (tmp1,1); + } + else + off = XEXP (tmp1,1); + if (GET_CODE (sym) == SYMBOL_REF) + { + if (GET_CODE (off) != CONST_INT) + abort (); + + if (CONSTANT_POOL_ADDRESS_P (sym) + || SYMBOL_REF_FLAG (sym)) + { + SYMBOL_REF_FLAG (tmp) = 1; + } + else + { + if (base) + { + if (indexexp) + abort (); + + indexexp = base; + } + + if (offset != 0) + abort (); + + base = sym; + offset = off; + break; + } + } + } case CONST_INT: - case SYMBOL_REF: case LABEL_REF: if (offset) offset = gen_rtx (PLUS, SImode, tmp, offset); @@ -526,26 +655,31 @@ print_operand_address (file, addr) if (! offset) offset = const0_rtx; -#ifdef INDEX_RATHER_THAN_BASE + if (base +#ifndef INDEX_RATHER_THAN_BASE + && (flag_pic || TARGET_HIMEM) + && GET_CODE (base) != SYMBOL_REF + && GET_CODE (offset) != CONST_INT +#else /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix. */ - if (base && !indexexp && GET_CODE (base) == REG +#endif + && !indexexp && GET_CODE (base) == REG && REG_OK_FOR_INDEX_P (base)) { indexexp = base; - base = 0; + base = NULL; } -#endif /* now, offset, base and indexexp are set */ +#ifndef BASE_REG_NEEDED if (! base) { #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC) if (GET_CODE (offset) == CONST_INT) -/* if (! (GET_CODE (offset) == LABEL_REF - || GET_CODE (offset) == SYMBOL_REF)) */ #endif PUT_ABSOLUTE_PREFIX (file); } +#endif output_addr_const (file, offset); if (base) /* base can be (REG ...) or (MEM ...) */ @@ -563,6 +697,14 @@ print_operand_address (file, addr) case REG: fprintf (file, "(%s)", reg_names[REGNO (base)]); break; + case SYMBOL_REF: + if (! flag_pic) + abort (); + + fprintf (file, "("); + output_addr_const (file, base); + fprintf (file, "(sb))"); + break; case MEM: addr = XEXP(base,0); base = NULL; @@ -611,30 +753,26 @@ print_operand_address (file, addr) output_addr_const (file, offset); if (base) fprintf (file, "(%s)", reg_names[REGNO (base)]); -#ifdef BASE_REG_NEEDED else if (TARGET_SB) fprintf (file, "(sb)"); else abort (); -#endif fprintf (file, ")"); break; - default: abort (); } #ifdef PC_RELATIVE - else /* no base */ - if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF) - fprintf (file, "(pc)"); -#endif -#ifdef BASE_REG_NEEDED /* this is defined if the assembler always - needs a base register */ - else if (TARGET_SB) - fprintf (file, "(sb)"); - else - abort (); + else if (GET_CODE (offset) != CONST_INT) + fprintf (file, "(pc)"); +#ifdef BASE_REG_NEEDED + else if (TARGET_SB) + fprintf (file, "(sb)"); + else + abort (); #endif +#endif /* PC_RELATIVE */ + /* now print index if we have one */ if (indexexp) { @@ -710,3 +848,26 @@ output_shift_insn (operands) else return "ashd %2,%0"; return "ashd %2,%0"; } + +char * +output_move_dconst (n, s) + int n; + char *s; +{ + static char r[32]; + + if (n > -9 && n < 8) + strcpy (r, "movqd "); + else if (n > 0 && n < 256) + strcpy (r, "movzbd "); + else if (n > 0 && n < 65536) + strcpy (r, "movzwd "); + else if (n < 0 && n > -129) + strcpy (r, "movxbd "); + else if (n < 0 && n > -32769) + strcpy (r, "movxwd "); + else + strcpy (r, "movd "); + strcat (r, s); + return r; +}