--- gcc/config/mips/mips.c 2018/04/24 18:10:25 1.1.1.1 +++ gcc/config/mips/mips.c 2018/04/24 18:15:37 1.1.1.2 @@ -190,6 +190,9 @@ int mips_isa; char *mips_cpu_string; /* for -mcpu= */ char *mips_isa_string; /* for -mips{1,2,3} */ +/* Generating calls to position independent functions? */ +enum mips_abicalls_type mips_abicalls; + /* Array to RTX class classification. At present, we care about whether the operator is an add-type operator, or a divide/modulus, and if divide/modulus, whether it is unsigned. This is for the @@ -1660,10 +1663,13 @@ gen_int_relational (test_code, result, c ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1) : new > INTVAL (cmp1)) != (p_info->const_add > 0)) - /* 1 is the right value in the LE and LEU case. - In the GT and GTU case, *p_invert is already set, - so this is effectively 0. */ - return force_reg (SImode, const1_rtx); + { + /* This test is always true, but if INVERT is true then + the result of the test needs to be inverted so 0 should + be returned instead. */ + emit_move_insn (result, invert ? const0_rtx : const_true_rtx); + return result; + } else cmp1 = GEN_INT (new); } @@ -2498,11 +2504,15 @@ function_arg_advance (cum, mode, type, n cum->arg_number++; switch (mode) { - default: - error ("Illegal mode given to function_arg_advance"); + case VOIDmode: break; - case VOIDmode: + default: + if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT + && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) + abort (); + cum->gp_reg_found = 1; + cum->arg_words += (GET_MODE_SIZE (mode) + 3) / 4; break; case BLKmode: @@ -2557,10 +2567,6 @@ function_arg (cum, mode, type, named) switch (mode) { - default: - error ("Illegal mode given to function_arg"); - break; - case SFmode: if (cum->gp_reg_found || cum->arg_number >= 2) regbase = GP_ARG_FIRST; @@ -2574,11 +2580,17 @@ function_arg (cum, mode, type, named) case DFmode: cum->arg_words += (cum->arg_words & 1); - regbase = (cum->gp_reg_found || TARGET_SOFT_FLOAT) - ? GP_ARG_FIRST - : FP_ARG_FIRST; + regbase = (cum->gp_reg_found || TARGET_SOFT_FLOAT || cum->arg_number >= 2 + ? GP_ARG_FIRST + : FP_ARG_FIRST); break; + default: + if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT + && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) + abort (); + + /* Drops through. */ case BLKmode: if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD) cum->arg_words += (cum->arg_words & 1); @@ -2625,9 +2637,14 @@ function_arg (cum, mode, type, named) last real argument, pass back a parallel vector holding each of the adjustments. */ - if (struct_p && (mode == QImode || mode == HImode)) + /* ??? function_arg can be called more than once for each argument. + As a result, we compute more adjustments than we need here. + See the CUMULATIVE_ARGS definition in mips.h. */ + + if (struct_p && int_size_in_bytes (type) < 4) { - rtx amount = GEN_INT (BITS_PER_WORD - GET_MODE_BITSIZE (mode)); + rtx amount = GEN_INT (BITS_PER_WORD + - int_size_in_bytes (type) * BITS_PER_UNIT); rtx reg = gen_rtx (REG, SImode, regbase + cum->arg_words + bias); cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount); } @@ -2647,9 +2664,16 @@ function_arg_partial_nregs (cum, mode, t tree type; /* type of the argument or 0 if lib support */ int named; /* != 0 for normal args, == 0 for ... args */ { - if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS) - { - int words = (int_size_in_bytes (type) + 3) / 4; + if ((mode == BLKmode + || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT + || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) + && cum->arg_words < MAX_ARGS_IN_REGISTERS) + { + int words; + if (mode == BLKmode) + words = (int_size_in_bytes (type) + 3) / 4; + else + words = (GET_MODE_SIZE (mode) + 3) / 4; if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS) return 0; /* structure fits in registers */ @@ -2892,6 +2916,11 @@ override_options () if (TARGET_HALF_PIC) HALF_PIC_INIT (); + if (TARGET_ABICALLS) + mips_abicalls = MIPS_ABICALLS_YES; + else + mips_abicalls = MIPS_ABICALLS_NO; + /* -mrnames says to use the MIPS software convention for register names instead of the hardware names (ie, a0 instead of $4). We do this by switching the names in mips_reg_names, which the @@ -2962,6 +2991,7 @@ override_options () mips_print_operand_punct['>'] = TRUE; mips_print_operand_punct['{'] = TRUE; mips_print_operand_punct['}'] = TRUE; + mips_print_operand_punct['^'] = TRUE; mips_char_to_class['d'] = GR_REGS; mips_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS); @@ -3112,7 +3142,8 @@ mips_debugger_offset (addr, offset) '#' Print nop if in a .set noreorder section. '?' Print 'l' if we are to use a branch likely instead of normal branch. '@' Print the name of the assembler temporary register (at or $1). - '.' Print the name of the register with a hard-wired zero (zero or $0). */ + '.' Print the name of the register with a hard-wired zero (zero or $0). + '^' Print the name of the pic call-through register (t9 or $25). */ void print_operand (file, op, letter) @@ -3139,6 +3170,10 @@ print_operand (file, op, letter) fputs (reg_names [GP_REG_FIRST + 1], file); break; + case '^': + fputs (reg_names [PIC_FUNCTION_ADDR_REGNUM], file); + break; + case '.': fputs (reg_names [GP_REG_FIRST + 0], file); break; @@ -3504,16 +3539,20 @@ mips_output_filename (stream, name) first_time = FALSE; SET_FILE_NUMBER (); current_function_file = name; - fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name); + fprintf (stream, "\t.file\t%d ", num_source_filenames); + output_quoted_string (stream, name); + fprintf (stream, "\n"); + /* This tells mips-tfile that stabs will follow. */ if (!TARGET_GAS && write_symbols == DBX_DEBUG) fprintf (stream, "\t#@stabs\n"); } - else if (!TARGET_GAS && write_symbols == DBX_DEBUG) + else if (write_symbols == DBX_DEBUG) { ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); - fprintf (stream, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP, - name, N_SOL, <ext_label_name[1]); + fprintf (stream, "%s ", ASM_STABS_OP); + output_quoted_string (stream, name); + fprintf (stream, ",%d,0,0,%s\n", N_SOL, <ext_label_name[1]); } else if (name != current_function_file @@ -3528,15 +3567,17 @@ mips_output_filename (stream, name) warning ("MIPS ECOFF format does not allow changing filenames within functions with #line"); } - fprintf (stream, "\t#.file\t%d \"%s\"\n", num_source_filenames, name); + fprintf (stream, "\t#.file\t%d ", num_source_filenames); } else { SET_FILE_NUMBER (); current_function_file = name; - fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name); + fprintf (stream, "\t.file\t%d ", num_source_filenames); } + output_quoted_string (stream, name); + fprintf (stream, "\n"); } } @@ -3551,7 +3592,7 @@ mips_output_lineno (stream, line) FILE *stream; int line; { - if (!TARGET_GAS && write_symbols == DBX_DEBUG) + if (write_symbols == DBX_DEBUG) { ++sym_lineno; fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n", @@ -3649,9 +3690,13 @@ mips_asm_file_start (stream) if (TARGET_MIPS_AS && optimize && flag_delayed_branch) fprintf (stream, "\t.set\tnobopt\n"); - /* Generate the pseudo ops that the Pyramid based System V.4 wants. */ + /* Generate the pseudo ops that System V.4 wants. */ +#ifndef ABICALLS_ASM_OP +#define ABICALLS_ASM_OP ".abicalls" +#endif if (TARGET_ABICALLS) - fprintf (stream, "\t.abicalls\n"); + /* ??? but do not want this (or want pic0) if -non-shared? */ + fprintf (stream, "\t%s\n", ABICALLS_ASM_OP); if (TARGET_GP_OPT) { @@ -3871,12 +3916,8 @@ epilogue_reg_mentioned_p (insn) | 4 words to save | | 4 words to save | | arguments passed | | arguments passed | | in registers, even | | in registers, even | - SP->| if not passed. | FP->| if not passed. | + SP->| if not passed. | VFP->| if not passed. | +-----------------------+ +-----------------------+ - | | - | GP save for V.4 abi | - | | - +-----------------------+ | | | fp register save | | | @@ -3894,6 +3935,10 @@ epilogue_reg_mentioned_p (insn) | | +-----------------------+ | | + | GP save for V.4 abi | + | | + +-----------------------+ + | | | arguments on stack | | | +-----------------------+ @@ -3976,6 +4021,15 @@ compute_frame_size (size) if (total_size == extra_size) total_size = extra_size = 0; + else if (TARGET_ABICALLS) + { + /* Add the context-pointer to the saved registers. */ + gp_reg_size += UNITS_PER_WORD; + mask |= 1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST); + total_size -= gp_reg_rounded; + gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); + total_size += gp_reg_rounded; + } /* Save other computed information. */ current_frame_info.total_size = total_size; @@ -3992,7 +4046,8 @@ compute_frame_size (size) if (mask) { - unsigned long offset = args_size + var_size + gp_reg_size - UNITS_PER_WORD; + unsigned long offset = args_size + extra_size + var_size + + gp_reg_size - UNITS_PER_WORD; current_frame_info.gp_sp_offset = offset; current_frame_info.gp_save_offset = offset - total_size; } @@ -4005,7 +4060,8 @@ compute_frame_size (size) if (fmask) { - unsigned long offset = args_size + var_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD; + unsigned long offset = args_size + extra_size + var_size + + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD; current_frame_info.fp_sp_offset = offset; current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD; } @@ -4124,16 +4180,21 @@ save_restore_insns (store_p, large_reg, if (store_p) emit_move_insn (mem_rtx, reg_rtx); - else + else if (!TARGET_ABICALLS + || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) emit_move_insn (reg_rtx, mem_rtx); } else - fprintf (file, "\t%s\t%s,%ld(%s)\n", - (store_p) ? "sw" : "lw", - reg_names[regno], - gp_offset - base_offset, - reg_names[REGNO(base_reg_rtx)]); + { + if (store_p || !TARGET_ABICALLS + || regno != (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) + fprintf (file, "\t%s\t%s,%ld(%s)\n", + (store_p) ? "sw" : "lw", + reg_names[regno], + gp_offset - base_offset, + reg_names[REGNO(base_reg_rtx)]); + } gp_offset -= UNITS_PER_WORD; } } @@ -4257,16 +4318,7 @@ function_prologue (file, size) assemble_name (file, current_function_name); fputs (":\n", file); - if (TARGET_ABICALLS) - fprintf (file, - "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n", - reg_names[ GP_REG_FIRST + 25 ]); - - tsize = current_frame_info.total_size; - if (tsize > 0 && TARGET_ABICALLS) - fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET); - - fprintf (file, "\t.frame\t%s,%d,%s\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n", + fprintf (file, "\t.frame\t%s,%d,%s\t\t# vars= %d, regs= %d/%d, args= %d, extra= %d\n", reg_names[ (frame_pointer_needed) ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ], tsize, reg_names[31 + GP_REG_FIRST], @@ -4281,6 +4333,19 @@ function_prologue (file, size) current_frame_info.gp_save_offset, current_frame_info.fmask, current_frame_info.fp_save_offset); + + if (TARGET_ABICALLS) + { + char *sp_str = reg_names[STACK_POINTER_REGNUM]; + + fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n", + reg_names[PIC_FUNCTION_ADDR_REGNUM]); + if (tsize > 0) + { + fprintf (file, "\tsubu\t%s,%s,%d\n", sp_str, sp_str, tsize); + fprintf (file, "\t.cprestore %d\n", current_frame_info.args_size); + } + } } @@ -4304,6 +4369,18 @@ mips_expand_prologue () tree cur_arg; CUMULATIVE_ARGS args_so_far; + /* If struct value address is treated as the first argument, make it so. */ + if (aggregate_value_p (DECL_RESULT (fndecl)) + && ! current_function_returns_pcc_struct + && struct_value_incoming_rtx == 0) + { + tree type = build_pointer_type (fntype); + tree function_result_decl = build_decl (PARM_DECL, NULL_TREE, type); + DECL_ARG_TYPE (function_result_decl) = type; + TREE_CHAIN (function_result_decl) = fnargs; + fnargs = function_result_decl; + } + /* Determine the last argument, and get its name. */ INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0); @@ -4376,6 +4453,8 @@ mips_expand_prologue () } } + tsize = compute_frame_size (get_frame_size ()); + /* If this function is a varargs function, store any registers that would normally hold arguments ($4 - $7) on the stack. */ if ((TYPE_ARG_TYPES (fntype) != 0 @@ -4384,30 +4463,40 @@ mips_expand_prologue () && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0) || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0)))) { + int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD; + rtx ptr = stack_pointer_rtx; + + /* If we are doing svr4-abi, sp has already been decremented by tsize. */ + if (TARGET_ABICALLS) + offset += tsize; + for (; regno <= GP_ARG_LAST; regno++) { - rtx ptr = stack_pointer_rtx; - if (regno != GP_ARG_FIRST) - ptr = gen_rtx (PLUS, Pmode, ptr, - GEN_INT ((regno - GP_ARG_FIRST) * UNITS_PER_WORD)); - - emit_move_insn (gen_rtx (MEM, Pmode, ptr), gen_rtx (REG, Pmode, regno)); + if (offset != 0) + ptr = gen_rtx (PLUS, Pmode, stack_pointer_rtx, GEN_INT (offset)); + emit_move_insn (gen_rtx (MEM, Pmode, ptr), + gen_rtx (REG, Pmode, regno)); + offset += UNITS_PER_WORD; } } - tsize = compute_frame_size (get_frame_size ()); if (tsize > 0) { rtx tsize_rtx = GEN_INT (tsize); - if (tsize > 32767) + /* If we are doing svr4-abi, sp move is done by function_prologue. */ + if (!TARGET_ABICALLS) { - tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM); - emit_move_insn (tmp_rtx, tsize_rtx); - tsize_rtx = tmp_rtx; - } + if (tsize > 32767) + { + tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM); + emit_move_insn (tmp_rtx, tsize_rtx); + tsize_rtx = tmp_rtx; + } - emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx)); + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, + tsize_rtx)); + } save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0); @@ -4426,6 +4515,7 @@ mips_expand_prologue () /* Do any necessary cleanup after a function to restore stack, frame, and regs. */ #define RA_MASK ((long) 0x80000000) /* 1 << 31 */ +#define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) void function_epilogue (file, size) @@ -4534,7 +4624,9 @@ function_epilogue (file, size) save_restore_insns (FALSE, tmp_rtx, tsize, file); - load_only_r31 = (current_frame_info.mask == RA_MASK + load_only_r31 = (((current_frame_info.mask + & ~ (TARGET_ABICALLS ? PIC_OFFSET_TABLE_MASK : 0)) + == RA_MASK) && current_frame_info.fmask == 0); if (noreorder)