diff options
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/gcc/config/alpha/alpha.c | 469 |
1 files changed, 316 insertions, 153 deletions
diff --git a/contrib/gcc/config/alpha/alpha.c b/contrib/gcc/config/alpha/alpha.c index 2320f1c..eb478e0 100644 --- a/contrib/gcc/config/alpha/alpha.c +++ b/contrib/gcc/config/alpha/alpha.c @@ -48,9 +48,7 @@ Boston, MA 02111-1307, USA. */ #include "tm_p.h" #include "target.h" #include "target-def.h" - -/* External data. */ -extern int rtx_equal_function_value_matters; +#include "debug.h" /* Specify which cpu to schedule for. */ @@ -118,9 +116,9 @@ int alpha_this_gpdisp_sequence_number; /* Declarations of static functions. */ static bool decl_in_text_section PARAMS ((tree)); -static int some_small_symbolic_mem_operand_1 +static int some_small_symbolic_operand_1 PARAMS ((rtx *, void *)); -static int split_small_symbolic_mem_operand_1 +static int split_small_symbolic_operand_1 PARAMS ((rtx *, void *)); static bool local_symbol_p PARAMS ((rtx)); @@ -1876,61 +1874,55 @@ alpha_legitimize_address (x, scratch, mode) so that sched2 has the proper dependency information. */ int -some_small_symbolic_mem_operand (x, mode) +some_small_symbolic_operand (x, mode) rtx x; enum machine_mode mode ATTRIBUTE_UNUSED; { - return for_each_rtx (&x, some_small_symbolic_mem_operand_1, NULL); + return for_each_rtx (&x, some_small_symbolic_operand_1, NULL); } static int -some_small_symbolic_mem_operand_1 (px, data) +some_small_symbolic_operand_1 (px, data) rtx *px; void *data ATTRIBUTE_UNUSED; { rtx x = *px; - if (GET_CODE (x) != MEM) - return 0; - x = XEXP (x, 0); - - /* If this is an ldq_u type address, discard the outer AND. */ - if (GET_CODE (x) == AND) - x = XEXP (x, 0); + /* Don't re-split. */ + if (GET_CODE (x) == LO_SUM) + return -1; - return small_symbolic_operand (x, Pmode) ? 1 : -1; + return small_symbolic_operand (x, Pmode) != 0; } rtx -split_small_symbolic_mem_operand (x) +split_small_symbolic_operand (x) rtx x; { x = copy_insn (x); - for_each_rtx (&x, split_small_symbolic_mem_operand_1, NULL); + for_each_rtx (&x, split_small_symbolic_operand_1, NULL); return x; } static int -split_small_symbolic_mem_operand_1 (px, data) +split_small_symbolic_operand_1 (px, data) rtx *px; void *data ATTRIBUTE_UNUSED; { rtx x = *px; - if (GET_CODE (x) != MEM) - return 0; - - px = &XEXP (x, 0), x = *px; - if (GET_CODE (x) == AND) - px = &XEXP (x, 0), x = *px; + /* Don't re-split. */ + if (GET_CODE (x) == LO_SUM) + return -1; if (small_symbolic_operand (x, Pmode)) { x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x); *px = x; + return -1; } - return -1; + return 0; } /* Try a machine-dependent way of reloading an illegitimate address @@ -2238,15 +2230,39 @@ alpha_emit_set_const (target, mode, c, n) HOST_WIDE_INT c; int n; { - rtx pat; + rtx result = 0; + rtx orig_target = target; int i; + /* If we can't make any pseudos, TARGET is an SImode hard register, we + can't load this constant in one insn, do this in DImode. */ + if (no_new_pseudos && mode == SImode + && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER + && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0) + { + target = gen_lowpart (DImode, target); + mode = DImode; + } + /* Try 1 insn, then 2, then up to N. */ for (i = 1; i <= n; i++) - if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0) - return pat; + { + result = alpha_emit_set_const_1 (target, mode, c, i); + if (result) + { + rtx insn = get_last_insn (); + rtx set = single_set (insn); + if (! CONSTANT_P (SET_SRC (set))) + set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c)); + break; + } + } - return 0; + /* Allow for the case where we changed the mode of TARGET. */ + if (result == target) + result = orig_target; + + return result; } /* Internal routine for the above to check for N or below insns. */ @@ -2262,18 +2278,8 @@ alpha_emit_set_const_1 (target, mode, c, n) int i, bits; /* Use a pseudo if highly optimizing and still generating RTL. */ rtx subtarget - = (flag_expensive_optimizations && rtx_equal_function_value_matters - ? 0 : target); - rtx temp; - -#if HOST_BITS_PER_WIDE_INT == 64 - /* We are only called for SImode and DImode. If this is SImode, ensure that - we are sign extended to a full word. This does not make any sense when - cross-compiling on a narrow machine. */ - - if (mode == SImode) - c = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000; -#endif + = (flag_expensive_optimizations && !no_new_pseudos ? 0 : target); + rtx temp, insn; /* If this is a sign-extended 32-bit constant, we can do this in at most three insns, so do it if we have enough insns left. We always have @@ -2314,12 +2320,28 @@ alpha_emit_set_const_1 (target, mode, c, n) { temp = copy_to_suggested_reg (GEN_INT (high << 16), subtarget, mode); + /* As of 2002-02-23, addsi3 is only available when not optimizing. + This means that if we go through expand_binop, we'll try to + generate extensions, etc, which will require new pseudos, which + will fail during some split phases. The SImode add patterns + still exist, but are not named. So build the insns by hand. */ + if (extra != 0) - temp = expand_binop (mode, add_optab, temp, GEN_INT (extra << 16), - subtarget, 0, OPTAB_WIDEN); + { + if (! subtarget) + subtarget = gen_reg_rtx (mode); + insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16)); + insn = gen_rtx_SET (VOIDmode, subtarget, insn); + emit_insn (insn); + temp = subtarget; + } - return expand_binop (mode, add_optab, temp, GEN_INT (low), - target, 0, OPTAB_WIDEN); + if (target == NULL) + target = gen_reg_rtx (mode); + insn = gen_rtx_PLUS (mode, temp, GEN_INT (low)); + insn = gen_rtx_SET (VOIDmode, target, insn); + emit_insn (insn); + return target; } } @@ -2328,8 +2350,7 @@ alpha_emit_set_const_1 (target, mode, c, n) we can't make pseudos, we can't do anything since the expand_binop and expand_unop calls will widen and try to make pseudos. */ - if (n == 1 - || (mode == SImode && ! rtx_equal_function_value_matters)) + if (n == 1 || (mode == SImode && no_new_pseudos)) return 0; /* Next, see if we can load a related constant and then shift and possibly @@ -2510,7 +2531,26 @@ alpha_expand_mov (mode, operands) /* Allow legitimize_address to perform some simplifications. */ if (mode == Pmode && symbolic_operand (operands[1], mode)) { - rtx tmp = alpha_legitimize_address (operands[1], operands[0], mode); + rtx tmp; + + /* With RTL inlining, at -O3, rtl is generated, stored, then actually + compiled at the end of compilation. In the meantime, someone can + re-encode-section-info on some symbol changing it e.g. from global + to local-not-small. If this happens, we'd have emitted a plain + load rather than a high+losum load and not recognize the insn. + + So if rtl inlining is in effect, we delay the global/not-global + decision until rest_of_compilation by wrapping it in an + UNSPEC_SYMBOL. */ + if (TARGET_EXPLICIT_RELOCS && flag_inline_functions + && rtx_equal_function_value_matters + && global_symbolic_operand (operands[1], mode)) + { + emit_insn (gen_movdi_er_maybe_g (operands[0], operands[1])); + return true; + } + + tmp = alpha_legitimize_address (operands[1], operands[0], mode); if (tmp) { operands[1] = tmp; @@ -2786,21 +2826,29 @@ alpha_emit_conditional_branch (code) 1 true Convert the compare against the raw return value. */ - if (code == UNORDERED || code == ORDERED) - cmp_code = EQ; - else - cmp_code = code; + switch (code) + { + case UNORDERED: + cmp_code = EQ; + code = LT; + break; + case ORDERED: + cmp_code = EQ; + code = GE; + break; + case NE: + cmp_code = NE; + code = NE; + break; + default: + cmp_code = code; + code = GT; + break; + } op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1); op1 = const0_rtx; alpha_compare.fp_p = 0; - - if (code == UNORDERED) - code = LT; - else if (code == ORDERED) - code = GE; - else - code = GT; } /* The general case: fold the comparison code to the types of compares @@ -4987,7 +5035,10 @@ alpha_return_addr (count, frame) rtx alpha_gp_save_rtx () { - return get_hard_reg_initial_val (DImode, 29); + rtx r = get_hard_reg_initial_val (DImode, 29); + if (GET_CODE (r) != MEM) + r = gen_mem_addressof (r, NULL_TREE); + return r; } static int @@ -4995,10 +5046,6 @@ alpha_ra_ever_killed () { rtx top; -#ifdef ASM_OUTPUT_MI_THUNK - if (current_function_is_thunk) - return 0; -#endif if (!has_hard_reg_initial_val (Pmode, REG_RA)) return regs_ever_live[REG_RA]; @@ -5514,12 +5561,13 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs) OPTAB_WIDEN); temp = expand_shift (RSHIFT_EXPR, Pmode, temp, build_int_2 (2, 0), NULL_RTX, 1); - temp = expand_and (gen_lowpart (SImode, temp), GEN_INT (0x3fff), 0); + temp = expand_and (SImode, gen_lowpart (SImode, temp), + GEN_INT (0x3fff), 0); /* Merge in the hint. */ addr = memory_address (SImode, plus_constant (tramp, jmpofs)); temp1 = force_reg (SImode, gen_rtx_MEM (SImode, addr)); - temp1 = expand_and (temp1, GEN_INT (0xffffc000), NULL_RTX); + temp1 = expand_and (SImode, temp1, GEN_INT (0xffffc000), NULL_RTX); temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1, OPTAB_WIDEN); emit_move_insn (gen_rtx_MEM (SImode, addr), temp1); @@ -5761,9 +5809,8 @@ rtx alpha_va_arg (valist, type) tree valist, type; { - HOST_WIDE_INT tsize; rtx addr; - tree t; + tree t, type_size, rounded_size; tree offset_field, base_field, addr_tree, addend; tree wide_type, wide_ofs; int indirect = 0; @@ -5771,7 +5818,18 @@ alpha_va_arg (valist, type) if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK) return std_expand_builtin_va_arg (valist, type); - tsize = ((TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT + 7) / 8) * 8; + if (type == error_mark_node + || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL + || TREE_OVERFLOW (type_size)) + rounded_size = size_zero_node; + else + rounded_size = fold (build (MULT_EXPR, sizetype, + fold (build (TRUNC_DIV_EXPR, sizetype, + fold (build (PLUS_EXPR, sizetype, + type_size, + size_int (7))), + size_int (8))), + size_int (8))); base_field = TYPE_FIELDS (TREE_TYPE (valist)); offset_field = TREE_CHAIN (base_field); @@ -5781,6 +5839,17 @@ alpha_va_arg (valist, type) offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field), valist, offset_field); + /* If the type could not be passed in registers, skip the block + reserved for the registers. */ + if (MUST_PASS_IN_STACK (TYPE_MODE (type), type)) + { + t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, + build (MAX_EXPR, TREE_TYPE (offset_field), + offset_field, build_int_2 (6*8, 0))); + TREE_SIDE_EFFECTS (t) = 1; + expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); + } + wide_type = make_signed_type (64); wide_ofs = save_expr (build1 (CONVERT_EXPR, wide_type, offset_field)); @@ -5789,7 +5858,7 @@ alpha_va_arg (valist, type) if (TYPE_MODE (type) == TFmode || TYPE_MODE (type) == TCmode) { indirect = 1; - tsize = UNITS_PER_WORD; + rounded_size = size_int (UNITS_PER_WORD); } else if (FLOAT_TYPE_P (type)) { @@ -5813,7 +5882,7 @@ alpha_va_arg (valist, type) t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, build (PLUS_EXPR, TREE_TYPE (offset_field), - offset_field, build_int_2 (tsize, 0))); + offset_field, rounded_size)); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -5837,7 +5906,8 @@ alpha_va_arg (valist, type) descriptior to generate. */ /* Nonzero if we need a stack procedure. */ -static int alpha_is_stack_procedure; +enum alpha_procedure_types {PT_NULL = 0, PT_REGISTER = 1, PT_STACK = 2}; +static enum alpha_procedure_types alpha_procedure_type; /* Register number (either FP or SP) that is used to unwind the frame. */ static int vms_unwind_regno; @@ -5861,43 +5931,48 @@ alpha_sa_mask (imaskP, fmaskP) unsigned long fmask = 0; unsigned int i; -#ifdef ASM_OUTPUT_MI_THUNK - if (!current_function_is_thunk) -#endif + /* Irritatingly, there are two kinds of thunks -- those created with + ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go through + the regular part of the compiler. In the ASM_OUTPUT_MI_THUNK case + we don't have valid register life info, but assemble_start_function + wants to output .frame and .mask directives. */ + if (current_function_is_thunk && !no_new_pseudos) { - if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure) - imask |= (1L << HARD_FRAME_POINTER_REGNUM); + *imaskP = 0; + *fmaskP = 0; + return; + } - /* One for every register we have to save. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (! fixed_regs[i] && ! call_used_regs[i] - && regs_ever_live[i] && i != REG_RA - && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM)) - { - if (i < 32) - imask |= (1L << i); - else - fmask |= (1L << (i - 32)); - } + if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) + imask |= (1L << HARD_FRAME_POINTER_REGNUM); - /* We need to restore these for the handler. */ - if (current_function_calls_eh_return) - { - for (i = 0; ; ++i) - { - unsigned regno = EH_RETURN_DATA_REGNO (i); - if (regno == INVALID_REGNUM) - break; - imask |= 1L << regno; - } - } + /* One for every register we have to save. */ + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (! fixed_regs[i] && ! call_used_regs[i] + && regs_ever_live[i] && i != REG_RA + && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM)) + { + if (i < 32) + imask |= (1L << i); + else + fmask |= (1L << (i - 32)); + } + + /* We need to restore these for the handler. */ + if (current_function_calls_eh_return) + for (i = 0; ; ++i) + { + unsigned regno = EH_RETURN_DATA_REGNO (i); + if (regno == INVALID_REGNUM) + break; + imask |= 1L << regno; + } - /* If any register spilled, then spill the return address also. */ - /* ??? This is required by the Digital stack unwind specification - and isn't needed if we're doing Dwarf2 unwinding. */ - if (imask || fmask || alpha_ra_ever_killed ()) - imask |= (1L << REG_RA); - } + /* If any register spilled, then spill the return address also. */ + /* ??? This is required by the Digital stack unwind specification + and isn't needed if we're doing Dwarf2 unwinding. */ + if (imask || fmask || alpha_ra_ever_killed ()) + imask |= (1L << REG_RA); *imaskP = imask; *fmaskP = fmask; @@ -5933,17 +6008,16 @@ alpha_sa_size () use alloca and have not determined that we need a frame for other reasons. */ - alpha_is_stack_procedure = (sa_size - || get_frame_size() != 0 - || current_function_outgoing_args_size - || current_function_varargs - || current_function_stdarg - || current_function_calls_alloca - || frame_pointer_needed); + alpha_procedure_type + = (sa_size || get_frame_size() != 0 + || current_function_outgoing_args_size || current_function_varargs + || current_function_stdarg || current_function_calls_alloca + || frame_pointer_needed) + ? PT_STACK : PT_REGISTER; /* Always reserve space for saving callee-saved registers if we need a frame as required by the calling convention. */ - if (alpha_is_stack_procedure) + if (alpha_procedure_type == PT_STACK) sa_size = 14; } else if (TARGET_ABI_OPEN_VMS) @@ -5951,22 +6025,29 @@ alpha_sa_size () /* Start by assuming we can use a register procedure if we don't make any calls (REG_RA not used) or need to save any registers and a stack procedure if we do. */ - alpha_is_stack_procedure = ((mask[0] >> REG_RA) & 1); + if ((mask[0] >> REG_RA) & 1) + alpha_procedure_type = PT_STACK; + else if (get_frame_size() != 0) + alpha_procedure_type = PT_REGISTER; + else + alpha_procedure_type = PT_NULL; - /* Don't reserve space for saving RA yet. Do that later after we've + /* Don't reserve space for saving FP & RA yet. Do that later after we've made the final decision on stack procedure vs register procedure. */ - if (alpha_is_stack_procedure) - sa_size--; + if (alpha_procedure_type == PT_STACK) + sa_size -= 2; /* Decide whether to refer to objects off our PV via FP or PV. If we need FP for something else or if we receive a nonlocal goto (which expects PV to contain the value), we must use PV. Otherwise, start by assuming we can use FP. */ - vms_base_regno = (frame_pointer_needed - || current_function_has_nonlocal_label - || alpha_is_stack_procedure - || current_function_outgoing_args_size - ? REG_PV : HARD_FRAME_POINTER_REGNUM); + + vms_base_regno + = (frame_pointer_needed + || current_function_has_nonlocal_label + || alpha_procedure_type == PT_STACK + || current_function_outgoing_args_size) + ? REG_PV : HARD_FRAME_POINTER_REGNUM; /* If we want to copy PV into FP, we need to find some register in which to save FP. */ @@ -5977,15 +6058,17 @@ alpha_sa_size () if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i]) vms_save_fp_regno = i; - if (vms_save_fp_regno == -1) - vms_base_regno = REG_PV, alpha_is_stack_procedure = 1; + if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER) + vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK; + else if (alpha_procedure_type == PT_NULL) + vms_base_regno = REG_PV; /* Stack unwinding should be done via FP unless we use it for PV. */ vms_unwind_regno = (vms_base_regno == REG_PV ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); /* If this is a stack procedure, allow space for saving FP and RA. */ - if (alpha_is_stack_procedure) + if (alpha_procedure_type == PT_STACK) sa_size += 2; } else @@ -6002,7 +6085,7 @@ int alpha_pv_save_size () { alpha_sa_size (); - return alpha_is_stack_procedure ? 8 : 0; + return alpha_procedure_type == PT_STACK ? 8 : 0; } int @@ -6045,10 +6128,8 @@ alpha_does_function_need_gp () if (TARGET_PROFILING_NEEDS_GP && current_function_profile) return 1; -#ifdef ASM_OUTPUT_MI_THUNK if (current_function_is_thunk) return 1; -#endif /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. Even if we are a static function, we still need to do this in case @@ -6153,13 +6234,13 @@ alpha_expand_prologue () frame_size = get_frame_size (); if (TARGET_ABI_OPEN_VMS) frame_size = ALPHA_ROUND (sa_size - + (alpha_is_stack_procedure ? 8 : 0) + + (alpha_procedure_type == PT_STACK ? 8 : 0) + frame_size + current_function_pretend_args_size); else if (TARGET_ABI_UNICOSMK) /* We have to allocate space for the DSIB if we generate a frame. */ frame_size = ALPHA_ROUND (sa_size - + (alpha_is_stack_procedure ? 48 : 0)) + + (alpha_procedure_type == PT_STACK ? 48 : 0)) + ALPHA_ROUND (frame_size + current_function_outgoing_args_size); else @@ -6314,7 +6395,7 @@ alpha_expand_prologue () } /* Save regs in stack order. Beginning with VMS PV. */ - if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure) + if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) { mem = gen_rtx_MEM (DImode, stack_pointer_rtx); set_mem_alias_set (mem, alpha_sr_alias_set); @@ -6350,7 +6431,7 @@ alpha_expand_prologue () reg_offset += 8; } } - else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure) + else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK) { /* The standard frame on the T3E includes space for saving registers. We just have to use it. We don't have to save the return address and @@ -6379,17 +6460,18 @@ alpha_expand_prologue () if (TARGET_ABI_OPEN_VMS) { - if (!alpha_is_stack_procedure) - /* Register frame procedures save the fp. */ - /* ??? Ought to have a dwarf2 save for this. */ + if (alpha_procedure_type == PT_REGISTER) + /* Register frame procedures save the fp. + ?? Ought to have a dwarf2 save for this. */ emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno), hard_frame_pointer_rtx); - if (vms_base_regno != REG_PV) + if (alpha_procedure_type != PT_NULL && vms_base_regno != REG_PV) emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno), gen_rtx_REG (DImode, REG_PV))); - if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM) + if (alpha_procedure_type != PT_NULL + && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM) FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); /* If we have to allocate space for outgoing args, do it now. */ @@ -6462,12 +6544,12 @@ alpha_start_function (file, fnname, decl) frame_size = get_frame_size (); if (TARGET_ABI_OPEN_VMS) frame_size = ALPHA_ROUND (sa_size - + (alpha_is_stack_procedure ? 8 : 0) + + (alpha_procedure_type == PT_STACK ? 8 : 0) + frame_size + current_function_pretend_args_size); else if (TARGET_ABI_UNICOSMK) frame_size = ALPHA_ROUND (sa_size - + (alpha_is_stack_procedure ? 48 : 0)) + + (alpha_procedure_type == PT_STACK ? 48 : 0)) + ALPHA_ROUND (frame_size + current_function_outgoing_args_size); else @@ -6514,7 +6596,9 @@ alpha_start_function (file, fnname, decl) /* If the function needs GP, we'll write the "..ng" label there. Otherwise, do it here. */ - if (TARGET_ABI_OSF && ! alpha_function_needs_gp) + if (TARGET_ABI_OSF + && ! alpha_function_needs_gp + && ! current_function_is_thunk) { putc ('$', file); assemble_name (file, fnname); @@ -6585,7 +6669,7 @@ alpha_start_function (file, fnname, decl) fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1L << REG_RA)); if (fmask) fprintf (file, "\t.fmask 0x%lx,0\n", fmask); - if (!alpha_is_stack_procedure) + if (alpha_procedure_type == PT_REGISTER) fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno); } else if (!flag_inhibit_size_directive) @@ -6629,7 +6713,9 @@ alpha_start_function (file, fnname, decl) ASM_OUTPUT_LABEL (file, fnname); fprintf (file, "\t.pdesc "); assemble_name (file, fnname); - fprintf (file, "..en,%s\n", alpha_is_stack_procedure ? "stack" : "reg"); + fprintf (file, "..en,%s\n", + alpha_procedure_type == PT_STACK ? "stack" + : alpha_procedure_type == PT_REGISTER ? "reg" : "null"); alpha_need_linkage (fnname, 1); text_section (); #endif @@ -6648,7 +6734,8 @@ alpha_output_function_end_prologue (file) else if (TARGET_ABI_WINDOWS_NT) fputs ("\t.prologue 0\n", file); else if (!flag_inhibit_size_directive) - fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp); + fprintf (file, "\t.prologue %d\n", + alpha_function_needs_gp || current_function_is_thunk); } /* Write function epilogue. */ @@ -6682,12 +6769,12 @@ alpha_expand_epilogue () frame_size = get_frame_size (); if (TARGET_ABI_OPEN_VMS) frame_size = ALPHA_ROUND (sa_size - + (alpha_is_stack_procedure ? 8 : 0) + + (alpha_procedure_type == PT_STACK ? 8 : 0) + frame_size + current_function_pretend_args_size); else if (TARGET_ABI_UNICOSMK) frame_size = ALPHA_ROUND (sa_size - + (alpha_is_stack_procedure ? 48 : 0)) + + (alpha_procedure_type == PT_STACK ? 48 : 0)) + ALPHA_ROUND (frame_size + current_function_outgoing_args_size); else @@ -6697,14 +6784,20 @@ alpha_expand_epilogue () + current_function_pretend_args_size)); if (TARGET_ABI_OPEN_VMS) - reg_offset = 8; + { + if (alpha_procedure_type == PT_STACK) + reg_offset = 8; + else + reg_offset = 0; + } else reg_offset = ALPHA_ROUND (current_function_outgoing_args_size); alpha_sa_mask (&imask, &fmask); - fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure) - || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed)); + fp_is_frame_pointer + = ((TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) + || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed)); fp_offset = 0; sa_reg = stack_pointer_rtx; @@ -6771,7 +6864,7 @@ alpha_expand_epilogue () reg_offset += 8; } } - else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure) + else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK) { /* Restore callee-saved general-purpose registers. */ @@ -6891,13 +6984,13 @@ alpha_expand_epilogue () } else { - if (TARGET_ABI_OPEN_VMS && !alpha_is_stack_procedure) + if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER) { emit_insn (gen_blockage ()); FRP (emit_move_insn (hard_frame_pointer_rtx, gen_rtx_REG (DImode, vms_save_fp_regno))); } - else if (TARGET_ABI_UNICOSMK && !alpha_is_stack_procedure) + else if (TARGET_ABI_UNICOSMK && alpha_procedure_type != PT_STACK) { /* Decrement the frame pointer if the function does not have a frame. */ @@ -6948,6 +7041,76 @@ alpha_end_function (file, fnname, decl) unicosmk_output_deferred_case_vectors (file); } } + +/* Emit a tail call to FUNCTION after adjusting THIS by DELTA. + + In order to avoid the hordes of differences between generated code + with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating + lots of code loading up large constants, generate rtl and emit it + instead of going straight to text. + + Not sure why this idea hasn't been explored before... */ + +void +alpha_output_mi_thunk_osf (file, thunk_fndecl, delta, function) + FILE *file; + tree thunk_fndecl ATTRIBUTE_UNUSED; + HOST_WIDE_INT delta; + tree function; +{ + HOST_WIDE_INT hi, lo; + rtx this, insn, funexp; + + /* We always require a valid GP. */ + emit_insn (gen_prologue_ldgp ()); + emit_note (NULL, NOTE_INSN_PROLOGUE_END); + + /* Find the "this" pointer. If the function returns a structure, + the structure return pointer is in $16. */ + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))) + this = gen_rtx_REG (Pmode, 17); + else + this = gen_rtx_REG (Pmode, 16); + + /* Add DELTA. When possible we use ldah+lda. Otherwise load the + entire constant for the add. */ + lo = ((delta & 0xffff) ^ 0x8000) - 0x8000; + hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000; + if (hi + lo == delta) + { + if (hi) + emit_insn (gen_adddi3 (this, this, GEN_INT (hi))); + if (lo) + emit_insn (gen_adddi3 (this, this, GEN_INT (lo))); + } + else + { + rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0), + delta, -(delta < 0)); + emit_insn (gen_adddi3 (this, this, tmp)); + } + + /* Generate a tail call to the target function. */ + if (! TREE_USED (function)) + { + assemble_external (function); + TREE_USED (function) = 1; + } + funexp = XEXP (DECL_RTL (function), 0); + funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); + insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); + SIBLING_CALL_P (insn) = 1; + + /* Run just enough of rest_of_compilation to get the insns emitted. + There's not really enough bulk here to make other passes such as + instruction scheduling worth while. Note that use_thunk calls + assemble_start_function and assemble_end_function. */ + insn = get_insns (); + shorten_branches (insn); + final_start_function (insn, file, 1); + final (insn, file, 1, 0); + final_end_function (); +} /* Debugging support. */ @@ -8630,7 +8793,7 @@ static void unicosmk_gen_dsib (imaskP) unsigned long * imaskP; { - if (alpha_is_stack_procedure) + if (alpha_procedure_type == PT_STACK) { const char *ssib_name; rtx mem; |