--- gcc/config/rs6000/rs6000.c 2018/04/24 18:10:26 1.1 +++ gcc/config/rs6000/rs6000.c 2018/04/24 18:22:47 1.1.1.3 @@ -1,6 +1,6 @@ /* Subroutines used for code generation on IBM RS/6000. - Copyright (C) 1991, 1993 Free Software Foundation, Inc. - Contributed by Richard Kenner (kenner@nyu.edu) + Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. + Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) This file is part of GNU CC. @@ -19,6 +19,7 @@ along with GNU CC; see the file COPYING. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +#include #include "config.h" #include "rtl.h" #include "regs.h" @@ -36,10 +37,16 @@ the Free Software Foundation, 675 Mass A #include "tree.h" extern char *language_string; +extern int profile_block_flag; #define min(A,B) ((A) < (B) ? (A) : (B)) #define max(A,B) ((A) > (B) ? (A) : (B)) +/* Target cpu type */ + +enum processor_type rs6000_cpu; +char *rs6000_cpu_string; + /* Set to non-zero by "fix" operation to indicate that itrunc and uitrunc must be defined. */ @@ -49,12 +56,114 @@ int rs6000_trunc_used; static int trunc_defined; +/* Set to non-zero once AIX common-mode calls have been defined. */ +static int common_mode_defined; /* Save information from a "cmpxx" operation until the branch or scc is emitted. */ rtx rs6000_compare_op0, rs6000_compare_op1; int rs6000_compare_fp_p; +/* Override command line options. Mostly we process the processor + type and sometimes adjust other TARGET_ options. */ + +void +rs6000_override_options () +{ + int i; + + /* Simplify the entries below by making a mask for any POWER + variant and any PowerPC variant. */ + +#define POWER_MASKS (MASK_POWER | MASK_POWER2) +#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \ + | MASK_PPC_GFXOPT | MASK_POWERPC64) +#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT) + + static struct ptt + { + char *name; /* Canonical processor name. */ + enum processor_type processor; /* Processor type enum value. */ + int target_enable; /* Target flags to enable. */ + int target_disable; /* Target flags to disable. */ + } processor_target_table[] + = {{"common", PROCESSOR_COMMON, 0, POWER_MASKS | POWERPC_MASKS}, + {"power", PROCESSOR_POWER, + MASK_POWER, + MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, + {"powerpc", PROCESSOR_POWERPC, + MASK_POWERPC | MASK_NEW_MNEMONICS, + POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, + {"rios", PROCESSOR_RIOS1, + MASK_POWER, + MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, + {"rios1", PROCESSOR_RIOS1, + MASK_POWER, + MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, + {"rsc", PROCESSOR_PPC601, + MASK_POWER, + MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, + {"rsc1", PROCESSOR_PPC601, + MASK_POWER, + MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, + {"rios2", PROCESSOR_RIOS2, + MASK_POWER | MASK_POWER2, + POWERPC_MASKS | MASK_NEW_MNEMONICS}, + {"601", PROCESSOR_PPC601, + MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS, + MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64}, + {"mpc601", PROCESSOR_PPC601, + MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS, + MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64}, + {"ppc601", PROCESSOR_PPC601, + MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS, + MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64}, + {"603", PROCESSOR_PPC603, + MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, + POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, + {"mpc603", PROCESSOR_PPC603, + MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, + POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, + {"ppc603", PROCESSOR_PPC603, + MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, + POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, + {"604", PROCESSOR_PPC604, + MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, + POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, + {"mpc604", PROCESSOR_PPC604, + MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, + POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, + {"ppc604", PROCESSOR_PPC604, + MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, + POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}}; + + int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt); + + profile_block_flag = 0; + + /* Identify the processor type */ + if (rs6000_cpu_string == 0) + rs6000_cpu = PROCESSOR_DEFAULT; + else + { + for (i = 0; i < ptt_size; i++) + if (! strcmp (rs6000_cpu_string, processor_target_table[i].name)) + { + rs6000_cpu = processor_target_table[i].processor; + target_flags |= processor_target_table[i].target_enable; + target_flags &= ~processor_target_table[i].target_disable; + break; + } + + if (i == ptt_size) + { + error ("bad value (%s) for -mcpu= switch", rs6000_cpu_string); + rs6000_cpu_string = "default"; + rs6000_cpu = PROCESSOR_DEFAULT; + } + } +} + /* Return non-zero if this function is known to have a null epilogue. */ int @@ -144,10 +253,7 @@ reg_or_short_operand (op, mode) register rtx op; enum machine_mode mode; { - if (GET_CODE (op) == CONST_INT) - return short_cint_operand (op, mode); - - return gpc_reg_operand (op, mode); + return short_cint_operand (op, mode) || gpc_reg_operand (op, mode); } /* Similar, except check if the negation of the constant would be valid for @@ -190,13 +296,9 @@ reg_or_cint_operand (op, mode) return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode); } -/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a - register with one instruction per word. For SFmode, this means that - the low 16-bits are zero. For DFmode, it means the low 16-bits of - the first word are zero and the high 16 bits of the second word - are zero (usually all bits in the low-order word will be zero). - - We only do this if we can safely read CONST_DOUBLE_{LOW,HIGH}. */ +/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a register + with one instruction per word. We only do this if we can safely read + CONST_DOUBLE_{LOW,HIGH}. */ int easy_fp_constant (op, mode) @@ -213,12 +315,11 @@ easy_fp_constant (op, mode) high = operand_subword (op, 0, 0, mode); low = operand_subword (op, 1, 0, mode); - if (high == 0 || GET_CODE (high) != CONST_INT || (INTVAL (high) & 0xffff)) + if (high == 0 || ! input_operand (high, word_mode)) return 0; return (mode == SFmode - || (low != 0 && GET_CODE (low) == CONST_INT - && (INTVAL (low) & 0xffff0000) == 0)); + || (low != 0 && input_operand (low, word_mode))); } /* Return 1 if the operand is either a floating-point register, a pseudo @@ -383,6 +484,21 @@ call_operand (op, mode) || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)); } + +/* Return 1 if the operand is a SYMBOL_REF for a function known to be in + this file. */ + +int +current_file_function_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == SYMBOL_REF + && (SYMBOL_REF_FLAG (op) + || op == XEXP (DECL_RTL (current_function_decl), 0))); +} + + /* Return 1 if this operand is a valid input for a move insn. */ int @@ -390,26 +506,37 @@ input_operand (op, mode) register rtx op; enum machine_mode mode; { + /* Memory is always valid. */ if (memory_operand (op, mode)) return 1; - /* For floating-point or multi-word mode, only register or memory - is valid. */ + /* For floating-point, easy constants are valid. */ + if (GET_MODE_CLASS (mode) == MODE_FLOAT + && CONSTANT_P (op) + && easy_fp_constant (op, mode)) + return 1; + + /* For floating-point or multi-word mode, the only remaining valid type + is a register. */ if (GET_MODE_CLASS (mode) == MODE_FLOAT || GET_MODE_SIZE (mode) > UNITS_PER_WORD) - return gpc_reg_operand (op, mode); + return register_operand (op, mode); /* The only cases left are integral modes one word or smaller (we do not get called for MODE_CC values). These can be in any register. */ if (register_operand (op, mode)) - return; + return 1; /* For HImode and QImode, any constant is valid. */ if ((mode == HImode || mode == QImode) && GET_CODE (op) == CONST_INT) return 1; + /* A SYMBOL_REF referring to the TOC is valid. */ + if (GET_CODE (op) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (op)) + return 1; + /* Otherwise, we will be doing this SET with an add, so anything valid for an add will be valid. */ return add_operand (op, mode); @@ -709,15 +836,26 @@ print_operand (file, x, code) switch (code) { + case '.': + /* Write out an instruction after the call which may be replaced + with glue code by the loader. This depends on the AIX version. */ + asm_fprintf (file, RS6000_CALL_GLUE); + return; + + case '*': + /* Write the register number of the TOC register. */ + fputs (TARGET_MINIMAL_TOC ? "30" : "2", file); + return; + case 'A': /* If X is a constant integer whose low-order 5 bits are zero, write 'l'. Otherwise, write 'r'. This is a kludge to fix a bug - in the RS/6000 assembler where "sri" with a zero shift count + in the AIX assembler where "sri" with a zero shift count write a trash instruction. */ if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0) - fprintf (file, "l"); + putc ('l', file); else - fprintf (file, "r"); + putc ('r', file); return; case 'b': @@ -770,7 +908,7 @@ print_operand (file, x, code) output_operand_lossage ("invalid %%E value"); fprintf(file, "%d", 4 * (REGNO (x) - 68) + 3); - break; + return; case 'f': /* X is a CR register. Print the shift count needed to move it @@ -796,9 +934,9 @@ print_operand (file, x, code) if (GET_CODE (x) != CONST_INT) output_operand_lossage ("invalid %%G value"); else if (INTVAL (x) >= 0) - fprintf (file, "z"); + putc ('z', file); else - fprintf (file, "m"); + putc ('m', file); return; case 'h': @@ -821,7 +959,7 @@ print_operand (file, x, code) case 'I': /* Print `i' if this is a constant, else nothing. */ if (INT_P (x)) - fprintf (file, "i"); + putc ('i', file); return; case 'j': @@ -840,7 +978,8 @@ print_operand (file, x, code) if (i == -1) output_operand_lossage ("invalid %%J code"); else - fprintf (file, "%d", i + 1); + /* If we want bit 31, write a shift count of zero, not 32. */ + fprintf (file, "%d", i == 31 ? 0 : i + 1); return; case 'k': @@ -916,7 +1055,7 @@ print_operand (file, x, code) the right. */ if ((val & 1) && val >= 0) { - fprintf (file, "31"); + fputs ("31", file); return; } else if ((val & 1) == 0) @@ -1011,9 +1150,9 @@ print_operand (file, x, code) || GET_CODE (x) == EQ || GET_CODE (x) == LT || GET_CODE (x) == GT || GET_CODE (x) == LTU || GET_CODE (x) == GTU) - fprintf (file, "12"); + fputs ("12", file); else - fprintf (file, "4"); + putc ('4', file); return; case 'T': @@ -1027,9 +1166,9 @@ print_operand (file, x, code) || GET_CODE (x) == EQ || GET_CODE (x) == LT || GET_CODE (x) == GT || GET_CODE (x) == LTU || GET_CODE (x) == GTU) - fprintf (file, "4"); + putc ('4', file); else - fprintf (file, "12"); + fputs ("12", file); return; case 'u': @@ -1037,7 +1176,7 @@ print_operand (file, x, code) if (! INT_P (x)) output_operand_lossage ("invalid %%u value"); - fprintf (file, "%d", (INT_LOWPART (x) >> 16) & 0xffff); + fprintf (file, "0x%x", (INT_LOWPART (x) >> 16) & 0xffff); return; case 'U': @@ -1045,7 +1184,7 @@ print_operand (file, x, code) if (GET_CODE (x) == MEM && (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC)) - fprintf (file, "u"); + putc ('u', file); return; case 'w': @@ -1070,7 +1209,7 @@ print_operand (file, x, code) case 'X': if (GET_CODE (x) == MEM && LEGITIMATE_INDEXED_ADDRESS_P (XEXP (x, 0))) - fprintf (file, "x"); + putc ('x', file); return; case 'Y': @@ -1094,7 +1233,7 @@ print_operand (file, x, code) if (GET_CODE (x) != SYMBOL_REF) abort (); - fprintf (file, "."); + putc ('.', file); RS6000_OUTPUT_BASENAME (file, XSTR (x, 0)); return; @@ -1130,7 +1269,7 @@ print_operand (file, x, code) } else output_addr_const (file, x); - break; + return; default: output_operand_lossage ("invalid %%xn code"); @@ -1149,7 +1288,12 @@ print_operand_address (file, x) else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST) { output_addr_const (file, x); - fprintf (file, "(2)"); + /* When TARGET_MINIMAL_TOC, use the indirected toc table pointer instead + of the toc pointer. */ + if (TARGET_MINIMAL_TOC) + fprintf (file, "(30)"); + else + fprintf (file, "(2)"); } else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG) { @@ -1222,7 +1366,6 @@ int rs6000_sa_size () { int size; - int i; /* We have the six fixed words, plus the size of the register save areas, rounded to a double-word. */ @@ -1293,9 +1436,21 @@ output_prolog (file, size) /* Write .extern for truncation routines, if needed. */ if (rs6000_trunc_used && ! trunc_defined) { - fprintf (file, "\t.extern .itrunc\n\t.extern .uitrunc\n"); + fprintf (file, "\t.extern .%s\n\t.extern .%s\n", + RS6000_ITRUNC, RS6000_UITRUNC); trunc_defined = 1; } + /* Write .extern for AIX common mode routines, if needed. */ + if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined) + { + fputs ("\t.extern __mulh\n", file); + fputs ("\t.extern __mull\n", file); + fputs ("\t.extern __divss\n", file); + fputs ("\t.extern __divus\n", file); + fputs ("\t.extern __quoss\n", file); + fputs ("\t.extern __quous\n", file); + common_mode_defined = 1; + } /* If we have to call a function to save fpr's, or if we are doing profiling, then we will be using LR. */ @@ -1304,52 +1459,78 @@ output_prolog (file, size) /* If we use the link register, get it into r0. */ if (regs_ever_live[65]) - fprintf (file, "\tmflr 0\n"); + asm_fprintf (file, "\tmflr 0\n"); /* If we need to save CR, put it into r12. */ if (must_save_cr ()) - fprintf (file, "\tmfcr 12\n"); + asm_fprintf (file, "\tmfcr 12\n"); /* Do any required saving of fpr's. If only one or two to save, do it - ourself. Otherwise, call function. */ + ourself. Otherwise, call function. Note that since they are statically + linked, we do not need a nop following them. */ if (first_fp_reg == 62) - fprintf (file, "\tstfd 30,-16(1)\n\tstfd 31,-8(1)\n"); + asm_fprintf (file, "\tstfd 30,-16(1)\n\tstfd 31,-8(1)\n"); else if (first_fp_reg == 63) - fprintf (file, "\tstfd 31,-8(1)\n"); + asm_fprintf (file, "\tstfd 31,-8(1)\n"); else if (first_fp_reg != 64) - fprintf (file, "\tbl ._savef%d\n\tcror 15,15,15\n", first_fp_reg - 32); + asm_fprintf (file, "\tbl ._savef%d\n", first_fp_reg - 32); /* Now save gpr's. */ - if (first_reg == 31) - fprintf (file, "\tst 31,%d(1)\n", -4 - (64 - first_fp_reg) * 8); + if (! TARGET_POWER || first_reg == 31) + { + int regno, loc; + + for (regno = first_reg, + loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8; + regno < 32; + regno++, loc += 4) + asm_fprintf (file, "\t{st|stw} %d,%d(1)\n", regno, loc); + } + else if (first_reg != 32) - fprintf (file, "\tstm %d,%d(1)\n", first_reg, + asm_fprintf (file, "\t{stm|stmw} %d,%d(1)\n", first_reg, - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8); /* Save lr if we used it. */ if (regs_ever_live[65]) - fprintf (file, "\tst 0,8(1)\n"); + asm_fprintf (file, "\t{st|stw} 0,8(1)\n"); /* Save CR if we use any that must be preserved. */ if (must_save_cr ()) - fprintf (file, "\tst 12,4(1)\n"); + asm_fprintf (file, "\t{st|stw} 12,4(1)\n"); /* Update stack and set back pointer. */ if (must_push) { if (total_size < 32767) - fprintf (file, "\tstu 1,%d(1)\n", - total_size); + asm_fprintf (file, "\t{stu|stwu} 1,%d(1)\n", - total_size); else { - fprintf (file, "\tcau 0,0,%d\n\toril 0,0,%d\n", + asm_fprintf (file, "\t{cau 0,0,%d|lis 0,%d}\n\t{oril|ori} 0,0,%d\n", (total_size >> 16) & 0xffff, total_size & 0xffff); - fprintf (file, "\tsf 12,0,1\n\tst 1,0(12)\n\toril 1,12,0\n"); + if (TARGET_POWERPC) + asm_fprintf (file, "\tsubf 12,0,1\n"); + else + asm_fprintf (file, "\t{sf|subfc} 12,0,1\n"); + asm_fprintf (file, "\t{st|stw} 1,0(12)\n\tmr 1,12\n"); } } /* Set frame pointer, if needed. */ if (frame_pointer_needed) - fprintf (file, "\toril 31,1,0\n"); + asm_fprintf (file, "\tmr 31,1\n"); + + /* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the + TOC_TABLE address into register 30. */ + if (TARGET_MINIMAL_TOC && get_pool_size () != 0) + { + char buf[100]; + + ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0); + asm_fprintf (file, "\t{l|lwz} 30,"); + assemble_name (file, buf); + asm_fprintf (file, "(2)\n"); + } } /* Write function epilogue. */ @@ -1380,222 +1561,248 @@ output_epilog (file, size) we know what size to update it with. */ if (frame_pointer_needed || current_function_calls_alloca || total_size > 32767) - fprintf (file, "\tl 1,0(1)\n"); + asm_fprintf (file, "\t{l|lwz} 1,0(1)\n"); else if (must_push) - fprintf (file, "\tai 1,1,%d\n", total_size); + asm_fprintf (file, "\t{cal 1,%d(1)|addi 1,1,%d}\n", total_size); /* Get the old lr if we saved it. */ if (regs_ever_live[65]) - fprintf (file, "\tl 0,8(1)\n"); + asm_fprintf (file, "\t{l|lwz} 0,8(1)\n"); /* Get the old cr if we saved it. */ if (must_save_cr ()) - fprintf (file, "\tl 12,4(1)\n"); + asm_fprintf (file, "\t{l|lwz} 12,4(1)\n"); /* Set LR here to try to overlap restores below. */ if (regs_ever_live[65]) - fprintf (file, "\tmtlr 0\n"); + asm_fprintf (file, "\tmtlr 0\n"); /* Restore gpr's. */ - if (first_reg == 31) - fprintf (file, "\tl 31,%d(1)\n", -4 - (64 - first_fp_reg) * 8); + if (! TARGET_POWER || first_reg == 31) + { + int regno, loc; + + for (regno = first_reg, + loc = - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8; + regno < 32; + regno++, loc += 4) + asm_fprintf (file, "\t{l|lwz} %d,%d(1)\n", regno, loc); + } + else if (first_reg != 32) - fprintf (file, "\tlm %d,%d(1)\n", first_reg, - - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8); + asm_fprintf (file, "\t{lm|lmw} %d,%d(1)\n", first_reg, + - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8); /* Restore fpr's if we can do it without calling a function. */ if (first_fp_reg == 62) - fprintf (file, "\tlfd 30,-16(1)\n\tlfd 31,-8(1)\n"); + asm_fprintf (file, "\tlfd 30,-16(1)\n\tlfd 31,-8(1)\n"); else if (first_fp_reg == 63) - fprintf (file, "\tlfd 31,-8(1)\n"); + asm_fprintf (file, "\tlfd 31,-8(1)\n"); /* If we saved cr, restore it here. Just those of cr2, cr3, and cr4 that were used. */ if (must_save_cr ()) - fprintf (file, "\tmtcrf %d,12\n", - (regs_ever_live[70] != 0) * 0x20 - + (regs_ever_live[71] != 0) * 0x10 - + (regs_ever_live[72] != 0) * 0x8); + asm_fprintf (file, "\tmtcrf %d,12\n", + (regs_ever_live[70] != 0) * 0x20 + + (regs_ever_live[71] != 0) * 0x10 + + (regs_ever_live[72] != 0) * 0x8); /* If we have to restore more than two FP registers, branch to the restore function. It will return to our caller. */ if (first_fp_reg < 62) - fprintf (file, "\tb ._restf%d\n\tcror 15,15,15\n", first_fp_reg - 32); + asm_fprintf (file, "\tb ._restf%d\n", first_fp_reg - 32); else - fprintf (file, "\tbr\n"); + asm_fprintf (file, "\t{br|blr}\n"); } /* Output a traceback table here. See /usr/include/sys/debug.h for info - on its format. */ - { - char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - int fixed_parms, float_parms, parm_info; - int i; - - /* Need label immediately before tbtab, so we can compute its offset - from the function start. */ - if (*fname == '*') - ++fname; - fprintf (file, "LT.."); - ASM_OUTPUT_LABEL (file, fname); - - /* The .tbtab pseudo-op can only be used for the first eight - expressions, since it can't handle the possibly variable length - fields that follow. However, if you omit the optional fields, - the assembler outputs zeros for all optional fields anyways, giving each - variable length field is minimum length (as defined in sys/debug.h). - Thus we can not use the .tbtab pseudo-op at all. */ - - /* An all-zero word flags the start of the tbtab, for debuggers that have - to find it by searching forward from the entry point or from the - current pc. */ - fprintf (file, "\t.long 0\n"); - - /* Tbtab format type. Use format type 0. */ - fprintf (file, "\t.byte 0,"); - - /* Language type. Unfortunately, there doesn't seem to be any official way - to get this info, so we use language_string. C is 0. C++ is 9. - No number defined for Obj-C, so use the value for C for now. */ - if (! strcmp (language_string, "GNU C") - || ! strcmp (language_string, "GNU Obj-C")) - i = 0; - else if (! strcmp (language_string, "GNU F77")) - i = 1; - else if (! strcmp (language_string, "GNU Ada")) - i = 3; - else if (! strcmp (language_string, "GNU PASCAL")) - i = 2; - else if (! strcmp (language_string, "GNU C++")) - i = 9; - else - abort (); - fprintf (file, "%d,", i); + on its format. - /* 8 single bit fields: global linkage (not set for C extern linkage, - apparently a PL/I convention?), out-of-line epilogue/prologue, offset - from start of procedure stored in tbtab, internal function, function - has controlled storage, function has no toc, function uses fp, - function logs/aborts fp operations. */ - /* Assume that fp operations are used if any fp reg must be saved. */ - fprintf (file, "%d,", (1 << 5) | ((first_fp_reg != 64) << 1)); - - /* 6 bitfields: function is interrupt handler, name present in proc table, - function calls alloca, on condition directives (controls stack walks, - 3 bits), saves condition reg, saves link reg. */ - /* The `function calls alloca' bit seems to be set whenever reg 31 is - set up as a frame pointer, even when there is no alloca call. */ - fprintf (file, "%d,", - ((1 << 6) | (frame_pointer_needed << 5) - | (must_save_cr () << 1) | (regs_ever_live[65]))); - - /* 3 bitfields: saves backchain, spare bit, number of fpr saved - (6 bits). */ - fprintf (file, "%d,", - (must_push << 7) | (64 - first_fp_reg_to_save ())); - - /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits). */ - fprintf (file, "%d,", (32 - first_reg_to_save ())); - - { - /* Compute the parameter info from the function decl argument list. */ - tree decl; - int next_parm_info_bit; - - next_parm_info_bit = 31; - parm_info = 0; - fixed_parms = 0; - float_parms = 0; - - for (decl = DECL_ARGUMENTS (current_function_decl); - decl; decl = TREE_CHAIN (decl)) - { - rtx parameter = DECL_INCOMING_RTL (decl); - enum machine_mode mode = GET_MODE (parameter); + We don't output a traceback table if -finhibit-size-directive was + used. The documentation for -finhibit-size-directive reads + ``don't output a @code{.size} assembler directive, or anything + else that would cause trouble if the function is split in the + middle, and the two halves are placed at locations far apart in + memory.'' The traceback table has this property, since it + includes the offset from the start of the function to the + traceback table itself. */ + if (! flag_inhibit_size_directive) + { + char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + int fixed_parms, float_parms, parm_info; + int i; + + /* Need label immediately before tbtab, so we can compute its offset + from the function start. */ + if (*fname == '*') + ++fname; + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT"); + ASM_OUTPUT_LABEL (file, fname); + + /* The .tbtab pseudo-op can only be used for the first eight + expressions, since it can't handle the possibly variable + length fields that follow. However, if you omit the optional + fields, the assembler outputs zeros for all optional fields + anyways, giving each variable length field is minimum length + (as defined in sys/debug.h). Thus we can not use the .tbtab + pseudo-op at all. */ + + /* An all-zero word flags the start of the tbtab, for debuggers + that have to find it by searching forward from the entry + point or from the current pc. */ + fprintf (file, "\t.long 0\n"); + + /* Tbtab format type. Use format type 0. */ + fprintf (file, "\t.byte 0,"); + + /* Language type. Unfortunately, there doesn't seem to be any + official way to get this info, so we use language_string. C + is 0. C++ is 9. No number defined for Obj-C, so use the + value for C for now. */ + if (! strcmp (language_string, "GNU C") + || ! strcmp (language_string, "GNU Obj-C")) + i = 0; + else if (! strcmp (language_string, "GNU F77")) + i = 1; + else if (! strcmp (language_string, "GNU Ada")) + i = 3; + else if (! strcmp (language_string, "GNU PASCAL")) + i = 2; + else if (! strcmp (language_string, "GNU C++")) + i = 9; + else + abort (); + fprintf (file, "%d,", i); - if (GET_CODE (parameter) == REG) - { - if (GET_MODE_CLASS (mode) == MODE_FLOAT) - { - int bits; - - float_parms++; - - if (mode == SFmode) - bits = 0x2; - else if (mode == DFmode) - bits = 0x3; - else - abort (); - - /* If only one bit will fit, don't or in this entry. */ - if (next_parm_info_bit > 0) - parm_info |= (bits << (next_parm_info_bit - 1)); - next_parm_info_bit -= 2; - } - else - { - fixed_parms += ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) - / UNITS_PER_WORD); - next_parm_info_bit -= 1; - } - } - } + /* 8 single bit fields: global linkage (not set for C extern linkage, + apparently a PL/I convention?), out-of-line epilogue/prologue, offset + from start of procedure stored in tbtab, internal function, function + has controlled storage, function has no toc, function uses fp, + function logs/aborts fp operations. */ + /* Assume that fp operations are used if any fp reg must be saved. */ + fprintf (file, "%d,", (1 << 5) | ((first_fp_reg != 64) << 1)); + + /* 6 bitfields: function is interrupt handler, name present in + proc table, function calls alloca, on condition directives + (controls stack walks, 3 bits), saves condition reg, saves + link reg. */ + /* The `function calls alloca' bit seems to be set whenever reg 31 is + set up as a frame pointer, even when there is no alloca call. */ + fprintf (file, "%d,", + ((1 << 6) | (frame_pointer_needed << 5) + | (must_save_cr () << 1) | (regs_ever_live[65]))); + + /* 3 bitfields: saves backchain, spare bit, number of fpr saved + (6 bits). */ + fprintf (file, "%d,", + (must_push << 7) | (64 - first_fp_reg_to_save ())); + + /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits). */ + fprintf (file, "%d,", (32 - first_reg_to_save ())); + + { + /* Compute the parameter info from the function decl argument + list. */ + tree decl; + int next_parm_info_bit; + + next_parm_info_bit = 31; + parm_info = 0; + fixed_parms = 0; + float_parms = 0; + + for (decl = DECL_ARGUMENTS (current_function_decl); + decl; decl = TREE_CHAIN (decl)) + { + rtx parameter = DECL_INCOMING_RTL (decl); + enum machine_mode mode = GET_MODE (parameter); + + if (GET_CODE (parameter) == REG) + { + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + int bits; + + float_parms++; + + if (mode == SFmode) + bits = 0x2; + else if (mode == DFmode) + bits = 0x3; + else + abort (); + + /* If only one bit will fit, don't or in this entry. */ + if (next_parm_info_bit > 0) + parm_info |= (bits << (next_parm_info_bit - 1)); + next_parm_info_bit -= 2; + } + else + { + fixed_parms += ((GET_MODE_SIZE (mode) + + (UNITS_PER_WORD - 1)) + / UNITS_PER_WORD); + next_parm_info_bit -= 1; + } + } + } + } + + /* Number of fixed point parameters. */ + /* This is actually the number of words of fixed point parameters; thus + an 8 byte struct counts as 2; and thus the maximum value is 8. */ + fprintf (file, "%d,", fixed_parms); + + /* 2 bitfields: number of floating point parameters (7 bits), parameters + all on stack. */ + /* This is actually the number of fp registers that hold parameters; + and thus the maximum value is 13. */ + /* Set parameters on stack bit if parameters are not in their original + registers, regardless of whether they are on the stack? Xlc + seems to set the bit when not optimizing. */ + fprintf (file, "%d\n", ((float_parms << 1) | (! optimize))); + + /* Optional fields follow. Some are variable length. */ + + /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float, + 11 double float. */ + /* There is an entry for each parameter in a register, in the order that + they occur in the parameter list. Any intervening arguments on the + stack are ignored. If the list overflows a long (max possible length + 34 bits) then completely leave off all elements that don't fit. */ + /* Only emit this long if there was at least one parameter. */ + if (fixed_parms || float_parms) + fprintf (file, "\t.long %d\n", parm_info); + + /* Offset from start of code to tb table. */ + fprintf (file, "\t.long "); + ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT"); + RS6000_OUTPUT_BASENAME (file, fname); + fprintf (file, "-."); + RS6000_OUTPUT_BASENAME (file, fname); + fprintf (file, "\n"); + + /* Interrupt handler mask. */ + /* Omit this long, since we never set the interrupt handler bit + above. */ + + /* Number of CTL (controlled storage) anchors. */ + /* Omit this long, since the has_ctl bit is never set above. */ + + /* Displacement into stack of each CTL anchor. */ + /* Omit this list of longs, because there are no CTL anchors. */ + + /* Length of function name. */ + fprintf (file, "\t.short %d\n", strlen (fname)); + + /* Function name. */ + assemble_string (fname, strlen (fname)); + + /* Register for alloca automatic storage; this is always reg 31. + Only emit this if the alloca bit was set above. */ + if (frame_pointer_needed) + fprintf (file, "\t.byte 31\n"); } - - /* Number of fixed point parameters. */ - /* This is actually the number of words of fixed point parameters; thus - an 8 byte struct counts as 2; and thus the maximum value is 8. */ - fprintf (file, "%d,", fixed_parms); - - /* 2 bitfields: number of floating point parameters (7 bits), parameters - all on stack. */ - /* This is actually the number of fp registers that hold parameters; - and thus the maximum value is 13. */ - /* Set parameters on stack bit if parameters are not in their original - registers, regardless of whether they are on the stack? Xlc - seems to set the bit when not optimizing. */ - fprintf (file, "%d\n", ((float_parms << 1) | (! optimize))); - - /* Optional fields follow. Some are variable length. */ - - /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float, - 11 double float. */ - /* There is an entry for each parameter in a register, in the order that - they occur in the parameter list. Any intervening arguments on the - stack are ignored. If the list overflows a long (max possible length - 34 bits) then completely leave off all elements that don't fit. */ - /* Only emit this long if there was at least one parameter. */ - if (fixed_parms || float_parms) - fprintf (file, "\t.long %d\n", parm_info); - - /* Offset from start of code to tb table. */ - fprintf (file, "\t.long LT.."); - RS6000_OUTPUT_BASENAME (file, fname); - fprintf (file, "-."); - RS6000_OUTPUT_BASENAME (file, fname); - fprintf (file, "\n"); - - /* Interrupt handler mask. */ - /* Omit this long, since we never set the interrupt handler bit above. */ - - /* Number of CTL (controlled storage) anchors. */ - /* Omit this long, since the has_ctl bit is never set above. */ - - /* Displacement into stack of each CTL anchor. */ - /* Omit this list of longs, because there are no CTL anchors. */ - - /* Length of function name. */ - fprintf (file, "\t.short %d\n", strlen (fname)); - - /* Function name. */ - assemble_string (fname, strlen (fname)); - - /* Register for alloca automatic storage; this is always reg 31. - Only emit this if the alloca bit was set above. */ - if (frame_pointer_needed) - fprintf (file, "\t.byte 31\n"); - } } /* Output a TOC entry. We derive the entry name from what is @@ -1614,27 +1821,36 @@ output_toc (file, x, labelno) ASM_OUTPUT_INTERNAL_LABEL (file, "LC", labelno); - /* Handle FP constants specially. */ + /* Handle FP constants specially. Note that if we have a minimal + TOC, things we put here aren't actually in the TOC, so we can allow + FP constants. */ if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode && TARGET_FLOAT_FORMAT == HOST_FLOAT_FORMAT && BITS_PER_WORD == HOST_BITS_PER_INT - && TARGET_FP_IN_TOC) + && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) { - fprintf (file, "\t.tc FD_%x_%x[TC],%d,%d\n", - CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x), - CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x)); + if (TARGET_MINIMAL_TOC) + fprintf (file, "\t.long %d\n\t.long %d\n", + CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x)); + else + fprintf (file, "\t.tc FD_%x_%x[TC],%d,%d\n", + CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x), + CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x)); return; } else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode - && TARGET_FP_IN_TOC) + && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) { rtx val = operand_subword (x, 0, 0, SFmode); if (val == 0 || GET_CODE (val) != CONST_INT) abort (); - fprintf (file, "\t.tc FS_%x[TC],%d\n", INTVAL (val), INTVAL (val)); + if (TARGET_MINIMAL_TOC) + fprintf (file, "\t.long %d\n", INTVAL (val)); + else + fprintf (file, "\t.tc FS_%x[TC],%d\n", INTVAL (val), INTVAL (val)); return; } @@ -1653,15 +1869,20 @@ output_toc (file, x, labelno) else abort (); - fprintf (file, "\t.tc "); - RS6000_OUTPUT_BASENAME (file, name); + if (TARGET_MINIMAL_TOC) + fprintf (file, "\t.long "); + else + { + fprintf (file, "\t.tc "); + RS6000_OUTPUT_BASENAME (file, name); - if (offset < 0) - fprintf (file, ".N%d", - offset); - else if (offset) - fprintf (file, ".P%d", offset); + if (offset < 0) + fprintf (file, ".N%d", - offset); + else if (offset) + fprintf (file, ".P%d", offset); - fprintf (file, "[TC],"); + fprintf (file, "[TC],"); + } output_addr_const (file, x); fprintf (file, "\n"); } @@ -1801,11 +2022,26 @@ output_function_profiler (file, labelno) /* The last used parameter register. */ int last_parm_reg; int i, j; + char buf[100]; /* Set up a TOC entry for the profiler label. */ toc_section (); - fprintf (file, "LPC..%d:\n\t.tc\tLP..%d[TC],LP..%d\n", - labelno, labelno, labelno); + ASM_OUTPUT_INTERNAL_LABEL (file, "LPC", labelno); + ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno); + if (TARGET_MINIMAL_TOC) + { + fprintf (file, "\t.long "); + assemble_name (file, buf); + fprintf (file, "\n"); + } + else + { + fprintf (file, "\t.tc\t"); + assemble_name (file, buf); + fprintf (file, "[TC],"); + assemble_name (file, buf); + fprintf (file, "\n"); + } text_section (); /* Figure out last used parameter register. The proper thing to do is @@ -1825,10 +2061,47 @@ output_function_profiler (file, labelno) /* Load location address into r3, and call mcount. */ - fprintf (file, "\tl 3,LPC..%d(2)\n\tbl .mcount\n", labelno); + ASM_GENERATE_INTERNAL_LABEL (buf, "LPC", labelno); + fprintf (file, "\tl 3,"); + assemble_name (file, buf); + fprintf (file, "(2)\n\tbl .mcount\n"); /* Restore parameter registers. */ for (i = 3, j = 30; i <= last_parm_reg; i++, j--) fprintf (file, "\tai %d,%d,0\n", i, j); } + +/* Adjust the cost of a scheduling dependency. Return the new cost of + a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ + +int +rs6000_adjust_cost (insn, link, dep_insn, cost) + rtx insn; + rtx link; + rtx dep_insn; + int cost; +{ + if (! recog_memoized (insn)) + return 0; + + if (REG_NOTE_KIND (link) != 0) + return 0; + + if (REG_NOTE_KIND (link) == 0) + { + /* Data dependency; DEP_INSN writes a register that INSN reads some + cycles later. */ + + /* Tell the first scheduling pass about the latency between a mtctr + and bctr (and mtlr and br/blr). The first scheduling pass will not + know about this latency since the mtctr instruction, which has the + latency associated to it, will be generated by reload. */ + if (get_attr_type (insn) == TYPE_JMPREG) + return TARGET_POWER ? 5 : 4; + + /* Fall out to return default cost. */ + } + + return cost; +}