--- gcc/config/rs6000.c 2018/04/24 17:51:30 1.1.1.1 +++ gcc/config/rs6000.c 2018/04/24 18:03:46 1.1.1.4 @@ -33,17 +33,13 @@ the Free Software Foundation, 675 Mass A #include "recog.h" #include "expr.h" #include "obstack.h" +#include "tree.h" + +extern char *language_string; #define min(A,B) ((A) < (B) ? (A) : (B)) #define max(A,B) ((A) > (B) ? (A) : (B)) -/* Names of bss and data sections. These should be unique names for each - compilation unit. */ - -char *rs6000_bss_section_name; -char *rs6000_private_data_section_name; -char *rs6000_read_only_section_name; - /* Set to non-zero by "fix" operation to indicate that itrunc and uitrunc must be defined. */ @@ -102,11 +98,22 @@ u_short_cint_operand (op, mode) return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0); } +/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field. */ + +int +non_short_cint_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT + && (unsigned) (INTVAL (op) + 0x8000) >= 0x10000); +} + /* Returns 1 if OP is a register that is not special (i.e., not MQ, ctr, or lr). */ int -gen_reg_operand (op, mode) +gpc_reg_operand (op, mode) register rtx op; enum machine_mode mode; { @@ -140,7 +147,7 @@ reg_or_short_operand (op, mode) if (GET_CODE (op) == CONST_INT) return short_cint_operand (op, mode); - return gen_reg_operand (op, mode); + return gpc_reg_operand (op, mode); } /* Similar, except check if the negation of the constant would be valid for @@ -154,7 +161,7 @@ reg_or_neg_short_operand (op, mode) if (GET_CODE (op) == CONST_INT) return CONST_OK_FOR_LETTER_P (INTVAL (op), 'P'); - return gen_reg_operand (op, mode); + return gpc_reg_operand (op, mode); } /* Return 1 if the operand is either a register or an integer whose high-order @@ -169,7 +176,7 @@ reg_or_u_short_operand (op, mode) && (INTVAL (op) & 0xffff0000) == 0) return 1; - return gen_reg_operand (op, mode); + return gpc_reg_operand (op, mode); } /* Return 1 is the operand is either a non-special register or ANY @@ -180,7 +187,7 @@ reg_or_cint_operand (op, mode) register rtx op; enum machine_mode mode; { - return GET_CODE (op) == CONST_INT || gen_reg_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 @@ -252,6 +259,18 @@ add_operand (op, mode) || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0)); } +/* Return 1 if OP is a constant but not a valid add_operand. */ + +int +non_add_cint_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT + && (unsigned) (INTVAL (op) + 0x8000) >= 0x10000 + && (INTVAL (op) & 0xffff) != 0); +} + /* Return 1 if the operand is a non-special register or a constant that can be used as the operand of an OR or XOR insn on the RS/6000. */ @@ -260,12 +279,25 @@ logical_operand (op, mode) register rtx op; enum machine_mode mode; { - return (gen_reg_operand (op, mode) + return (gpc_reg_operand (op, mode) || (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0xffff0000) == 0 || (INTVAL (op) & 0xffff) == 0))); } +/* Return 1 if C is a constant that is not a logical operand (as + above). */ + +int +non_logical_cint_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) & 0xffff0000) != 0 + && (INTVAL (op) & 0xffff) != 0); +} + /* Return 1 if C is a constant that can be encoded in a mask on the RS/6000. It is if there are no more than two 1->0 or 0->1 transitions. Reject all ones and all zeros, since these should have been optimized @@ -314,6 +346,17 @@ and_operand (op, mode) || mask_operand (op, mode)); } +/* Return 1 if the operand is a constant but not a valid operand for an AND + insn. */ + +int +non_and_cint_operand (op, mode) + register rtx op; + enum machine_mode mode; +{ + return GET_CODE (op) == CONST_INT && ! and_operand (op, mode); +} + /* Return 1 if the operand is a general register or memory operand. */ int @@ -321,7 +364,7 @@ reg_or_mem_operand (op, mode) register rtx op; register enum machine_mode mode; { - return gen_reg_operand (op, mode) || memory_operand (op, mode); + return gpc_reg_operand (op, mode) || memory_operand (op, mode); } /* Return 1 if the operand, used inside a MEM, is a valid first argument @@ -354,18 +397,19 @@ input_operand (op, mode) is valid. */ if (GET_MODE_CLASS (mode) == MODE_FLOAT || GET_MODE_SIZE (mode) > UNITS_PER_WORD) - return gen_reg_operand (op, mode); + return gpc_reg_operand (op, mode); - /* For SImode, we can also load from a special register, so any register - is valid. */ - if (mode == SImode && 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; + + /* For HImode and QImode, any constant is valid. */ + if ((mode == HImode || mode == QImode) + && GET_CODE (op) == CONST_INT) return 1; - /* For HImode and QImode, any constant is valid along with any - non-special register. */ - if (mode == HImode || mode == QImode) - return register_operand (op, mode) || GET_CODE (op) == CONST_INT; - /* Otherwise, we will be doing this SET with an add, so anything valid for an add will be valid. */ return add_operand (op, mode); @@ -519,6 +563,9 @@ scc_comparison_operator (op, mode) && (cc_mode != CCUNSmode)) return 0; + if (cc_mode == CCEQmode && code != EQ && code != NE) + return 0; + return 1; } @@ -591,7 +638,7 @@ secondary_reload_class (class, mode, in) SCC_P is 1 if this is for an scc. That means that %D will have been used instead of %C, so the bits will be in different places. - Return -1 if OP isn't a valid compaison for some reason. */ + Return -1 if OP isn't a valid comparison for some reason. */ int ccr_bit (op, scc_p) @@ -610,6 +657,12 @@ ccr_bit (op, scc_p) cc_regnum = REGNO (XEXP (op, 0)); base_bit = 4 * (cc_regnum - 68); + /* In CCEQmode cases we have made sure that the result is always in the + third bit of the CR field. */ + + if (cc_mode == CCEQmode) + return base_bit + 3; + switch (code) { case NE: @@ -657,7 +710,8 @@ print_operand (file, x, code) switch (code) { case 'h': - /* If constant, output low-order six bits. Otherwise, write normally. */ + /* If constant, output low-order five bits. Otherwise, + write normally. */ if (INT_P (x)) fprintf (file, "%d", INT_LOWPART (x) & 31); else @@ -665,7 +719,7 @@ print_operand (file, x, code) return; case 'H': - /* X must be a constant. Output the low order 6 bits plus 24. */ + /* X must be a constant. Output the low order 5 bits plus 24. */ if (! INT_P (x)) output_operand_lossage ("invalid %%H value"); @@ -684,7 +738,8 @@ print_operand (file, x, code) /* If constant, low-order 16 bits of constant, signed. Otherwise, write normally. */ if (INT_P (x)) - fprintf (file, "%d", (INT_LOWPART (x) << 16) >> 16); + fprintf (file, "%d", + (INT_LOWPART (x) & 0xffff) - 2 * (INT_LOWPART (x) & 0x8000)); else print_operand (file, x, 0); return; @@ -820,6 +875,14 @@ print_operand (file, x, code) fprintf (file, "%d", 32 - 4 * (REGNO (x) - 68)); return; + case 'E': + /* X is a CR register. Print the number of the third bit of the CR */ + if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x))) + output_operand_lossage ("invalid %%E value"); + + fprintf(file, "%d", 4 * (REGNO (x) - 68) + 3); + break; + case 'R': /* X is a CR register. Print the mask for `mtcrf'. */ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x))) @@ -835,7 +898,7 @@ print_operand (file, x, code) return; case 'U': - /* Print `u' is this has an auto-increment or auto-decremement. */ + /* Print `u' is this has an auto-increment or auto-decrement. */ if (GET_CODE (x) == MEM && (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC)) @@ -1008,8 +1071,8 @@ print_operand (file, x, code) return; case 'z': - /* X is a SYMBOL_REF. Write out the name preceeded by a - period and without any trailing data in backets. Used for function + /* X is a SYMBOL_REF. Write out the name preceded by a + period and without any trailing data in brackets. Used for function names. */ if (GET_CODE (x) != SYMBOL_REF) abort (); @@ -1018,6 +1081,17 @@ print_operand (file, x, code) RS6000_OUTPUT_BASENAME (file, XSTR (x, 0)); 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 + write a trash instruction. */ + if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0) + fprintf (file, "l"); + else + fprintf (file, "r"); + return; + case 0: if (GET_CODE (x) == REG) fprintf (file, "%s", reg_names[REGNO (x)]); @@ -1086,6 +1160,15 @@ first_reg_to_save () if (regs_ever_live[first_reg]) break; + /* If profiling, then we must save/restore every register that contains + a parameter before/after the .mcount call. Use registers from 30 down + to 23 to do this. Don't use the frame pointer in reg 31. + + For now, save enough room for all of the parameter registers. */ + if (profile_flag) + if (first_reg > 23) + first_reg = 23; + return first_reg; } @@ -1190,8 +1273,9 @@ output_prolog (file, size) trunc_defined = 1; } - /* If we have to call a function to save fpr's, we will be using LR. */ - if (first_fp_reg < 62) + /* If we have to call a function to save fpr's, or if we are doing profiling, + then we will be using LR. */ + if (first_fp_reg < 62 || profile_flag) regs_ever_live[65] = 1; /* If we use the link register, get it into r0. */ @@ -1276,19 +1360,18 @@ output_epilog (file, size) else if (must_push) fprintf (file, "\tai 1,1,%d\n", total_size); - /* Get the old lr if we saved it. To speed things up, copy it into - lr here if we don't have to save more than 2 fp regs. */ + /* Get the old lr if we saved it. */ if (regs_ever_live[65]) - { - fprintf (file, "\tl 0,8(1)\n"); - if (first_fp_reg >= 62) - fprintf (file, "\tmtlr 0\n"); - } + fprintf (file, "\tl 0,8(1)\n"); /* Get the old cr if we saved it. */ if (must_save_cr ()) fprintf (file, "\tl 12,4(1)\n"); + /* Set LR here to try to overlap restores below. */ + if (regs_ever_live[65]) + 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); @@ -1296,25 +1379,195 @@ output_epilog (file, size) fprintf (file, "\tlm %d,%d(1)\n", first_reg, - (32 - first_reg) * 4 - (64 - first_fp_reg) * 8); - /* Restore fpr's. */ + /* 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"); else if (first_fp_reg == 63) fprintf (file, "\tlfd 31,-8(1)\n"); - else if (first_fp_reg != 64) - fprintf (file, "\tbl ._restf%d\n\tcror 15,15,15\n", first_fp_reg - 32); - - /* If we used the link register, get it from r0 if we haven't - already. */ - if (regs_ever_live[65] && first_fp_reg < 62) - fprintf (file, "\tmtlr 0\n"); /* If we saved cr, restore it here. Just set cr2, cr3, and cr4. */ if (must_save_cr ()) fprintf (file, "\tmtcrf 0x38,12\n"); - fprintf (file, "\tbr\n"); + /* 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); + else + fprintf (file, "\tbr\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, but it doesn't have its own + language_string, so we can't detect it anyways. */ + if (! strcmp (language_string, "GNU 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); + + /* 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 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 @@ -1376,9 +1629,9 @@ output_toc (file, x, labelno) RS6000_OUTPUT_BASENAME (file, name); if (offset < 0) - fprintf (file, "P.N.%d", - offset); + fprintf (file, ".N%d", - offset); else if (offset) - fprintf (file, ".P.%d", offset); + fprintf (file, ".P%d", offset); fprintf (file, "[TC],"); output_addr_const (file, x); @@ -1507,3 +1760,45 @@ rs6000_gen_section_name (buf, filename, else *p = '\0'; } + +/* Write function profiler code. */ + +void +output_function_profiler (file, labelno) + FILE *file; + int labelno; +{ + /* The last used parameter register. */ + int last_parm_reg; + int i, j; + + /* 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); + text_section (); + + /* Figure out last used parameter register. The proper thing to do is + to walk incoming args of the function. A function might have live + parameter registers even if it has no incoming args. */ + + for (last_parm_reg = 10; + last_parm_reg > 2 && ! regs_ever_live [last_parm_reg]; + last_parm_reg--) + ; + + /* Save parameter registers in regs 23-30. Don't overwrite reg 31, since + it might be set up as the frame pointer. */ + + for (i = 3, j = 30; i <= last_parm_reg; i++, j--) + fprintf (file, "\tai %d,%d,0\n", j, i); + + /* Load location address into r3, and call mcount. */ + + fprintf (file, "\tl 3,LPC..%d(2)\n\tbl .mcount\n", labelno); + + /* Restore parameter registers. */ + + for (i = 3, j = 30; i <= last_parm_reg; i++, j--) + fprintf (file, "\tai %d,%d,0\n", i, j); +}