X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=gcc%2Fconfig%2Fpdp11%2Fpdp11.c;h=f6171356a1255e998c4a2410478c80292a1a4439;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=505456550bd72a0e0b718e6e593564f7b64aeaef;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c index 50545655..f6171356 100644 --- a/gcc/config/pdp11/pdp11.c +++ b/gcc/config/pdp11/pdp11.c @@ -1,27 +1,28 @@ /* Subroutines for gcc2 for pdp11. - Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001 - Free Software Foundation, Inc. + Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004, 2005, + 2006, 2007, 2008 Free Software Foundation, Inc. Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at). -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify +GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. -GNU CC is distributed in the hope that it will be useful, +GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "rtl.h" #include "regs.h" #include "hard-reg-set.h" @@ -39,6 +40,7 @@ Boston, MA 02111-1307, USA. */ #include "tm_p.h" #include "target.h" #include "target-def.h" +#include "df.h" /* #define FPU_REG_P(X) ((X)>=8 && (X)<14) @@ -49,14 +51,107 @@ Boston, MA 02111-1307, USA. */ defined in tm.h */ int current_first_parm_offset; +/* Routines to encode/decode pdp11 floats */ +static void encode_pdp11_f (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_pdp11_f (const struct real_format *, + REAL_VALUE_TYPE *, const long *); +static void encode_pdp11_d (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_pdp11_d (const struct real_format *, + REAL_VALUE_TYPE *, const long *); + +/* These two are taken from the corresponding vax descriptors + in real.c, changing only the encode/decode routine pointers. */ +const struct real_format pdp11_f_format = + { + encode_pdp11_f, + decode_pdp11_f, + 2, + 1, + 24, + 24, + -127, + 127, + 15, + false, + false, + false, + false, + false, + false, + false, + false + }; + +const struct real_format pdp11_d_format = + { + encode_pdp11_d, + decode_pdp11_d, + 2, + 1, + 56, + 56, + -127, + 127, + 15, + false, + false, + false, + false, + false, + false, + false, + false + }; + +static void +encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) +{ + (*vax_f_format.encode) (fmt, buf, r); + buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); +} + +static void +decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) +{ + long tbuf; + tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); + (*vax_f_format.decode) (fmt, r, &tbuf); +} + +static void +encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) +{ + (*vax_d_format.encode) (fmt, buf, r); + buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); + buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16); +} + +static void +decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) +{ + long tbuf[2]; + tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); + tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16); + (*vax_d_format.decode) (fmt, r, tbuf); +} + /* This is where the condition code register lives. */ /* rtx cc0_reg_rtx; - no longer needed? */ -static rtx find_addr_reg PARAMS ((rtx)); -static const char *singlemove_string PARAMS ((rtx *)); -static bool pdp11_assemble_integer PARAMS ((rtx, unsigned int, int)); -static void pdp11_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); -static void pdp11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); +static bool pdp11_handle_option (size_t, const char *, int); +static rtx find_addr_reg (rtx); +static const char *singlemove_string (rtx *); +static bool pdp11_assemble_integer (rtx, unsigned int, int); +static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT); +static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT); +static bool pdp11_rtx_costs (rtx, int, int, int *, bool); +static bool pdp11_return_in_memory (const_tree, const_tree); /* Initialize the GCC target structure. */ #undef TARGET_ASM_BYTE_OP @@ -78,38 +173,59 @@ static void pdp11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); #undef TARGET_ASM_CLOSE_PAREN #define TARGET_ASM_CLOSE_PAREN "]" +#undef TARGET_DEFAULT_TARGET_FLAGS +#define TARGET_DEFAULT_TARGET_FLAGS \ + (MASK_FPU | MASK_45 | MASK_ABSHI_BUILTIN | TARGET_UNIX_ASM_DEFAULT) +#undef TARGET_HANDLE_OPTION +#define TARGET_HANDLE_OPTION pdp11_handle_option + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS pdp11_rtx_costs + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory + struct gcc_target targetm = TARGET_INITIALIZER; +/* Implement TARGET_HANDLE_OPTION. */ + +static bool +pdp11_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, + int value ATTRIBUTE_UNUSED) +{ + switch (code) + { + case OPT_m10: + target_flags &= ~(MASK_40 | MASK_45); + return true; + + default: + return true; + } +} + /* Nonzero if OP is a valid second operand for an arithmetic insn. */ int -arith_operand (op, mode) - rtx op; - enum machine_mode mode; +arith_operand (rtx op, enum machine_mode mode) { return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); } int -const_immediate_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { return (GET_CODE (op) == CONST_INT); } int -immediate15_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000)); } int -expand_shift_operand (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { return (GET_CODE (op) == CONST_INT && abs (INTVAL(op)) > 1 @@ -128,16 +244,14 @@ expand_shift_operand (op, mode) #ifdef TWO_BSD static void -pdp11_output_function_prologue (stream, size) - FILE *stream; - HOST_WIDE_INT size; +pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size) { fprintf (stream, "\tjsr r5, csv\n"); if (size) { fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n"); if (size > 2) - fprintf(stream, "\tsub $%d, sp\n", size - 2); + asm_fprintf (stream, "\tsub $%#wo, sp\n", size - 2); } } @@ -145,16 +259,15 @@ pdp11_output_function_prologue (stream, size) #else /* !TWO_BSD */ static void -pdp11_output_function_prologue (stream, size) - FILE *stream; - HOST_WIDE_INT size; +pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size) { HOST_WIDE_INT fsize = ((size) + 1) & ~1; int regno; int via_ac = -1; fprintf (stream, - "\n\t; /* function prologue %s*/\n", current_function_name); + "\n\t; /* function prologue %s*/\n", + current_function_name ()); /* if we are outputting code for main, the switch FPU to right mode if TARGET_FPU */ @@ -168,8 +281,8 @@ pdp11_output_function_prologue (stream, size) if (frame_pointer_needed) { - fprintf(stream, "\tmov fp, -(sp)\n"); - fprintf(stream, "\tmov sp, fp\n"); + fprintf(stream, "\tmov r5, -(sp)\n"); + fprintf(stream, "\tmov sp, r5\n"); } else { @@ -178,11 +291,11 @@ pdp11_output_function_prologue (stream, size) /* make frame */ if (fsize) - fprintf (stream, "\tsub $%o, sp\n", fsize); + asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize); /* save CPU registers */ for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) + if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) if (! ((regno == FRAME_POINTER_REGNUM) && frame_pointer_needed)) fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]); @@ -195,24 +308,23 @@ pdp11_output_function_prologue (stream, size) { /* ac0 - ac3 */ if (LOAD_FPU_REG_P(regno) - && regs_ever_live[regno] + && df_regs_ever_live_p (regno) && ! call_used_regs[regno]) { - fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]); + fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]); via_ac = regno; } /* maybe make ac4, ac5 call used regs?? */ /* ac4 - ac5 */ if (NO_LOAD_FPU_REG_P(regno) - && regs_ever_live[regno] + && df_regs_ever_live_p (regno) && ! call_used_regs[regno]) { - if (via_ac == -1) - abort(); - - fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]); - fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]); + gcc_assert (via_ac != -1); + fprintf (stream, "\tldd %s, %s\n", + reg_names[regno], reg_names[via_ac]); + fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]); } } @@ -243,9 +355,8 @@ pdp11_output_function_prologue (stream, size) #ifdef TWO_BSD static void -pdp11_output_function_epilogue (stream, size) - FILE *stream; - HOST_WIDE_INT size ATTRIBUTE_UNUSED; +pdp11_output_function_epilogue (FILE *stream, + HOST_WIDE_INT size ATTRIBUTE_UNUSED) { fprintf (stream, "\t/* SP ignored by cret? */\n"); fprintf (stream, "\tjmp cret\n"); @@ -254,9 +365,7 @@ pdp11_output_function_epilogue (stream, size) #else /* !TWO_BSD */ static void -pdp11_output_function_epilogue (stream, size) - FILE *stream; - HOST_WIDE_INT size; +pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size) { HOST_WIDE_INT fsize = ((size) + 1) & ~1; int i, j, k; @@ -268,24 +377,26 @@ pdp11_output_function_epilogue (stream, size) if (frame_pointer_needed) { /* hope this is safe - m68k does it also .... */ - regs_ever_live[FRAME_POINTER_REGNUM] = 0; + df_set_regs_ever_live (FRAME_POINTER_REGNUM, false); for (i =7, j = 0 ; i >= 0 ; i--) - if (regs_ever_live[i] && ! call_used_regs[i]) + if (df_regs_ever_live_p (i) && ! call_used_regs[i]) j++; /* remember # of pushed bytes for CPU regs */ k = 2*j; + /* change fp -> r5 due to the compile error on libgcc2.c */ for (i =7 ; i >= 0 ; i--) - if (regs_ever_live[i] && ! call_used_regs[i]) - fprintf(stream, "\tmov %o(fp), %s\n",-fsize-2*j--, reg_names[i]); + if (df_regs_ever_live_p (i) && ! call_used_regs[i]) + fprintf(stream, "\tmov %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", + (-fsize-2*j--)&0xffff, reg_names[i]); /* get ACs */ via_ac = FIRST_PSEUDO_REGISTER -1; for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) - if (regs_ever_live[i] && ! call_used_regs[i]) + if (df_regs_ever_live_p (i) && ! call_used_regs[i]) { via_ac = i; k += 8; @@ -294,28 +405,29 @@ pdp11_output_function_epilogue (stream, size) for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) { if (LOAD_FPU_REG_P(i) - && regs_ever_live[i] + && df_regs_ever_live_p (i) && ! call_used_regs[i]) { - fprintf(stream, "\tfldd %o(fp), %s\n", -fsize-k, reg_names[i]); + fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", + (-fsize-k)&0xffff, reg_names[i]); k -= 8; } if (NO_LOAD_FPU_REG_P(i) - && regs_ever_live[i] + && df_regs_ever_live_p (i) && ! call_used_regs[i]) { - if (! LOAD_FPU_REG_P(via_ac)) - abort(); + gcc_assert (LOAD_FPU_REG_P(via_ac)); - fprintf(stream, "\tfldd %o(fp), %s\n", -fsize-k, reg_names[via_ac]); - fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]); + fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", + (-fsize-k)&0xffff, reg_names[via_ac]); + fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]); k -= 8; } } - fprintf(stream, "\tmov fp, sp\n"); - fprintf (stream, "\tmov (sp)+, fp\n"); + fprintf(stream, "\tmov r5, sp\n"); + fprintf (stream, "\tmov (sp)+, r5\n"); } else { @@ -323,34 +435,34 @@ pdp11_output_function_epilogue (stream, size) /* get ACs */ for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) - if (regs_ever_live[i] && call_used_regs[i]) + if (df_regs_ever_live_p (i) && call_used_regs[i]) via_ac = i; for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) { if (LOAD_FPU_REG_P(i) - && regs_ever_live[i] + && df_regs_ever_live_p (i) && ! call_used_regs[i]) - fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]); + fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]); if (NO_LOAD_FPU_REG_P(i) - && regs_ever_live[i] + && df_regs_ever_live_p (i) && ! call_used_regs[i]) { - if (! LOAD_FPU_REG_P(via_ac)) - abort(); + gcc_assert (LOAD_FPU_REG_P(via_ac)); - fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]); - fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]); + fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]); + fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]); } } for (i=7; i >= 0; i--) - if (regs_ever_live[i] && !call_used_regs[i]) + if (df_regs_ever_live_p (i) && !call_used_regs[i]) fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]); if (fsize) - fprintf((stream), "\tadd $%o, sp\n", fsize); + fprintf((stream), "\tadd $%#" HOST_WIDE_INT_PRINT "o, sp\n", + (fsize)&0xffff); } fprintf (stream, "\trts pc\n"); @@ -362,8 +474,7 @@ pdp11_output_function_epilogue (stream, size) /* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */ static const char * -singlemove_string (operands) - rtx *operands; +singlemove_string (rtx *operands) { if (operands[1] != const0_rtx) return "mov %1,%0"; @@ -376,8 +487,7 @@ singlemove_string (operands) with operands OPERANDS. */ const char * -output_move_double (operands) - rtx *operands; +output_move_double (rtx *operands) { enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; @@ -400,10 +510,11 @@ output_move_double (operands) if (REG_P (operands[1])) optype1 = REGOP; - else if (CONSTANT_P (operands[1])) + else if (CONSTANT_P (operands[1]) #if 0 - || GET_CODE (operands[1]) == CONST_DOUBLE) + || GET_CODE (operands[1]) == CONST_DOUBLE #endif + ) optype1 = CNSTOP; else if (offsettable_memref_p (operands[1])) optype1 = OFFSOP; @@ -420,8 +531,7 @@ output_move_double (operands) supposed to allow to happen. Abort if we get one, because generating code for these cases is painful. */ - if (optype0 == RNDOP || optype1 == RNDOP) - abort (); + gcc_assert (optype0 != RNDOP && optype1 != RNDOP); /* If one operand is decrementing and one is incrementing decrement the former register explicitly @@ -481,11 +591,9 @@ output_move_double (operands) latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16); operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff); } - else if (GET_CODE (operands[1]) == CONST_DOUBLE) - { - /* immediate 32 bit values not allowed */ - abort(); - } + else + /* immediate 32-bit values not allowed */ + gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE); } else latehalf[1] = operands[1]; @@ -554,14 +662,13 @@ output_move_double (operands) with operands OPERANDS. */ const char * -output_move_quad (operands) - rtx *operands; +output_move_quad (rtx *operands) { enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; rtx addreg0 = 0, addreg1 = 0; - output_asm_insn(";; movdi/df: %1 -> %0", operands); + output_asm_insn(";/* movdi/df: %1 -> %0 */", operands); if (REG_P (operands[0])) optype0 = REGOP; @@ -596,15 +703,13 @@ output_move_quad (operands) supposed to allow to happen. Abort if we get one, because generating code for these cases is painful. */ - if (optype0 == RNDOP || optype1 == RNDOP) - abort (); + gcc_assert (optype0 != RNDOP && optype1 != RNDOP); /* check if we move a CPU reg to an FPU reg, or vice versa! */ if (optype0 == REGOP && optype1 == REGOP) /* bogus - 64 bit cannot reside in CPU! */ - if (CPU_REG_P(REGNO(operands[0])) - || CPU_REG_P (REGNO(operands[1]))) - abort(); + gcc_assert (!CPU_REG_P(REGNO(operands[0])) + && !CPU_REG_P (REGNO(operands[1]))); if (optype0 == REGOP || optype1 == REGOP) { @@ -620,11 +725,10 @@ output_move_quad (operands) { if (GET_CODE(operands[1]) == CONST_DOUBLE) { - union { double d; int i[2]; } u; - u.i[0] = CONST_DOUBLE_LOW (operands[1]); - u.i[1] = CONST_DOUBLE_HIGH (operands[1]); - - if (u.d == 0.0) + REAL_VALUE_TYPE r; + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + + if (REAL_VALUES_EQUAL (r, dconst0)) return "{clrd|clrf} %0"; } @@ -687,29 +791,19 @@ output_move_quad (operands) { if (GET_CODE (operands[1]) == CONST_DOUBLE) { - /* floats only. not yet supported! - - -- compute it into PDP float format, - internally, - just use IEEE and ignore possible problems ;-) - - we might get away with it !!!! */ - - abort(); - -#ifndef HOST_WORDS_BIG_ENDIAN - latehalf[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); - operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); -#else /* HOST_WORDS_BIG_ENDIAN */ - latehalf[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); - operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); -#endif /* HOST_WORDS_BIG_ENDIAN */ + REAL_VALUE_TYPE r; + long dval[2]; + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + REAL_VALUE_TO_TARGET_DOUBLE (r, dval); + latehalf[1] = GEN_INT (dval[1]); + operands[1] = GEN_INT (dval[0]); } else if (GET_CODE(operands[1]) == CONST_INT) { - latehalf[1] = GEN_INT (0); + latehalf[1] = const0_rtx; } else - abort(); + gcc_unreachable (); } else latehalf[1] = operands[1]; @@ -780,8 +874,7 @@ output_move_quad (operands) ADDR can be effectively incremented by incrementing REG. */ static rtx -find_addr_reg (addr) - rtx addr; +find_addr_reg (rtx addr) { while (GET_CODE (addr) == PLUS) { @@ -801,10 +894,7 @@ find_addr_reg (addr) /* Output an ascii string. */ void -output_ascii (file, p, size) - FILE *file; - const char *p; - int size; +output_ascii (FILE *file, const char *p, int size) { int i; @@ -817,7 +907,7 @@ output_ascii (file, p, size) register int c = p[i]; if (c < 0) c += 256; - fprintf (file, "%o", c); + fprintf (file, "%#o", c); if (i < size - 1) putc (',', file); } @@ -828,9 +918,7 @@ output_ascii (file, p, size) /* --- stole from out-vax, needs changes */ void -print_operand_address (file, addr) - FILE *file; - register rtx addr; +print_operand_address (FILE *file, register rtx addr) { register rtx reg1, reg2, breg, ireg; rtx offset; @@ -851,10 +939,12 @@ print_operand_address (file, addr) fprintf (file, "(%s)", reg_names[REGNO (addr)]); break; + case PRE_MODIFY: case PRE_DEC: fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); break; + case POST_MODIFY: case POST_INC: fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); break; @@ -907,7 +997,7 @@ print_operand_address (file, addr) } if (offset != 0) { - if (addr != 0) abort (); + gcc_assert (addr == 0); addr = offset; } if (reg1 != 0 && GET_CODE (reg1) == MULT) @@ -934,17 +1024,15 @@ print_operand_address (file, addr) output_address (addr); if (breg != 0) { - if (GET_CODE (breg) != REG) - abort (); + gcc_assert (GET_CODE (breg) == REG); fprintf (file, "(%s)", reg_names[REGNO (breg)]); } if (ireg != 0) { if (GET_CODE (ireg) == MULT) ireg = XEXP (ireg, 0); - if (GET_CODE (ireg) != REG) - abort (); - abort(); + gcc_assert (GET_CODE (ireg) == REG); + gcc_unreachable(); /* ??? */ fprintf (file, "[%s]", reg_names[REGNO (ireg)]); } break; @@ -958,10 +1046,7 @@ print_operand_address (file, addr) pdp-specific version of output_addr_const. */ static bool -pdp11_assemble_integer (x, size, aligned_p) - rtx x; - unsigned int size; - int aligned_p; +pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p) { if (aligned_p) switch (size) @@ -984,7 +1069,7 @@ pdp11_assemble_integer (x, size, aligned_p) /* register move costs, indexed by regs */ -static int move_costs[N_REG_CLASSES][N_REG_CLASSES] = +static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = { /* NO MUL GEN LFPU NLFPU FPU ALL */ @@ -1004,16 +1089,121 @@ static int move_costs[N_REG_CLASSES][N_REG_CLASSES] = -- as we do here with 22 -- or not ? */ int -register_move_cost(c1, c2) - enum reg_class c1, c2; +register_move_cost(enum reg_class c1, enum reg_class c2) { return move_costs[(int)c1][(int)c2]; } +static bool +pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, + bool speed ATTRIBUTE_UNUSED) +{ + switch (code) + { + case CONST_INT: + if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1) + { + *total = 0; + return true; + } + /* FALLTHRU */ + + case CONST: + case LABEL_REF: + case SYMBOL_REF: + /* Twice as expensive as REG. */ + *total = 2; + return true; + + case CONST_DOUBLE: + /* Twice (or 4 times) as expensive as 16 bit. */ + *total = 4; + return true; + + case MULT: + /* ??? There is something wrong in MULT because MULT is not + as cheap as total = 2 even if we can shift! */ + /* If optimizing for size make mult etc cheap, but not 1, so when + in doubt the faster insn is chosen. */ + if (optimize_size) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (11); + return false; + + case DIV: + if (optimize_size) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (25); + return false; + + case MOD: + if (optimize_size) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (26); + return false; + + case ABS: + /* Equivalent to length, so same for optimize_size. */ + *total = COSTS_N_INSNS (3); + return false; + + case ZERO_EXTEND: + /* Only used for qi->hi. */ + *total = COSTS_N_INSNS (1); + return false; + + case SIGN_EXTEND: + if (GET_MODE (x) == HImode) + *total = COSTS_N_INSNS (1); + else if (GET_MODE (x) == SImode) + *total = COSTS_N_INSNS (6); + else + *total = COSTS_N_INSNS (2); + return false; + + case ASHIFT: + case LSHIFTRT: + case ASHIFTRT: + if (optimize_size) + *total = COSTS_N_INSNS (1); + else if (GET_MODE (x) == QImode) + { + if (GET_CODE (XEXP (x, 1)) != CONST_INT) + *total = COSTS_N_INSNS (8); /* worst case */ + else + *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))); + } + else if (GET_MODE (x) == HImode) + { + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + { + if (abs (INTVAL (XEXP (x, 1))) == 1) + *total = COSTS_N_INSNS (1); + else + *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1))); + } + else + *total = COSTS_N_INSNS (10); /* worst case */ + } + else if (GET_MODE (x) == SImode) + { + if (GET_CODE (XEXP (x, 1)) == CONST_INT) + *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1))); + else /* worst case */ + *total = COSTS_N_INSNS (18); + } + return false; + + default: + return false; + } +} + const char * -output_jump(pos, neg, length) - const char *pos, *neg; - int length; +output_jump (const char *pos, const char *neg, int length) { static int x = 0; @@ -1048,15 +1238,13 @@ output_jump(pos, neg, length) default: - abort(); + gcc_unreachable (); } } void -notice_update_cc_on_set(exp, insn) - rtx exp; - rtx insn ATTRIBUTE_UNUSED; +notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED) { if (GET_CODE (SET_DEST (exp)) == CC0) { @@ -1126,9 +1314,7 @@ notice_update_cc_on_set(exp, insn) int -simple_memory_operand(op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; +simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { rtx addr; @@ -1201,8 +1387,7 @@ simple_memory_operand(op, mode) const char * -output_block_move(operands) - rtx *operands; +output_block_move(rtx *operands) { static int count = 0; char buf[200]; @@ -1439,62 +1624,8 @@ output_block_move(operands) return ""; } -/* for future use */ int -comparison_operator_index(op) - rtx op; -{ - switch (GET_CODE(op)) - { - case NE: - return 0; - - case EQ: - return 1; - - case GE: - return 2; - - case GT: - return 3; - - case LE: - return 4; - - case LT: - return 5; - - case GEU: - return 6; - - case GTU: - return 7; - - case LEU: - return 8; - - case LTU: - return 9; - - default: - return -1; - } -} - -/* tests whether the rtx is a comparison operator */ -int -comp_operator (op, mode) - rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - return comparison_operator_index(op) >= 0; -} - - -int -legitimate_address_p (mode, address) - enum machine_mode mode; - rtx address; +legitimate_address_p (enum machine_mode mode, rtx address) { /* #define REG_OK_STRICT */ GO_IF_LEGITIMATE_ADDRESS(mode, address, win); @@ -1507,15 +1638,28 @@ legitimate_address_p (mode, address) /* #undef REG_OK_STRICT */ } +/* This function checks whether a real value can be encoded as + a literal, i.e., addressing mode 27. In that mode, real values + are one word values, so the remaining 48 bits have to be zero. */ +int +legitimate_const_double_p (rtx address) +{ + REAL_VALUE_TYPE r; + long sval[2]; + REAL_VALUE_FROM_CONST_DOUBLE (r, address); + REAL_VALUE_TO_TARGET_DOUBLE (r, sval); + if ((sval[0] & 0xffff) == 0 && sval[1] == 0) + return 1; + return 0; +} + /* A copy of output_addr_const modified for pdp11 expression syntax. output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't use, and for debugging output, which we don't support with this port either. So this copy should get called whenever needed. */ void -output_addr_const_pdp11 (file, x) - FILE *file; - rtx x; +output_addr_const_pdp11 (FILE *file, rtx x) { char buf[256]; @@ -1523,10 +1667,8 @@ output_addr_const_pdp11 (file, x) switch (GET_CODE (x)) { case PC: - if (flag_pic) - putc ('.', file); - else - abort (); + gcc_assert (flag_pic); + putc ('.', file); break; case SYMBOL_REF: @@ -1546,7 +1688,7 @@ output_addr_const_pdp11 (file, x) case CONST_INT: /* Should we check for constants which are too big? Maybe cutting them off to 16 bits is OK? */ - fprintf (file, "%ho", (unsigned short) INTVAL (x)); + fprintf (file, "%#ho", (unsigned short) INTVAL (x)); break; case CONST: @@ -1559,10 +1701,8 @@ output_addr_const_pdp11 (file, x) if (GET_MODE (x) == VOIDmode) { /* We can use %o if the number is one word and positive. */ - if (CONST_DOUBLE_HIGH (x)) - abort (); /* Should we just silently drop the high part? */ - else - fprintf (file, "%ho", (unsigned short) CONST_DOUBLE_LOW (x)); + gcc_assert (!CONST_DOUBLE_HIGH (x)); + fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x)); } else /* We can't handle floating point constants; @@ -1571,7 +1711,7 @@ output_addr_const_pdp11 (file, x) break; case PLUS: - /* Some assemblers need integer constants to appear last (eg masm). */ + /* Some assemblers need integer constants to appear last (e.g. masm). */ if (GET_CODE (XEXP (x, 0)) == CONST_INT) { output_addr_const_pdp11 (file, XEXP (x, 1)); @@ -1617,3 +1757,18 @@ output_addr_const_pdp11 (file, x) output_operand_lossage ("invalid expression as operand"); } } + +/* Worker function for TARGET_RETURN_IN_MEMORY. */ + +static bool +pdp11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) +{ + /* Should probably return DImode and DFmode in memory, lest + we fill up all regs! + + have to, else we crash - exception: maybe return result in + ac0 if DFmode and FPU present - compatibility problem with + libraries for non-floating point.... */ + return (TYPE_MODE (type) == DImode + || (TYPE_MODE (type) == DFmode && ! TARGET_AC0)); +}