Mercurial > hg > CbC > CbC_gcc
diff gcc/config/pa/pa.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | 3bfb6c00c1e0 |
children | b7f97abdc517 |
line wrap: on
line diff
--- a/gcc/config/pa/pa.c Sun Feb 07 18:28:00 2010 +0900 +++ b/gcc/config/pa/pa.c Fri Feb 12 23:39:51 2010 +0900 @@ -93,7 +93,7 @@ static void pa_reorg (void); static void pa_combine_instructions (void); static int pa_can_combine_p (rtx, rtx, rtx, int, rtx, rtx, rtx); -static int forward_branch_p (rtx); +static bool forward_branch_p (rtx); static void compute_zdepwi_operands (unsigned HOST_WIDE_INT, unsigned *); static int compute_movmem_length (rtx); static int compute_clrmem_length (rtx); @@ -103,6 +103,7 @@ static void store_reg_modify (int, int, HOST_WIDE_INT); static void load_reg (int, HOST_WIDE_INT, int); static void set_reg_plus_d (int, int, HOST_WIDE_INT, int); +static rtx pa_function_value (const_tree, const_tree, bool); static void pa_output_function_prologue (FILE *, HOST_WIDE_INT); static void update_total_code_bytes (unsigned int); static void pa_output_function_epilogue (FILE *, HOST_WIDE_INT); @@ -131,6 +132,7 @@ static bool pa_commutative_p (const_rtx x, int outer_code); static void copy_fp_args (rtx) ATTRIBUTE_UNUSED; static int length_fp_args (rtx) ATTRIBUTE_UNUSED; +static rtx hppa_legitimize_address (rtx, rtx, enum machine_mode); static inline void pa_file_start_level (void) ATTRIBUTE_UNUSED; static inline void pa_file_start_space (int) ATTRIBUTE_UNUSED; static inline void pa_file_start_file (int) ATTRIBUTE_UNUSED; @@ -158,17 +160,19 @@ enum machine_mode, secondary_reload_info *); static void pa_extra_live_on_entry (bitmap); +static enum machine_mode pa_promote_function_mode (const_tree, + enum machine_mode, int *, + const_tree, int); + +static void pa_asm_trampoline_template (FILE *); +static void pa_trampoline_init (rtx, tree, rtx); +static rtx pa_trampoline_adjust_address (rtx); /* The following extra sections are only used for SOM. */ static GTY(()) section *som_readonly_data_section; static GTY(()) section *som_one_only_readonly_data_section; static GTY(()) section *som_one_only_data_section; -/* Save the operands last given to a compare for use when we - generate a scc or bcc insn. */ -rtx hppa_compare_op0, hppa_compare_op1; -enum cmp_type hppa_branch_type; - /* Which cpu we are scheduling for. */ enum processor_type pa_cpu = TARGET_SCHED_DEFAULT; @@ -196,7 +200,7 @@ /* Variables to handle plabels that we discover are necessary at assembly output time. They are output after the current function. */ -struct deferred_plabel GTY(()) +struct GTY(()) deferred_plabel { rtx internal_label; rtx symbol; @@ -228,6 +232,12 @@ #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE pa_output_function_epilogue +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE pa_function_value + +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS hppa_legitimize_address + #undef TARGET_SCHED_ADJUST_COST #define TARGET_SCHED_ADJUST_COST pa_adjust_cost #undef TARGET_SCHED_ADJUST_PRIORITY @@ -286,8 +296,8 @@ #define TARGET_INIT_LIBFUNCS pa_hpux_init_libfuncs #endif -#undef TARGET_PROMOTE_FUNCTION_RETURN -#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true +#undef TARGET_PROMOTE_FUNCTION_MODE +#define TARGET_PROMOTE_FUNCTION_MODE pa_promote_function_mode #undef TARGET_PROMOTE_PROTOTYPES #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true @@ -323,6 +333,13 @@ #undef TARGET_EXTRA_LIVE_ON_ENTRY #define TARGET_EXTRA_LIVE_ON_ENTRY pa_extra_live_on_entry +#undef TARGET_ASM_TRAMPOLINE_TEMPLATE +#define TARGET_ASM_TRAMPOLINE_TEMPLATE pa_asm_trampoline_template +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT pa_trampoline_init +#undef TARGET_TRAMPOLINE_ADJUST_ADDRESS +#define TARGET_TRAMPOLINE_ADJUST_ADDRESS pa_trampoline_adjust_address + struct gcc_target targetm = TARGET_INITIALIZER; /* Parse the -mfixed-range= option string. */ @@ -684,7 +701,7 @@ insn = emit_insn (gen_rtx_SET (VOIDmode, reg, orig)); /* Put a REG_EQUAL note on this insn, so that it can be optimized. */ - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, REG_NOTES (insn)); + add_reg_note (insn, REG_EQUAL, orig); /* During and after reload, we need to generate a REG_LABEL_OPERAND note and update LABEL_NUSES because this is not done automatically. */ @@ -872,9 +889,6 @@ OLDX is the address as it was before break_out_memory_refs was called. In some cases it is useful to look at this to decide what needs to be done. - MODE and WIN are passed so that this macro can use - GO_IF_LEGITIMATE_ADDRESS. - It is always safe for this macro to do nothing. It exists to recognize opportunities to optimize the output. @@ -3400,11 +3414,9 @@ insn = emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg)); if (DO_FRAME_NOTES) { - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, tmpreg, - gen_rtx_PLUS (Pmode, basereg, delta)), - REG_NOTES (insn)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, tmpreg, + gen_rtx_PLUS (Pmode, basereg, delta))); RTX_FRAME_RELATED_P (insn) = 1; } dest = gen_rtx_MEM (word_mode, tmpreg); @@ -3420,16 +3432,13 @@ dest = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta)); insn = emit_move_insn (dest, src); if (DO_FRAME_NOTES) - { - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, - gen_rtx_MEM (word_mode, - gen_rtx_PLUS (word_mode, basereg, - delta)), - src), - REG_NOTES (insn)); - } + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, + gen_rtx_MEM (word_mode, + gen_rtx_PLUS (word_mode, + basereg, + delta)), + src)); } if (DO_FRAME_NOTES) @@ -3489,11 +3498,9 @@ insn = emit_move_insn (gen_rtx_REG (Pmode, reg), gen_rtx_PLUS (Pmode, tmpreg, basereg)); if (DO_FRAME_NOTES) - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, tmpreg, - gen_rtx_PLUS (Pmode, basereg, delta)), - REG_NOTES (insn)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, tmpreg, + gen_rtx_PLUS (Pmode, basereg, delta))); } else { @@ -3917,10 +3924,8 @@ { rtx mem = gen_rtx_MEM (DFmode, plus_constant (base, offset)); - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, mem, reg), - REG_NOTES (insn)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, mem, reg)); } else { @@ -3937,10 +3942,8 @@ RTX_FRAME_RELATED_P (setl) = 1; RTX_FRAME_RELATED_P (setr) = 1; vec = gen_rtvec (2, setl, setr); - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, - gen_rtx_SEQUENCE (VOIDmode, vec), - REG_NOTES (insn)); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SEQUENCE (VOIDmode, vec)); } } offset += GET_MODE_SIZE (DFmode); @@ -4358,8 +4361,7 @@ /* Indicate the _mcount call cannot throw, nor will it execute a non-local goto. */ - REG_NOTES (call_insn) - = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx, REG_NOTES (call_insn)); + make_reg_eh_region_note_nothrow_nononlocal (call_insn); } /* Fetch the return address for the frame COUNT steps up from @@ -4396,6 +4398,19 @@ rtx saved_rp; rtx ins; + /* Instruction stream at the normal return address for the export stub: + + 0x4bc23fd1 | stub+8: ldw -18(sr0,sp),rp + 0x004010a1 | stub+12: ldsid (sr0,rp),r1 + 0x00011820 | stub+16: mtsp r1,sr0 + 0xe0400002 | stub+20: be,n 0(sr0,rp) + + 0xe0400002 must be specified as -532676606 so that it won't be + rejected as an invalid immediate operand on 64-bit hosts. */ + + HOST_WIDE_INT insns[4] = {0x4bc23fd1, 0x004010a1, 0x00011820, -532676606}; + int i; + if (count != 0) return NULL_RTX; @@ -4404,6 +4419,9 @@ if (TARGET_64BIT || TARGET_NO_SPACE_REGS) return rp; + /* If there is no export stub then just use the value saved from + the return pointer register. */ + saved_rp = gen_reg_rtx (Pmode); emit_move_insn (saved_rp, rp); @@ -4415,37 +4433,15 @@ label = gen_label_rtx (); /* Check the instruction stream at the normal return address for the - export stub: - - 0x4bc23fd1 | stub+8: ldw -18(sr0,sp),rp - 0x004010a1 | stub+12: ldsid (sr0,rp),r1 - 0x00011820 | stub+16: mtsp r1,sr0 - 0xe0400002 | stub+20: be,n 0(sr0,rp) - - If it is an export stub, than our return address is really in - -24[frameaddr]. */ - - emit_cmp_insn (gen_rtx_MEM (SImode, ins), GEN_INT (0x4bc23fd1), NE, - NULL_RTX, SImode, 1); - emit_jump_insn (gen_bne (label)); - - emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 4)), - GEN_INT (0x004010a1), NE, NULL_RTX, SImode, 1); - emit_jump_insn (gen_bne (label)); - - emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 8)), - GEN_INT (0x00011820), NE, NULL_RTX, SImode, 1); - emit_jump_insn (gen_bne (label)); - - /* 0xe0400002 must be specified as -532676606 so that it won't be - rejected as an invalid immediate operand on 64-bit hosts. */ - emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 12)), - GEN_INT (-532676606), NE, NULL_RTX, SImode, 1); - - /* If there is no export stub then just use the value saved from - the return pointer register. */ - - emit_jump_insn (gen_bne (label)); + export stub. If it is an export stub, than our return address is + really in -24[frameaddr]. */ + + for (i = 0; i < 3; i++) + { + rtx op0 = gen_rtx_MEM (SImode, plus_constant (ins, i * 4)); + rtx op1 = GEN_INT (insns[i]); + emit_cmp_and_jump_insns (op0, op1, NE, NULL, SImode, 0, label); + } /* Here we know that our return address points to an export stub. We don't want to return the address of the export stub, @@ -4459,30 +4455,32 @@ -24)))); emit_label (label); + return saved_rp; } void -emit_bcond_fp (enum rtx_code code, rtx operand0) -{ +emit_bcond_fp (rtx operands[]) +{ + enum rtx_code code = GET_CODE (operands[0]); + rtx operand0 = operands[1]; + rtx operand1 = operands[2]; + rtx label = operands[3]; + + emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CCFPmode, 0), + gen_rtx_fmt_ee (code, CCFPmode, operand0, operand1))); + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, - gen_rtx_fmt_ee (code, + gen_rtx_fmt_ee (NE, VOIDmode, gen_rtx_REG (CCFPmode, 0), const0_rtx), - gen_rtx_LABEL_REF (VOIDmode, operand0), + gen_rtx_LABEL_REF (VOIDmode, label), pc_rtx))); } -rtx -gen_cmp_fp (enum rtx_code code, rtx operand0, rtx operand1) -{ - return gen_rtx_SET (VOIDmode, gen_rtx_REG (CCFPmode, 0), - gen_rtx_fmt_ee (code, CCFPmode, operand0, operand1)); -} - /* 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. */ @@ -4776,6 +4774,7 @@ /* Adjust a short backwards conditional with an unfilled delay slot. */ if (GET_CODE (pat) == SET && length == 4 + && JUMP_LABEL (insn) != NULL_RTX && ! forward_branch_p (insn)) return 4; else if (GET_CODE (pat) == PARALLEL @@ -5809,9 +5808,10 @@ break; case CONST: op = XEXP (x, 0); - is_symbolic = (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF - && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0))) - || GET_CODE (XEXP (op, 0)) == LABEL_REF) + is_symbolic = (GET_CODE (op) == PLUS + && ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF + && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0))) + || GET_CODE (XEXP (op, 0)) == LABEL_REF) && GET_CODE (XEXP (op, 1)) == CONST_INT); break; default: @@ -6111,6 +6111,38 @@ } } +/* Return TRUE if INSN, a jump insn, has an unfilled delay slot and + it branches to the next real instruction. Otherwise, return FALSE. */ + +static bool +branch_to_delay_slot_p (rtx insn) +{ + if (dbr_sequence_length ()) + return FALSE; + + return next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn); +} + +/* Return TRUE if INSN, a jump insn, needs a nop in its delay slot. + + This occurs when INSN has an unfilled delay slot and is followed + by an ASM_INPUT. Disaster can occur if the ASM_INPUT is empty and + the jump branches into the delay slot. So, we add a nop in the delay + slot just to be safe. This messes up our instruction count, but we + don't know how big the ASM_INPUT insn is anyway. */ + +static bool +branch_needs_nop_p (rtx insn) +{ + rtx next_insn; + + if (dbr_sequence_length ()) + return FALSE; + + next_insn = next_real_insn (insn); + return GET_CODE (PATTERN (next_insn)) == ASM_INPUT; +} + /* This routine handles all the normal conditional branch sequences we might need to generate. It handles compare immediate vs compare register, nullification of delay slots, varying length branches, @@ -6136,7 +6168,7 @@ slot and the same branch target as this branch. We could check for this but jump optimization should eliminate nop jumps. It is always safe to emit a nop. */ - if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) + if (branch_to_delay_slot_p (insn)) return "nop"; /* The doubleword form of the cmpib instruction doesn't have the LEU @@ -6185,7 +6217,12 @@ if (useskip) strcat (buf, " %2,%r1,%%r0"); else if (nullify) - strcat (buf, ",n %2,%r1,%0"); + { + if (branch_needs_nop_p (insn)) + strcat (buf, ",n %2,%r1,%0%#"); + else + strcat (buf, ",n %2,%r1,%0"); + } else strcat (buf, " %2,%r1,%0"); break; @@ -6458,7 +6495,7 @@ is only used when optimizing; jump optimization should eliminate the jump. But be prepared just in case. */ - if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) + if (branch_to_delay_slot_p (insn)) return "nop"; /* If this is a long branch with its delay slot unfilled, set `nullify' @@ -6504,11 +6541,21 @@ if (useskip) strcat (buf, " %0,%1,1,%%r0"); else if (nullify && negated) - strcat (buf, ",n %0,%1,%3"); + { + if (branch_needs_nop_p (insn)) + strcat (buf, ",n %0,%1,%3%#"); + else + strcat (buf, ",n %0,%1,%3"); + } else if (nullify && ! negated) - strcat (buf, ",n %0,%1,%2"); + { + if (branch_needs_nop_p (insn)) + strcat (buf, ",n %0,%1,%2%#"); + else + strcat (buf, ",n %0,%1,%2"); + } else if (! nullify && negated) - strcat (buf, "%0,%1,%3"); + strcat (buf, " %0,%1,%3"); else if (! nullify && ! negated) strcat (buf, " %0,%1,%2"); break; @@ -6639,7 +6686,7 @@ is only used when optimizing; jump optimization should eliminate the jump. But be prepared just in case. */ - if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) + if (branch_to_delay_slot_p (insn)) return "nop"; /* If this is a long branch with its delay slot unfilled, set `nullify' @@ -6685,11 +6732,21 @@ if (useskip) strcat (buf, "{ %0,1,%%r0| %0,%%sar,1,%%r0}"); else if (nullify && negated) - strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}"); + { + if (branch_needs_nop_p (insn)) + strcat (buf, "{,n %0,%3%#|,n %0,%%sar,%3%#}"); + else + strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}"); + } else if (nullify && ! negated) - strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}"); + { + if (branch_needs_nop_p (insn)) + strcat (buf, "{,n %0,%2%#|,n %0,%%sar,%2%#}"); + else + strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}"); + } else if (! nullify && negated) - strcat (buf, "{%0,%3|%0,%%sar,%3}"); + strcat (buf, "{ %0,%3| %0,%%sar,%3}"); else if (! nullify && ! negated) strcat (buf, "{ %0,%2| %0,%%sar,%2}"); break; @@ -6811,7 +6868,7 @@ /* A conditional branch to the following instruction (e.g. the delay slot) is asking for a disaster. Be prepared! */ - if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) + if (branch_to_delay_slot_p (insn)) { if (which_alternative == 0) return "ldo %1(%0),%0"; @@ -6848,7 +6905,12 @@ { case 4: if (nullify) - return "addib,%C2,n %1,%0,%3"; + { + if (branch_needs_nop_p (insn)) + return "addib,%C2,n %1,%0,%3%#"; + else + return "addib,%C2,n %1,%0,%3"; + } else return "addib,%C2 %1,%0,%3"; @@ -6956,7 +7018,7 @@ /* A conditional branch to the following instruction (e.g. the delay slot) is asking for a disaster. Be prepared! */ - if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) + if (branch_to_delay_slot_p (insn)) { if (which_alternative == 0) return "copy %1,%0"; @@ -6994,7 +7056,12 @@ { case 4: if (nullify) - return "movb,%C2,n %1,%0,%3"; + { + if (branch_needs_nop_p (insn)) + return "movb,%C2,n %1,%0,%3%#"; + else + return "movb,%C2,n %1,%0,%3"; + } else return "movb,%C2 %1,%0,%3"; @@ -7726,12 +7793,15 @@ if (!delay_slot_filled && INSN_ADDRESSES_SET_P ()) { /* See if the return address can be adjusted. Use the containing - sequence insn's address. */ + sequence insn's address. This would break the regular call/return@ + relationship assumed by the table based eh unwinder, so only do that + if the call is not possibly throwing. */ rtx seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0))); int distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn)))) - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8); - if (VAL_14_BITS_P (distance)) + if (VAL_14_BITS_P (distance) + && !(can_throw_internal (insn) || can_throw_external (insn))) { xoperands[1] = gen_label_rtx (); output_asm_insn ("ldo %0-%1(%%r2),%%r2", xoperands); @@ -8533,22 +8603,28 @@ return ! (GET_CODE (op) == REG && REGNO (op) < FIRST_PSEUDO_REGISTER); } -/* Return 1 if INSN branches forward. Should be using insn_addresses - to avoid walking through all the insns... */ -static int +/* Return TRUE if INSN branches forward. */ + +static bool forward_branch_p (rtx insn) { - rtx label = JUMP_LABEL (insn); + rtx lab = JUMP_LABEL (insn); + + /* The INSN must have a jump label. */ + gcc_assert (lab != NULL_RTX); + + if (INSN_ADDRESSES_SET_P ()) + return INSN_ADDRESSES (INSN_UID (lab)) > INSN_ADDRESSES (INSN_UID (insn)); while (insn) { - if (insn == label) - break; + if (insn == lab) + return true; else insn = NEXT_INSN (insn); } - return (insn == label); + return false; } /* Return 1 if OP is an equality comparison, else return 0. */ @@ -9130,17 +9206,33 @@ && get_attr_type (insn) == TYPE_MILLI)); } +/* Promote the return value, but not the arguments. */ + +static enum machine_mode +pa_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, + enum machine_mode mode, + int *punsignedp ATTRIBUTE_UNUSED, + const_tree fntype ATTRIBUTE_UNUSED, + int for_return) +{ + if (for_return == 0) + return mode; + return promote_mode (type, mode, punsignedp); +} + /* On the HP-PA the value is found in register(s) 28(-29), unless the mode is SF or DF. Then the value is returned in fr4 (32). - This must perform the same promotions as PROMOTE_MODE, else - TARGET_PROMOTE_FUNCTION_RETURN will not work correctly. + This must perform the same promotions as PROMOTE_MODE, else promoting + return values in TARGET_PROMOTE_FUNCTION_MODE will not work correctly. Small structures must be returned in a PARALLEL on PA64 in order to match the HP Compiler ABI. */ rtx -function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) +pa_function_value (const_tree valtype, + const_tree func ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) { enum machine_mode valmode; @@ -9619,7 +9711,7 @@ at the end of the file if and only if SYMBOL_REF_REFERENCED_P is true. This avoids putting out names that are never really used. */ -typedef struct extern_symbol GTY(()) +typedef struct GTY(()) extern_symbol { tree decl; const char *name; @@ -9733,4 +9825,174 @@ return true; } + +/* Length in units of the trampoline instruction code. */ + +#define TRAMPOLINE_CODE_SIZE (TARGET_64BIT ? 24 : (TARGET_PA_20 ? 32 : 40)) + + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts.\ + + The trampoline sets the static chain pointer to STATIC_CHAIN_REGNUM + and then branches to the specified routine. + + This code template is copied from text segment to stack location + and then patched with pa_trampoline_init to contain valid values, + and then entered as a subroutine. + + It is best to keep this as small as possible to avoid having to + flush multiple lines in the cache. */ + +static void +pa_asm_trampoline_template (FILE *f) +{ + if (!TARGET_64BIT) + { + fputs ("\tldw 36(%r22),%r21\n", f); + fputs ("\tbb,>=,n %r21,30,.+16\n", f); + if (ASSEMBLER_DIALECT == 0) + fputs ("\tdepi 0,31,2,%r21\n", f); + else + fputs ("\tdepwi 0,31,2,%r21\n", f); + fputs ("\tldw 4(%r21),%r19\n", f); + fputs ("\tldw 0(%r21),%r21\n", f); + if (TARGET_PA_20) + { + fputs ("\tbve (%r21)\n", f); + fputs ("\tldw 40(%r22),%r29\n", f); + fputs ("\t.word 0\n", f); + fputs ("\t.word 0\n", f); + } + else + { + fputs ("\tldsid (%r21),%r1\n", f); + fputs ("\tmtsp %r1,%sr0\n", f); + fputs ("\tbe 0(%sr0,%r21)\n", f); + fputs ("\tldw 40(%r22),%r29\n", f); + } + fputs ("\t.word 0\n", f); + fputs ("\t.word 0\n", f); + fputs ("\t.word 0\n", f); + fputs ("\t.word 0\n", f); + } + else + { + fputs ("\t.dword 0\n", f); + fputs ("\t.dword 0\n", f); + fputs ("\t.dword 0\n", f); + fputs ("\t.dword 0\n", f); + fputs ("\tmfia %r31\n", f); + fputs ("\tldd 24(%r31),%r1\n", f); + fputs ("\tldd 24(%r1),%r27\n", f); + fputs ("\tldd 16(%r1),%r1\n", f); + fputs ("\tbve (%r1)\n", f); + fputs ("\tldd 32(%r31),%r31\n", f); + fputs ("\t.dword 0 ; fptr\n", f); + fputs ("\t.dword 0 ; static link\n", f); + } +} + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. + + Move the function address to the trampoline template at offset 36. + Move the static chain value to trampoline template at offset 40. + Move the trampoline address to trampoline template at offset 44. + Move r19 to trampoline template at offset 48. The latter two + words create a plabel for the indirect call to the trampoline. + + A similar sequence is used for the 64-bit port but the plabel is + at the beginning of the trampoline. + + Finally, the cache entries for the trampoline code are flushed. + This is necessary to ensure that the trampoline instruction sequence + is written to memory prior to any attempts at prefetching the code + sequence. */ + +static void +pa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) +{ + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + rtx start_addr = gen_reg_rtx (Pmode); + rtx end_addr = gen_reg_rtx (Pmode); + rtx line_length = gen_reg_rtx (Pmode); + rtx r_tramp, tmp; + + emit_block_move (m_tramp, assemble_trampoline_template (), + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); + r_tramp = force_reg (Pmode, XEXP (m_tramp, 0)); + + if (!TARGET_64BIT) + { + tmp = adjust_address (m_tramp, Pmode, 36); + emit_move_insn (tmp, fnaddr); + tmp = adjust_address (m_tramp, Pmode, 40); + emit_move_insn (tmp, chain_value); + + /* Create a fat pointer for the trampoline. */ + tmp = adjust_address (m_tramp, Pmode, 44); + emit_move_insn (tmp, r_tramp); + tmp = adjust_address (m_tramp, Pmode, 48); + emit_move_insn (tmp, gen_rtx_REG (Pmode, 19)); + + /* fdc and fic only use registers for the address to flush, + they do not accept integer displacements. We align the + start and end addresses to the beginning of their respective + cache lines to minimize the number of lines flushed. */ + emit_insn (gen_andsi3 (start_addr, r_tramp, + GEN_INT (-MIN_CACHELINE_SIZE))); + tmp = force_reg (Pmode, plus_constant (r_tramp, TRAMPOLINE_CODE_SIZE-1)); + emit_insn (gen_andsi3 (end_addr, tmp, + GEN_INT (-MIN_CACHELINE_SIZE))); + emit_move_insn (line_length, GEN_INT (MIN_CACHELINE_SIZE)); + emit_insn (gen_dcacheflushsi (start_addr, end_addr, line_length)); + emit_insn (gen_icacheflushsi (start_addr, end_addr, line_length, + gen_reg_rtx (Pmode), + gen_reg_rtx (Pmode))); + } + else + { + tmp = adjust_address (m_tramp, Pmode, 56); + emit_move_insn (tmp, fnaddr); + tmp = adjust_address (m_tramp, Pmode, 64); + emit_move_insn (tmp, chain_value); + + /* Create a fat pointer for the trampoline. */ + tmp = adjust_address (m_tramp, Pmode, 16); + emit_move_insn (tmp, force_reg (Pmode, plus_constant (r_tramp, 32))); + tmp = adjust_address (m_tramp, Pmode, 24); + emit_move_insn (tmp, gen_rtx_REG (Pmode, 27)); + + /* fdc and fic only use registers for the address to flush, + they do not accept integer displacements. We align the + start and end addresses to the beginning of their respective + cache lines to minimize the number of lines flushed. */ + tmp = force_reg (Pmode, plus_constant (r_tramp, 32)); + emit_insn (gen_anddi3 (start_addr, tmp, + GEN_INT (-MIN_CACHELINE_SIZE))); + tmp = force_reg (Pmode, plus_constant (tmp, TRAMPOLINE_CODE_SIZE - 1)); + emit_insn (gen_anddi3 (end_addr, tmp, + GEN_INT (-MIN_CACHELINE_SIZE))); + emit_move_insn (line_length, GEN_INT (MIN_CACHELINE_SIZE)); + emit_insn (gen_dcacheflushdi (start_addr, end_addr, line_length)); + emit_insn (gen_icacheflushdi (start_addr, end_addr, line_length, + gen_reg_rtx (Pmode), + gen_reg_rtx (Pmode))); + } +} + +/* Perform any machine-specific adjustment in the address of the trampoline. + ADDR contains the address that was passed to pa_trampoline_init. + Adjust the trampoline address to point to the plabel at offset 44. */ + +static rtx +pa_trampoline_adjust_address (rtx addr) +{ + if (!TARGET_64BIT) + addr = memory_address (Pmode, plus_constant (addr, 46)); + return addr; +} + #include "gt-pa.h"