Mercurial > hg > CbC > CbC_gcc
comparison 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 |
comparison
equal
deleted
inserted
replaced
52:c156f1bd5cd9 | 55:77e2b8dfacca |
---|---|
91 static bool hppa_rtx_costs (rtx, int, int, int *, bool); | 91 static bool hppa_rtx_costs (rtx, int, int, int *, bool); |
92 static inline rtx force_mode (enum machine_mode, rtx); | 92 static inline rtx force_mode (enum machine_mode, rtx); |
93 static void pa_reorg (void); | 93 static void pa_reorg (void); |
94 static void pa_combine_instructions (void); | 94 static void pa_combine_instructions (void); |
95 static int pa_can_combine_p (rtx, rtx, rtx, int, rtx, rtx, rtx); | 95 static int pa_can_combine_p (rtx, rtx, rtx, int, rtx, rtx, rtx); |
96 static int forward_branch_p (rtx); | 96 static bool forward_branch_p (rtx); |
97 static void compute_zdepwi_operands (unsigned HOST_WIDE_INT, unsigned *); | 97 static void compute_zdepwi_operands (unsigned HOST_WIDE_INT, unsigned *); |
98 static int compute_movmem_length (rtx); | 98 static int compute_movmem_length (rtx); |
99 static int compute_clrmem_length (rtx); | 99 static int compute_clrmem_length (rtx); |
100 static bool pa_assemble_integer (rtx, unsigned int, int); | 100 static bool pa_assemble_integer (rtx, unsigned int, int); |
101 static void remove_useless_addtr_insns (int); | 101 static void remove_useless_addtr_insns (int); |
102 static void store_reg (int, HOST_WIDE_INT, int); | 102 static void store_reg (int, HOST_WIDE_INT, int); |
103 static void store_reg_modify (int, int, HOST_WIDE_INT); | 103 static void store_reg_modify (int, int, HOST_WIDE_INT); |
104 static void load_reg (int, HOST_WIDE_INT, int); | 104 static void load_reg (int, HOST_WIDE_INT, int); |
105 static void set_reg_plus_d (int, int, HOST_WIDE_INT, int); | 105 static void set_reg_plus_d (int, int, HOST_WIDE_INT, int); |
106 static rtx pa_function_value (const_tree, const_tree, bool); | |
106 static void pa_output_function_prologue (FILE *, HOST_WIDE_INT); | 107 static void pa_output_function_prologue (FILE *, HOST_WIDE_INT); |
107 static void update_total_code_bytes (unsigned int); | 108 static void update_total_code_bytes (unsigned int); |
108 static void pa_output_function_epilogue (FILE *, HOST_WIDE_INT); | 109 static void pa_output_function_epilogue (FILE *, HOST_WIDE_INT); |
109 static int pa_adjust_cost (rtx, rtx, rtx, int); | 110 static int pa_adjust_cost (rtx, rtx, rtx, int); |
110 static int pa_adjust_priority (rtx, int); | 111 static int pa_adjust_priority (rtx, int); |
129 static tree hppa_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); | 130 static tree hppa_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); |
130 static bool pa_scalar_mode_supported_p (enum machine_mode); | 131 static bool pa_scalar_mode_supported_p (enum machine_mode); |
131 static bool pa_commutative_p (const_rtx x, int outer_code); | 132 static bool pa_commutative_p (const_rtx x, int outer_code); |
132 static void copy_fp_args (rtx) ATTRIBUTE_UNUSED; | 133 static void copy_fp_args (rtx) ATTRIBUTE_UNUSED; |
133 static int length_fp_args (rtx) ATTRIBUTE_UNUSED; | 134 static int length_fp_args (rtx) ATTRIBUTE_UNUSED; |
135 static rtx hppa_legitimize_address (rtx, rtx, enum machine_mode); | |
134 static inline void pa_file_start_level (void) ATTRIBUTE_UNUSED; | 136 static inline void pa_file_start_level (void) ATTRIBUTE_UNUSED; |
135 static inline void pa_file_start_space (int) ATTRIBUTE_UNUSED; | 137 static inline void pa_file_start_space (int) ATTRIBUTE_UNUSED; |
136 static inline void pa_file_start_file (int) ATTRIBUTE_UNUSED; | 138 static inline void pa_file_start_file (int) ATTRIBUTE_UNUSED; |
137 static inline void pa_file_start_mcount (const char*) ATTRIBUTE_UNUSED; | 139 static inline void pa_file_start_mcount (const char*) ATTRIBUTE_UNUSED; |
138 static void pa_elf_file_start (void) ATTRIBUTE_UNUSED; | 140 static void pa_elf_file_start (void) ATTRIBUTE_UNUSED; |
156 static struct machine_function * pa_init_machine_status (void); | 158 static struct machine_function * pa_init_machine_status (void); |
157 static enum reg_class pa_secondary_reload (bool, rtx, enum reg_class, | 159 static enum reg_class pa_secondary_reload (bool, rtx, enum reg_class, |
158 enum machine_mode, | 160 enum machine_mode, |
159 secondary_reload_info *); | 161 secondary_reload_info *); |
160 static void pa_extra_live_on_entry (bitmap); | 162 static void pa_extra_live_on_entry (bitmap); |
163 static enum machine_mode pa_promote_function_mode (const_tree, | |
164 enum machine_mode, int *, | |
165 const_tree, int); | |
166 | |
167 static void pa_asm_trampoline_template (FILE *); | |
168 static void pa_trampoline_init (rtx, tree, rtx); | |
169 static rtx pa_trampoline_adjust_address (rtx); | |
161 | 170 |
162 /* The following extra sections are only used for SOM. */ | 171 /* The following extra sections are only used for SOM. */ |
163 static GTY(()) section *som_readonly_data_section; | 172 static GTY(()) section *som_readonly_data_section; |
164 static GTY(()) section *som_one_only_readonly_data_section; | 173 static GTY(()) section *som_one_only_readonly_data_section; |
165 static GTY(()) section *som_one_only_data_section; | 174 static GTY(()) section *som_one_only_data_section; |
166 | 175 |
167 /* Save the operands last given to a compare for use when we | |
168 generate a scc or bcc insn. */ | |
169 rtx hppa_compare_op0, hppa_compare_op1; | |
170 enum cmp_type hppa_branch_type; | |
171 | |
172 /* Which cpu we are scheduling for. */ | 176 /* Which cpu we are scheduling for. */ |
173 enum processor_type pa_cpu = TARGET_SCHED_DEFAULT; | 177 enum processor_type pa_cpu = TARGET_SCHED_DEFAULT; |
174 | 178 |
175 /* The UNIX standard to use for predefines and linking. */ | 179 /* The UNIX standard to use for predefines and linking. */ |
176 int flag_pa_unix = TARGET_HPUX_11_11 ? 1998 : TARGET_HPUX_10_10 ? 1995 : 1993; | 180 int flag_pa_unix = TARGET_HPUX_11_11 ? 1998 : TARGET_HPUX_10_10 ? 1995 : 1993; |
194 a thunk can use an IA-relative branch to reach its target function. */ | 198 a thunk can use an IA-relative branch to reach its target function. */ |
195 static unsigned int last_address; | 199 static unsigned int last_address; |
196 | 200 |
197 /* Variables to handle plabels that we discover are necessary at assembly | 201 /* Variables to handle plabels that we discover are necessary at assembly |
198 output time. They are output after the current function. */ | 202 output time. They are output after the current function. */ |
199 struct deferred_plabel GTY(()) | 203 struct GTY(()) deferred_plabel |
200 { | 204 { |
201 rtx internal_label; | 205 rtx internal_label; |
202 rtx symbol; | 206 rtx symbol; |
203 }; | 207 }; |
204 static GTY((length ("n_deferred_plabels"))) struct deferred_plabel * | 208 static GTY((length ("n_deferred_plabels"))) struct deferred_plabel * |
226 #undef TARGET_ASM_FUNCTION_PROLOGUE | 230 #undef TARGET_ASM_FUNCTION_PROLOGUE |
227 #define TARGET_ASM_FUNCTION_PROLOGUE pa_output_function_prologue | 231 #define TARGET_ASM_FUNCTION_PROLOGUE pa_output_function_prologue |
228 #undef TARGET_ASM_FUNCTION_EPILOGUE | 232 #undef TARGET_ASM_FUNCTION_EPILOGUE |
229 #define TARGET_ASM_FUNCTION_EPILOGUE pa_output_function_epilogue | 233 #define TARGET_ASM_FUNCTION_EPILOGUE pa_output_function_epilogue |
230 | 234 |
235 #undef TARGET_FUNCTION_VALUE | |
236 #define TARGET_FUNCTION_VALUE pa_function_value | |
237 | |
238 #undef TARGET_LEGITIMIZE_ADDRESS | |
239 #define TARGET_LEGITIMIZE_ADDRESS hppa_legitimize_address | |
240 | |
231 #undef TARGET_SCHED_ADJUST_COST | 241 #undef TARGET_SCHED_ADJUST_COST |
232 #define TARGET_SCHED_ADJUST_COST pa_adjust_cost | 242 #define TARGET_SCHED_ADJUST_COST pa_adjust_cost |
233 #undef TARGET_SCHED_ADJUST_PRIORITY | 243 #undef TARGET_SCHED_ADJUST_PRIORITY |
234 #define TARGET_SCHED_ADJUST_PRIORITY pa_adjust_priority | 244 #define TARGET_SCHED_ADJUST_PRIORITY pa_adjust_priority |
235 #undef TARGET_SCHED_ISSUE_RATE | 245 #undef TARGET_SCHED_ISSUE_RATE |
284 #ifdef HPUX_LONG_DOUBLE_LIBRARY | 294 #ifdef HPUX_LONG_DOUBLE_LIBRARY |
285 #undef TARGET_INIT_LIBFUNCS | 295 #undef TARGET_INIT_LIBFUNCS |
286 #define TARGET_INIT_LIBFUNCS pa_hpux_init_libfuncs | 296 #define TARGET_INIT_LIBFUNCS pa_hpux_init_libfuncs |
287 #endif | 297 #endif |
288 | 298 |
289 #undef TARGET_PROMOTE_FUNCTION_RETURN | 299 #undef TARGET_PROMOTE_FUNCTION_MODE |
290 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true | 300 #define TARGET_PROMOTE_FUNCTION_MODE pa_promote_function_mode |
291 #undef TARGET_PROMOTE_PROTOTYPES | 301 #undef TARGET_PROMOTE_PROTOTYPES |
292 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true | 302 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true |
293 | 303 |
294 #undef TARGET_STRUCT_VALUE_RTX | 304 #undef TARGET_STRUCT_VALUE_RTX |
295 #define TARGET_STRUCT_VALUE_RTX pa_struct_value_rtx | 305 #define TARGET_STRUCT_VALUE_RTX pa_struct_value_rtx |
320 #undef TARGET_SECONDARY_RELOAD | 330 #undef TARGET_SECONDARY_RELOAD |
321 #define TARGET_SECONDARY_RELOAD pa_secondary_reload | 331 #define TARGET_SECONDARY_RELOAD pa_secondary_reload |
322 | 332 |
323 #undef TARGET_EXTRA_LIVE_ON_ENTRY | 333 #undef TARGET_EXTRA_LIVE_ON_ENTRY |
324 #define TARGET_EXTRA_LIVE_ON_ENTRY pa_extra_live_on_entry | 334 #define TARGET_EXTRA_LIVE_ON_ENTRY pa_extra_live_on_entry |
335 | |
336 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE | |
337 #define TARGET_ASM_TRAMPOLINE_TEMPLATE pa_asm_trampoline_template | |
338 #undef TARGET_TRAMPOLINE_INIT | |
339 #define TARGET_TRAMPOLINE_INIT pa_trampoline_init | |
340 #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS | |
341 #define TARGET_TRAMPOLINE_ADJUST_ADDRESS pa_trampoline_adjust_address | |
325 | 342 |
326 struct gcc_target targetm = TARGET_INITIALIZER; | 343 struct gcc_target targetm = TARGET_INITIALIZER; |
327 | 344 |
328 /* Parse the -mfixed-range= option string. */ | 345 /* Parse the -mfixed-range= option string. */ |
329 | 346 |
682 expanders completely. */ | 699 expanders completely. */ |
683 mark_reg_pointer (reg, BITS_PER_UNIT); | 700 mark_reg_pointer (reg, BITS_PER_UNIT); |
684 insn = emit_insn (gen_rtx_SET (VOIDmode, reg, orig)); | 701 insn = emit_insn (gen_rtx_SET (VOIDmode, reg, orig)); |
685 | 702 |
686 /* Put a REG_EQUAL note on this insn, so that it can be optimized. */ | 703 /* Put a REG_EQUAL note on this insn, so that it can be optimized. */ |
687 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, REG_NOTES (insn)); | 704 add_reg_note (insn, REG_EQUAL, orig); |
688 | 705 |
689 /* During and after reload, we need to generate a REG_LABEL_OPERAND note | 706 /* During and after reload, we need to generate a REG_LABEL_OPERAND note |
690 and update LABEL_NUSES because this is not done automatically. */ | 707 and update LABEL_NUSES because this is not done automatically. */ |
691 if (reload_in_progress || reload_completed) | 708 if (reload_in_progress || reload_completed) |
692 { | 709 { |
869 to be legitimate. If we find one, return the new, valid address. | 886 to be legitimate. If we find one, return the new, valid address. |
870 This macro is used in only one place: `memory_address' in explow.c. | 887 This macro is used in only one place: `memory_address' in explow.c. |
871 | 888 |
872 OLDX is the address as it was before break_out_memory_refs was called. | 889 OLDX is the address as it was before break_out_memory_refs was called. |
873 In some cases it is useful to look at this to decide what needs to be done. | 890 In some cases it is useful to look at this to decide what needs to be done. |
874 | |
875 MODE and WIN are passed so that this macro can use | |
876 GO_IF_LEGITIMATE_ADDRESS. | |
877 | 891 |
878 It is always safe for this macro to do nothing. It exists to recognize | 892 It is always safe for this macro to do nothing. It exists to recognize |
879 opportunities to optimize the output. | 893 opportunities to optimize the output. |
880 | 894 |
881 For the PA, transform: | 895 For the PA, transform: |
3398 | 3412 |
3399 emit_move_insn (tmpreg, delta); | 3413 emit_move_insn (tmpreg, delta); |
3400 insn = emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg)); | 3414 insn = emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg)); |
3401 if (DO_FRAME_NOTES) | 3415 if (DO_FRAME_NOTES) |
3402 { | 3416 { |
3403 REG_NOTES (insn) | 3417 add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
3404 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | 3418 gen_rtx_SET (VOIDmode, tmpreg, |
3405 gen_rtx_SET (VOIDmode, tmpreg, | 3419 gen_rtx_PLUS (Pmode, basereg, delta))); |
3406 gen_rtx_PLUS (Pmode, basereg, delta)), | |
3407 REG_NOTES (insn)); | |
3408 RTX_FRAME_RELATED_P (insn) = 1; | 3420 RTX_FRAME_RELATED_P (insn) = 1; |
3409 } | 3421 } |
3410 dest = gen_rtx_MEM (word_mode, tmpreg); | 3422 dest = gen_rtx_MEM (word_mode, tmpreg); |
3411 insn = emit_move_insn (dest, src); | 3423 insn = emit_move_insn (dest, src); |
3412 } | 3424 } |
3418 | 3430 |
3419 emit_move_insn (tmpreg, high); | 3431 emit_move_insn (tmpreg, high); |
3420 dest = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta)); | 3432 dest = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta)); |
3421 insn = emit_move_insn (dest, src); | 3433 insn = emit_move_insn (dest, src); |
3422 if (DO_FRAME_NOTES) | 3434 if (DO_FRAME_NOTES) |
3423 { | 3435 add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
3424 REG_NOTES (insn) | 3436 gen_rtx_SET (VOIDmode, |
3425 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | 3437 gen_rtx_MEM (word_mode, |
3426 gen_rtx_SET (VOIDmode, | 3438 gen_rtx_PLUS (word_mode, |
3427 gen_rtx_MEM (word_mode, | 3439 basereg, |
3428 gen_rtx_PLUS (word_mode, basereg, | 3440 delta)), |
3429 delta)), | 3441 src)); |
3430 src), | |
3431 REG_NOTES (insn)); | |
3432 } | |
3433 } | 3442 } |
3434 | 3443 |
3435 if (DO_FRAME_NOTES) | 3444 if (DO_FRAME_NOTES) |
3436 RTX_FRAME_RELATED_P (insn) = 1; | 3445 RTX_FRAME_RELATED_P (insn) = 1; |
3437 } | 3446 } |
3487 | 3496 |
3488 emit_move_insn (tmpreg, delta); | 3497 emit_move_insn (tmpreg, delta); |
3489 insn = emit_move_insn (gen_rtx_REG (Pmode, reg), | 3498 insn = emit_move_insn (gen_rtx_REG (Pmode, reg), |
3490 gen_rtx_PLUS (Pmode, tmpreg, basereg)); | 3499 gen_rtx_PLUS (Pmode, tmpreg, basereg)); |
3491 if (DO_FRAME_NOTES) | 3500 if (DO_FRAME_NOTES) |
3492 REG_NOTES (insn) | 3501 add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
3493 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | 3502 gen_rtx_SET (VOIDmode, tmpreg, |
3494 gen_rtx_SET (VOIDmode, tmpreg, | 3503 gen_rtx_PLUS (Pmode, basereg, delta))); |
3495 gen_rtx_PLUS (Pmode, basereg, delta)), | |
3496 REG_NOTES (insn)); | |
3497 } | 3504 } |
3498 else | 3505 else |
3499 { | 3506 { |
3500 rtx basereg = gen_rtx_REG (Pmode, base); | 3507 rtx basereg = gen_rtx_REG (Pmode, base); |
3501 rtx delta = GEN_INT (disp); | 3508 rtx delta = GEN_INT (disp); |
3915 RTX_FRAME_RELATED_P (insn) = 1; | 3922 RTX_FRAME_RELATED_P (insn) = 1; |
3916 if (TARGET_64BIT) | 3923 if (TARGET_64BIT) |
3917 { | 3924 { |
3918 rtx mem = gen_rtx_MEM (DFmode, | 3925 rtx mem = gen_rtx_MEM (DFmode, |
3919 plus_constant (base, offset)); | 3926 plus_constant (base, offset)); |
3920 REG_NOTES (insn) | 3927 add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
3921 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | 3928 gen_rtx_SET (VOIDmode, mem, reg)); |
3922 gen_rtx_SET (VOIDmode, mem, reg), | |
3923 REG_NOTES (insn)); | |
3924 } | 3929 } |
3925 else | 3930 else |
3926 { | 3931 { |
3927 rtx meml = gen_rtx_MEM (SFmode, | 3932 rtx meml = gen_rtx_MEM (SFmode, |
3928 plus_constant (base, offset)); | 3933 plus_constant (base, offset)); |
3935 rtvec vec; | 3940 rtvec vec; |
3936 | 3941 |
3937 RTX_FRAME_RELATED_P (setl) = 1; | 3942 RTX_FRAME_RELATED_P (setl) = 1; |
3938 RTX_FRAME_RELATED_P (setr) = 1; | 3943 RTX_FRAME_RELATED_P (setr) = 1; |
3939 vec = gen_rtvec (2, setl, setr); | 3944 vec = gen_rtvec (2, setl, setr); |
3940 REG_NOTES (insn) | 3945 add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
3941 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | 3946 gen_rtx_SEQUENCE (VOIDmode, vec)); |
3942 gen_rtx_SEQUENCE (VOIDmode, vec), | |
3943 REG_NOTES (insn)); | |
3944 } | 3947 } |
3945 } | 3948 } |
3946 offset += GET_MODE_SIZE (DFmode); | 3949 offset += GET_MODE_SIZE (DFmode); |
3947 fr_saved++; | 3950 fr_saved++; |
3948 } | 3951 } |
4356 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), gen_rtx_REG (SImode, 25)); | 4359 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), gen_rtx_REG (SImode, 25)); |
4357 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), gen_rtx_REG (SImode, 26)); | 4360 use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), gen_rtx_REG (SImode, 26)); |
4358 | 4361 |
4359 /* Indicate the _mcount call cannot throw, nor will it execute a | 4362 /* Indicate the _mcount call cannot throw, nor will it execute a |
4360 non-local goto. */ | 4363 non-local goto. */ |
4361 REG_NOTES (call_insn) | 4364 make_reg_eh_region_note_nothrow_nononlocal (call_insn); |
4362 = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx, REG_NOTES (call_insn)); | |
4363 } | 4365 } |
4364 | 4366 |
4365 /* Fetch the return address for the frame COUNT steps up from | 4367 /* Fetch the return address for the frame COUNT steps up from |
4366 the current frame, after the prologue. FRAMEADDR is the | 4368 the current frame, after the prologue. FRAMEADDR is the |
4367 frame pointer of the COUNT frame. | 4369 frame pointer of the COUNT frame. |
4394 rtx label; | 4396 rtx label; |
4395 rtx rp; | 4397 rtx rp; |
4396 rtx saved_rp; | 4398 rtx saved_rp; |
4397 rtx ins; | 4399 rtx ins; |
4398 | 4400 |
4401 /* Instruction stream at the normal return address for the export stub: | |
4402 | |
4403 0x4bc23fd1 | stub+8: ldw -18(sr0,sp),rp | |
4404 0x004010a1 | stub+12: ldsid (sr0,rp),r1 | |
4405 0x00011820 | stub+16: mtsp r1,sr0 | |
4406 0xe0400002 | stub+20: be,n 0(sr0,rp) | |
4407 | |
4408 0xe0400002 must be specified as -532676606 so that it won't be | |
4409 rejected as an invalid immediate operand on 64-bit hosts. */ | |
4410 | |
4411 HOST_WIDE_INT insns[4] = {0x4bc23fd1, 0x004010a1, 0x00011820, -532676606}; | |
4412 int i; | |
4413 | |
4399 if (count != 0) | 4414 if (count != 0) |
4400 return NULL_RTX; | 4415 return NULL_RTX; |
4401 | 4416 |
4402 rp = get_hard_reg_initial_val (Pmode, 2); | 4417 rp = get_hard_reg_initial_val (Pmode, 2); |
4403 | 4418 |
4404 if (TARGET_64BIT || TARGET_NO_SPACE_REGS) | 4419 if (TARGET_64BIT || TARGET_NO_SPACE_REGS) |
4405 return rp; | 4420 return rp; |
4421 | |
4422 /* If there is no export stub then just use the value saved from | |
4423 the return pointer register. */ | |
4406 | 4424 |
4407 saved_rp = gen_reg_rtx (Pmode); | 4425 saved_rp = gen_reg_rtx (Pmode); |
4408 emit_move_insn (saved_rp, rp); | 4426 emit_move_insn (saved_rp, rp); |
4409 | 4427 |
4410 /* Get pointer to the instruction stream. We have to mask out the | 4428 /* Get pointer to the instruction stream. We have to mask out the |
4413 instruction that would have been executed if we returned. */ | 4431 instruction that would have been executed if we returned. */ |
4414 ins = copy_to_reg (gen_rtx_AND (Pmode, rp, MASK_RETURN_ADDR)); | 4432 ins = copy_to_reg (gen_rtx_AND (Pmode, rp, MASK_RETURN_ADDR)); |
4415 label = gen_label_rtx (); | 4433 label = gen_label_rtx (); |
4416 | 4434 |
4417 /* Check the instruction stream at the normal return address for the | 4435 /* Check the instruction stream at the normal return address for the |
4418 export stub: | 4436 export stub. If it is an export stub, than our return address is |
4419 | 4437 really in -24[frameaddr]. */ |
4420 0x4bc23fd1 | stub+8: ldw -18(sr0,sp),rp | 4438 |
4421 0x004010a1 | stub+12: ldsid (sr0,rp),r1 | 4439 for (i = 0; i < 3; i++) |
4422 0x00011820 | stub+16: mtsp r1,sr0 | 4440 { |
4423 0xe0400002 | stub+20: be,n 0(sr0,rp) | 4441 rtx op0 = gen_rtx_MEM (SImode, plus_constant (ins, i * 4)); |
4424 | 4442 rtx op1 = GEN_INT (insns[i]); |
4425 If it is an export stub, than our return address is really in | 4443 emit_cmp_and_jump_insns (op0, op1, NE, NULL, SImode, 0, label); |
4426 -24[frameaddr]. */ | 4444 } |
4427 | |
4428 emit_cmp_insn (gen_rtx_MEM (SImode, ins), GEN_INT (0x4bc23fd1), NE, | |
4429 NULL_RTX, SImode, 1); | |
4430 emit_jump_insn (gen_bne (label)); | |
4431 | |
4432 emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 4)), | |
4433 GEN_INT (0x004010a1), NE, NULL_RTX, SImode, 1); | |
4434 emit_jump_insn (gen_bne (label)); | |
4435 | |
4436 emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 8)), | |
4437 GEN_INT (0x00011820), NE, NULL_RTX, SImode, 1); | |
4438 emit_jump_insn (gen_bne (label)); | |
4439 | |
4440 /* 0xe0400002 must be specified as -532676606 so that it won't be | |
4441 rejected as an invalid immediate operand on 64-bit hosts. */ | |
4442 emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 12)), | |
4443 GEN_INT (-532676606), NE, NULL_RTX, SImode, 1); | |
4444 | |
4445 /* If there is no export stub then just use the value saved from | |
4446 the return pointer register. */ | |
4447 | |
4448 emit_jump_insn (gen_bne (label)); | |
4449 | 4445 |
4450 /* Here we know that our return address points to an export | 4446 /* Here we know that our return address points to an export |
4451 stub. We don't want to return the address of the export stub, | 4447 stub. We don't want to return the address of the export stub, |
4452 but rather the return address of the export stub. That return | 4448 but rather the return address of the export stub. That return |
4453 address is stored at -24[frameaddr]. */ | 4449 address is stored at -24[frameaddr]. */ |
4457 memory_address (Pmode, | 4453 memory_address (Pmode, |
4458 plus_constant (frameaddr, | 4454 plus_constant (frameaddr, |
4459 -24)))); | 4455 -24)))); |
4460 | 4456 |
4461 emit_label (label); | 4457 emit_label (label); |
4458 | |
4462 return saved_rp; | 4459 return saved_rp; |
4463 } | 4460 } |
4464 | 4461 |
4465 void | 4462 void |
4466 emit_bcond_fp (enum rtx_code code, rtx operand0) | 4463 emit_bcond_fp (rtx operands[]) |
4467 { | 4464 { |
4465 enum rtx_code code = GET_CODE (operands[0]); | |
4466 rtx operand0 = operands[1]; | |
4467 rtx operand1 = operands[2]; | |
4468 rtx label = operands[3]; | |
4469 | |
4470 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CCFPmode, 0), | |
4471 gen_rtx_fmt_ee (code, CCFPmode, operand0, operand1))); | |
4472 | |
4468 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, | 4473 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, |
4469 gen_rtx_IF_THEN_ELSE (VOIDmode, | 4474 gen_rtx_IF_THEN_ELSE (VOIDmode, |
4470 gen_rtx_fmt_ee (code, | 4475 gen_rtx_fmt_ee (NE, |
4471 VOIDmode, | 4476 VOIDmode, |
4472 gen_rtx_REG (CCFPmode, 0), | 4477 gen_rtx_REG (CCFPmode, 0), |
4473 const0_rtx), | 4478 const0_rtx), |
4474 gen_rtx_LABEL_REF (VOIDmode, operand0), | 4479 gen_rtx_LABEL_REF (VOIDmode, label), |
4475 pc_rtx))); | 4480 pc_rtx))); |
4476 | 4481 |
4477 } | |
4478 | |
4479 rtx | |
4480 gen_cmp_fp (enum rtx_code code, rtx operand0, rtx operand1) | |
4481 { | |
4482 return gen_rtx_SET (VOIDmode, gen_rtx_REG (CCFPmode, 0), | |
4483 gen_rtx_fmt_ee (code, CCFPmode, operand0, operand1)); | |
4484 } | 4482 } |
4485 | 4483 |
4486 /* Adjust the cost of a scheduling dependency. Return the new cost of | 4484 /* Adjust the cost of a scheduling dependency. Return the new cost of |
4487 a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ | 4485 a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ |
4488 | 4486 |
4774 else if (GET_CODE (insn) == JUMP_INSN && ! simplejump_p (insn)) | 4772 else if (GET_CODE (insn) == JUMP_INSN && ! simplejump_p (insn)) |
4775 { | 4773 { |
4776 /* Adjust a short backwards conditional with an unfilled delay slot. */ | 4774 /* Adjust a short backwards conditional with an unfilled delay slot. */ |
4777 if (GET_CODE (pat) == SET | 4775 if (GET_CODE (pat) == SET |
4778 && length == 4 | 4776 && length == 4 |
4777 && JUMP_LABEL (insn) != NULL_RTX | |
4779 && ! forward_branch_p (insn)) | 4778 && ! forward_branch_p (insn)) |
4780 return 4; | 4779 return 4; |
4781 else if (GET_CODE (pat) == PARALLEL | 4780 else if (GET_CODE (pat) == PARALLEL |
4782 && get_attr_type (insn) == TYPE_PARALLEL_BRANCH | 4781 && get_attr_type (insn) == TYPE_PARALLEL_BRANCH |
4783 && length == 4) | 4782 && length == 4) |
5807 case LABEL_REF: | 5806 case LABEL_REF: |
5808 is_symbolic = 1; | 5807 is_symbolic = 1; |
5809 break; | 5808 break; |
5810 case CONST: | 5809 case CONST: |
5811 op = XEXP (x, 0); | 5810 op = XEXP (x, 0); |
5812 is_symbolic = (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF | 5811 is_symbolic = (GET_CODE (op) == PLUS |
5813 && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0))) | 5812 && ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF |
5814 || GET_CODE (XEXP (op, 0)) == LABEL_REF) | 5813 && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0))) |
5814 || GET_CODE (XEXP (op, 0)) == LABEL_REF) | |
5815 && GET_CODE (XEXP (op, 1)) == CONST_INT); | 5815 && GET_CODE (XEXP (op, 1)) == CONST_INT); |
5816 break; | 5816 break; |
5817 default: | 5817 default: |
5818 is_symbolic = 0; | 5818 is_symbolic = 0; |
5819 break; | 5819 break; |
6109 default: | 6109 default: |
6110 gcc_unreachable (); | 6110 gcc_unreachable (); |
6111 } | 6111 } |
6112 } | 6112 } |
6113 | 6113 |
6114 /* Return TRUE if INSN, a jump insn, has an unfilled delay slot and | |
6115 it branches to the next real instruction. Otherwise, return FALSE. */ | |
6116 | |
6117 static bool | |
6118 branch_to_delay_slot_p (rtx insn) | |
6119 { | |
6120 if (dbr_sequence_length ()) | |
6121 return FALSE; | |
6122 | |
6123 return next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn); | |
6124 } | |
6125 | |
6126 /* Return TRUE if INSN, a jump insn, needs a nop in its delay slot. | |
6127 | |
6128 This occurs when INSN has an unfilled delay slot and is followed | |
6129 by an ASM_INPUT. Disaster can occur if the ASM_INPUT is empty and | |
6130 the jump branches into the delay slot. So, we add a nop in the delay | |
6131 slot just to be safe. This messes up our instruction count, but we | |
6132 don't know how big the ASM_INPUT insn is anyway. */ | |
6133 | |
6134 static bool | |
6135 branch_needs_nop_p (rtx insn) | |
6136 { | |
6137 rtx next_insn; | |
6138 | |
6139 if (dbr_sequence_length ()) | |
6140 return FALSE; | |
6141 | |
6142 next_insn = next_real_insn (insn); | |
6143 return GET_CODE (PATTERN (next_insn)) == ASM_INPUT; | |
6144 } | |
6145 | |
6114 /* This routine handles all the normal conditional branch sequences we | 6146 /* This routine handles all the normal conditional branch sequences we |
6115 might need to generate. It handles compare immediate vs compare | 6147 might need to generate. It handles compare immediate vs compare |
6116 register, nullification of delay slots, varying length branches, | 6148 register, nullification of delay slots, varying length branches, |
6117 negated branches, and all combinations of the above. It returns the | 6149 negated branches, and all combinations of the above. It returns the |
6118 output appropriate to emit the branch corresponding to all given | 6150 output appropriate to emit the branch corresponding to all given |
6134 While it is usually safe to emit nothing, this can fail if the | 6166 While it is usually safe to emit nothing, this can fail if the |
6135 preceding instruction is a nullified branch with an empty delay | 6167 preceding instruction is a nullified branch with an empty delay |
6136 slot and the same branch target as this branch. We could check | 6168 slot and the same branch target as this branch. We could check |
6137 for this but jump optimization should eliminate nop jumps. It | 6169 for this but jump optimization should eliminate nop jumps. It |
6138 is always safe to emit a nop. */ | 6170 is always safe to emit a nop. */ |
6139 if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) | 6171 if (branch_to_delay_slot_p (insn)) |
6140 return "nop"; | 6172 return "nop"; |
6141 | 6173 |
6142 /* The doubleword form of the cmpib instruction doesn't have the LEU | 6174 /* The doubleword form of the cmpib instruction doesn't have the LEU |
6143 and GTU conditions while the cmpb instruction does. Since we accept | 6175 and GTU conditions while the cmpb instruction does. Since we accept |
6144 zero for cmpb, we must ensure that we use cmpb for the comparison. */ | 6176 zero for cmpb, we must ensure that we use cmpb for the comparison. */ |
6183 else | 6215 else |
6184 strcat (buf, "%S3"); | 6216 strcat (buf, "%S3"); |
6185 if (useskip) | 6217 if (useskip) |
6186 strcat (buf, " %2,%r1,%%r0"); | 6218 strcat (buf, " %2,%r1,%%r0"); |
6187 else if (nullify) | 6219 else if (nullify) |
6188 strcat (buf, ",n %2,%r1,%0"); | 6220 { |
6221 if (branch_needs_nop_p (insn)) | |
6222 strcat (buf, ",n %2,%r1,%0%#"); | |
6223 else | |
6224 strcat (buf, ",n %2,%r1,%0"); | |
6225 } | |
6189 else | 6226 else |
6190 strcat (buf, " %2,%r1,%0"); | 6227 strcat (buf, " %2,%r1,%0"); |
6191 break; | 6228 break; |
6192 | 6229 |
6193 /* All long conditionals. Note a short backward branch with an | 6230 /* All long conditionals. Note a short backward branch with an |
6456 /* A conditional branch to the following instruction (e.g. the delay slot) is | 6493 /* A conditional branch to the following instruction (e.g. the delay slot) is |
6457 asking for a disaster. I do not think this can happen as this pattern | 6494 asking for a disaster. I do not think this can happen as this pattern |
6458 is only used when optimizing; jump optimization should eliminate the | 6495 is only used when optimizing; jump optimization should eliminate the |
6459 jump. But be prepared just in case. */ | 6496 jump. But be prepared just in case. */ |
6460 | 6497 |
6461 if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) | 6498 if (branch_to_delay_slot_p (insn)) |
6462 return "nop"; | 6499 return "nop"; |
6463 | 6500 |
6464 /* If this is a long branch with its delay slot unfilled, set `nullify' | 6501 /* If this is a long branch with its delay slot unfilled, set `nullify' |
6465 as it can nullify the delay slot and save a nop. */ | 6502 as it can nullify the delay slot and save a nop. */ |
6466 if (length == 8 && dbr_sequence_length () == 0) | 6503 if (length == 8 && dbr_sequence_length () == 0) |
6502 else | 6539 else |
6503 strcat (buf, "<"); | 6540 strcat (buf, "<"); |
6504 if (useskip) | 6541 if (useskip) |
6505 strcat (buf, " %0,%1,1,%%r0"); | 6542 strcat (buf, " %0,%1,1,%%r0"); |
6506 else if (nullify && negated) | 6543 else if (nullify && negated) |
6507 strcat (buf, ",n %0,%1,%3"); | 6544 { |
6545 if (branch_needs_nop_p (insn)) | |
6546 strcat (buf, ",n %0,%1,%3%#"); | |
6547 else | |
6548 strcat (buf, ",n %0,%1,%3"); | |
6549 } | |
6508 else if (nullify && ! negated) | 6550 else if (nullify && ! negated) |
6509 strcat (buf, ",n %0,%1,%2"); | 6551 { |
6552 if (branch_needs_nop_p (insn)) | |
6553 strcat (buf, ",n %0,%1,%2%#"); | |
6554 else | |
6555 strcat (buf, ",n %0,%1,%2"); | |
6556 } | |
6510 else if (! nullify && negated) | 6557 else if (! nullify && negated) |
6511 strcat (buf, "%0,%1,%3"); | 6558 strcat (buf, " %0,%1,%3"); |
6512 else if (! nullify && ! negated) | 6559 else if (! nullify && ! negated) |
6513 strcat (buf, " %0,%1,%2"); | 6560 strcat (buf, " %0,%1,%2"); |
6514 break; | 6561 break; |
6515 | 6562 |
6516 /* All long conditionals. Note a short backward branch with an | 6563 /* All long conditionals. Note a short backward branch with an |
6637 /* A conditional branch to the following instruction (e.g. the delay slot) is | 6684 /* A conditional branch to the following instruction (e.g. the delay slot) is |
6638 asking for a disaster. I do not think this can happen as this pattern | 6685 asking for a disaster. I do not think this can happen as this pattern |
6639 is only used when optimizing; jump optimization should eliminate the | 6686 is only used when optimizing; jump optimization should eliminate the |
6640 jump. But be prepared just in case. */ | 6687 jump. But be prepared just in case. */ |
6641 | 6688 |
6642 if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) | 6689 if (branch_to_delay_slot_p (insn)) |
6643 return "nop"; | 6690 return "nop"; |
6644 | 6691 |
6645 /* If this is a long branch with its delay slot unfilled, set `nullify' | 6692 /* If this is a long branch with its delay slot unfilled, set `nullify' |
6646 as it can nullify the delay slot and save a nop. */ | 6693 as it can nullify the delay slot and save a nop. */ |
6647 if (length == 8 && dbr_sequence_length () == 0) | 6694 if (length == 8 && dbr_sequence_length () == 0) |
6683 else | 6730 else |
6684 strcat (buf, "<"); | 6731 strcat (buf, "<"); |
6685 if (useskip) | 6732 if (useskip) |
6686 strcat (buf, "{ %0,1,%%r0| %0,%%sar,1,%%r0}"); | 6733 strcat (buf, "{ %0,1,%%r0| %0,%%sar,1,%%r0}"); |
6687 else if (nullify && negated) | 6734 else if (nullify && negated) |
6688 strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}"); | 6735 { |
6736 if (branch_needs_nop_p (insn)) | |
6737 strcat (buf, "{,n %0,%3%#|,n %0,%%sar,%3%#}"); | |
6738 else | |
6739 strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}"); | |
6740 } | |
6689 else if (nullify && ! negated) | 6741 else if (nullify && ! negated) |
6690 strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}"); | 6742 { |
6743 if (branch_needs_nop_p (insn)) | |
6744 strcat (buf, "{,n %0,%2%#|,n %0,%%sar,%2%#}"); | |
6745 else | |
6746 strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}"); | |
6747 } | |
6691 else if (! nullify && negated) | 6748 else if (! nullify && negated) |
6692 strcat (buf, "{%0,%3|%0,%%sar,%3}"); | 6749 strcat (buf, "{ %0,%3| %0,%%sar,%3}"); |
6693 else if (! nullify && ! negated) | 6750 else if (! nullify && ! negated) |
6694 strcat (buf, "{ %0,%2| %0,%%sar,%2}"); | 6751 strcat (buf, "{ %0,%2| %0,%%sar,%2}"); |
6695 break; | 6752 break; |
6696 | 6753 |
6697 /* All long conditionals. Note a short backward branch with an | 6754 /* All long conditionals. Note a short backward branch with an |
6809 int length = get_attr_length (insn); | 6866 int length = get_attr_length (insn); |
6810 | 6867 |
6811 /* A conditional branch to the following instruction (e.g. the delay slot) is | 6868 /* A conditional branch to the following instruction (e.g. the delay slot) is |
6812 asking for a disaster. Be prepared! */ | 6869 asking for a disaster. Be prepared! */ |
6813 | 6870 |
6814 if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) | 6871 if (branch_to_delay_slot_p (insn)) |
6815 { | 6872 { |
6816 if (which_alternative == 0) | 6873 if (which_alternative == 0) |
6817 return "ldo %1(%0),%0"; | 6874 return "ldo %1(%0),%0"; |
6818 else if (which_alternative == 1) | 6875 else if (which_alternative == 1) |
6819 { | 6876 { |
6846 | 6903 |
6847 switch (length) | 6904 switch (length) |
6848 { | 6905 { |
6849 case 4: | 6906 case 4: |
6850 if (nullify) | 6907 if (nullify) |
6851 return "addib,%C2,n %1,%0,%3"; | 6908 { |
6909 if (branch_needs_nop_p (insn)) | |
6910 return "addib,%C2,n %1,%0,%3%#"; | |
6911 else | |
6912 return "addib,%C2,n %1,%0,%3"; | |
6913 } | |
6852 else | 6914 else |
6853 return "addib,%C2 %1,%0,%3"; | 6915 return "addib,%C2 %1,%0,%3"; |
6854 | 6916 |
6855 case 8: | 6917 case 8: |
6856 /* Handle weird backwards branch with a fulled delay slot | 6918 /* Handle weird backwards branch with a fulled delay slot |
6954 int length = get_attr_length (insn); | 7016 int length = get_attr_length (insn); |
6955 | 7017 |
6956 /* A conditional branch to the following instruction (e.g. the delay slot) is | 7018 /* A conditional branch to the following instruction (e.g. the delay slot) is |
6957 asking for a disaster. Be prepared! */ | 7019 asking for a disaster. Be prepared! */ |
6958 | 7020 |
6959 if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn)) | 7021 if (branch_to_delay_slot_p (insn)) |
6960 { | 7022 { |
6961 if (which_alternative == 0) | 7023 if (which_alternative == 0) |
6962 return "copy %1,%0"; | 7024 return "copy %1,%0"; |
6963 else if (which_alternative == 1) | 7025 else if (which_alternative == 1) |
6964 { | 7026 { |
6992 | 7054 |
6993 switch (length) | 7055 switch (length) |
6994 { | 7056 { |
6995 case 4: | 7057 case 4: |
6996 if (nullify) | 7058 if (nullify) |
6997 return "movb,%C2,n %1,%0,%3"; | 7059 { |
7060 if (branch_needs_nop_p (insn)) | |
7061 return "movb,%C2,n %1,%0,%3%#"; | |
7062 else | |
7063 return "movb,%C2,n %1,%0,%3"; | |
7064 } | |
6998 else | 7065 else |
6999 return "movb,%C2 %1,%0,%3"; | 7066 return "movb,%C2 %1,%0,%3"; |
7000 | 7067 |
7001 case 8: | 7068 case 8: |
7002 /* Handle weird backwards branch with a filled delay slot | 7069 /* Handle weird backwards branch with a filled delay slot |
7724 xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1); | 7791 xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1); |
7725 | 7792 |
7726 if (!delay_slot_filled && INSN_ADDRESSES_SET_P ()) | 7793 if (!delay_slot_filled && INSN_ADDRESSES_SET_P ()) |
7727 { | 7794 { |
7728 /* See if the return address can be adjusted. Use the containing | 7795 /* See if the return address can be adjusted. Use the containing |
7729 sequence insn's address. */ | 7796 sequence insn's address. This would break the regular call/return@ |
7797 relationship assumed by the table based eh unwinder, so only do that | |
7798 if the call is not possibly throwing. */ | |
7730 rtx seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0))); | 7799 rtx seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0))); |
7731 int distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn)))) | 7800 int distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn)))) |
7732 - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8); | 7801 - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8); |
7733 | 7802 |
7734 if (VAL_14_BITS_P (distance)) | 7803 if (VAL_14_BITS_P (distance) |
7804 && !(can_throw_internal (insn) || can_throw_external (insn))) | |
7735 { | 7805 { |
7736 xoperands[1] = gen_label_rtx (); | 7806 xoperands[1] = gen_label_rtx (); |
7737 output_asm_insn ("ldo %0-%1(%%r2),%%r2", xoperands); | 7807 output_asm_insn ("ldo %0-%1(%%r2),%%r2", xoperands); |
7738 targetm.asm_out.internal_label (asm_out_file, "L", | 7808 targetm.asm_out.internal_label (asm_out_file, "L", |
7739 CODE_LABEL_NUMBER (xoperands[1])); | 7809 CODE_LABEL_NUMBER (xoperands[1])); |
8531 non_hard_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | 8601 non_hard_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
8532 { | 8602 { |
8533 return ! (GET_CODE (op) == REG && REGNO (op) < FIRST_PSEUDO_REGISTER); | 8603 return ! (GET_CODE (op) == REG && REGNO (op) < FIRST_PSEUDO_REGISTER); |
8534 } | 8604 } |
8535 | 8605 |
8536 /* Return 1 if INSN branches forward. Should be using insn_addresses | 8606 /* Return TRUE if INSN branches forward. */ |
8537 to avoid walking through all the insns... */ | 8607 |
8538 static int | 8608 static bool |
8539 forward_branch_p (rtx insn) | 8609 forward_branch_p (rtx insn) |
8540 { | 8610 { |
8541 rtx label = JUMP_LABEL (insn); | 8611 rtx lab = JUMP_LABEL (insn); |
8612 | |
8613 /* The INSN must have a jump label. */ | |
8614 gcc_assert (lab != NULL_RTX); | |
8615 | |
8616 if (INSN_ADDRESSES_SET_P ()) | |
8617 return INSN_ADDRESSES (INSN_UID (lab)) > INSN_ADDRESSES (INSN_UID (insn)); | |
8542 | 8618 |
8543 while (insn) | 8619 while (insn) |
8544 { | 8620 { |
8545 if (insn == label) | 8621 if (insn == lab) |
8546 break; | 8622 return true; |
8547 else | 8623 else |
8548 insn = NEXT_INSN (insn); | 8624 insn = NEXT_INSN (insn); |
8549 } | 8625 } |
8550 | 8626 |
8551 return (insn == label); | 8627 return false; |
8552 } | 8628 } |
8553 | 8629 |
8554 /* Return 1 if OP is an equality comparison, else return 0. */ | 8630 /* Return 1 if OP is an equality comparison, else return 0. */ |
8555 int | 8631 int |
8556 eq_neq_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | 8632 eq_neq_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
9128 && GET_CODE (PATTERN (insn)) != USE | 9204 && GET_CODE (PATTERN (insn)) != USE |
9129 && GET_CODE (PATTERN (insn)) != CLOBBER | 9205 && GET_CODE (PATTERN (insn)) != CLOBBER |
9130 && get_attr_type (insn) == TYPE_MILLI)); | 9206 && get_attr_type (insn) == TYPE_MILLI)); |
9131 } | 9207 } |
9132 | 9208 |
9209 /* Promote the return value, but not the arguments. */ | |
9210 | |
9211 static enum machine_mode | |
9212 pa_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, | |
9213 enum machine_mode mode, | |
9214 int *punsignedp ATTRIBUTE_UNUSED, | |
9215 const_tree fntype ATTRIBUTE_UNUSED, | |
9216 int for_return) | |
9217 { | |
9218 if (for_return == 0) | |
9219 return mode; | |
9220 return promote_mode (type, mode, punsignedp); | |
9221 } | |
9222 | |
9133 /* On the HP-PA the value is found in register(s) 28(-29), unless | 9223 /* On the HP-PA the value is found in register(s) 28(-29), unless |
9134 the mode is SF or DF. Then the value is returned in fr4 (32). | 9224 the mode is SF or DF. Then the value is returned in fr4 (32). |
9135 | 9225 |
9136 This must perform the same promotions as PROMOTE_MODE, else | 9226 This must perform the same promotions as PROMOTE_MODE, else promoting |
9137 TARGET_PROMOTE_FUNCTION_RETURN will not work correctly. | 9227 return values in TARGET_PROMOTE_FUNCTION_MODE will not work correctly. |
9138 | 9228 |
9139 Small structures must be returned in a PARALLEL on PA64 in order | 9229 Small structures must be returned in a PARALLEL on PA64 in order |
9140 to match the HP Compiler ABI. */ | 9230 to match the HP Compiler ABI. */ |
9141 | 9231 |
9142 rtx | 9232 rtx |
9143 function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) | 9233 pa_function_value (const_tree valtype, |
9234 const_tree func ATTRIBUTE_UNUSED, | |
9235 bool outgoing ATTRIBUTE_UNUSED) | |
9144 { | 9236 { |
9145 enum machine_mode valmode; | 9237 enum machine_mode valmode; |
9146 | 9238 |
9147 if (AGGREGATE_TYPE_P (valtype) | 9239 if (AGGREGATE_TYPE_P (valtype) |
9148 || TREE_CODE (valtype) == COMPLEX_TYPE | 9240 || TREE_CODE (valtype) == COMPLEX_TYPE |
9617 /* Structure to hold declaration and name of external symbols that are | 9709 /* Structure to hold declaration and name of external symbols that are |
9618 emitted by GCC. We generate a vector of these symbols and output them | 9710 emitted by GCC. We generate a vector of these symbols and output them |
9619 at the end of the file if and only if SYMBOL_REF_REFERENCED_P is true. | 9711 at the end of the file if and only if SYMBOL_REF_REFERENCED_P is true. |
9620 This avoids putting out names that are never really used. */ | 9712 This avoids putting out names that are never really used. */ |
9621 | 9713 |
9622 typedef struct extern_symbol GTY(()) | 9714 typedef struct GTY(()) extern_symbol |
9623 { | 9715 { |
9624 tree decl; | 9716 tree decl; |
9625 const char *name; | 9717 const char *name; |
9626 } extern_symbol; | 9718 } extern_symbol; |
9627 | 9719 |
9731 return false; | 9823 return false; |
9732 | 9824 |
9733 return true; | 9825 return true; |
9734 } | 9826 } |
9735 | 9827 |
9828 | |
9829 /* Length in units of the trampoline instruction code. */ | |
9830 | |
9831 #define TRAMPOLINE_CODE_SIZE (TARGET_64BIT ? 24 : (TARGET_PA_20 ? 32 : 40)) | |
9832 | |
9833 | |
9834 /* Output assembler code for a block containing the constant parts | |
9835 of a trampoline, leaving space for the variable parts.\ | |
9836 | |
9837 The trampoline sets the static chain pointer to STATIC_CHAIN_REGNUM | |
9838 and then branches to the specified routine. | |
9839 | |
9840 This code template is copied from text segment to stack location | |
9841 and then patched with pa_trampoline_init to contain valid values, | |
9842 and then entered as a subroutine. | |
9843 | |
9844 It is best to keep this as small as possible to avoid having to | |
9845 flush multiple lines in the cache. */ | |
9846 | |
9847 static void | |
9848 pa_asm_trampoline_template (FILE *f) | |
9849 { | |
9850 if (!TARGET_64BIT) | |
9851 { | |
9852 fputs ("\tldw 36(%r22),%r21\n", f); | |
9853 fputs ("\tbb,>=,n %r21,30,.+16\n", f); | |
9854 if (ASSEMBLER_DIALECT == 0) | |
9855 fputs ("\tdepi 0,31,2,%r21\n", f); | |
9856 else | |
9857 fputs ("\tdepwi 0,31,2,%r21\n", f); | |
9858 fputs ("\tldw 4(%r21),%r19\n", f); | |
9859 fputs ("\tldw 0(%r21),%r21\n", f); | |
9860 if (TARGET_PA_20) | |
9861 { | |
9862 fputs ("\tbve (%r21)\n", f); | |
9863 fputs ("\tldw 40(%r22),%r29\n", f); | |
9864 fputs ("\t.word 0\n", f); | |
9865 fputs ("\t.word 0\n", f); | |
9866 } | |
9867 else | |
9868 { | |
9869 fputs ("\tldsid (%r21),%r1\n", f); | |
9870 fputs ("\tmtsp %r1,%sr0\n", f); | |
9871 fputs ("\tbe 0(%sr0,%r21)\n", f); | |
9872 fputs ("\tldw 40(%r22),%r29\n", f); | |
9873 } | |
9874 fputs ("\t.word 0\n", f); | |
9875 fputs ("\t.word 0\n", f); | |
9876 fputs ("\t.word 0\n", f); | |
9877 fputs ("\t.word 0\n", f); | |
9878 } | |
9879 else | |
9880 { | |
9881 fputs ("\t.dword 0\n", f); | |
9882 fputs ("\t.dword 0\n", f); | |
9883 fputs ("\t.dword 0\n", f); | |
9884 fputs ("\t.dword 0\n", f); | |
9885 fputs ("\tmfia %r31\n", f); | |
9886 fputs ("\tldd 24(%r31),%r1\n", f); | |
9887 fputs ("\tldd 24(%r1),%r27\n", f); | |
9888 fputs ("\tldd 16(%r1),%r1\n", f); | |
9889 fputs ("\tbve (%r1)\n", f); | |
9890 fputs ("\tldd 32(%r31),%r31\n", f); | |
9891 fputs ("\t.dword 0 ; fptr\n", f); | |
9892 fputs ("\t.dword 0 ; static link\n", f); | |
9893 } | |
9894 } | |
9895 | |
9896 /* Emit RTL insns to initialize the variable parts of a trampoline. | |
9897 FNADDR is an RTX for the address of the function's pure code. | |
9898 CXT is an RTX for the static chain value for the function. | |
9899 | |
9900 Move the function address to the trampoline template at offset 36. | |
9901 Move the static chain value to trampoline template at offset 40. | |
9902 Move the trampoline address to trampoline template at offset 44. | |
9903 Move r19 to trampoline template at offset 48. The latter two | |
9904 words create a plabel for the indirect call to the trampoline. | |
9905 | |
9906 A similar sequence is used for the 64-bit port but the plabel is | |
9907 at the beginning of the trampoline. | |
9908 | |
9909 Finally, the cache entries for the trampoline code are flushed. | |
9910 This is necessary to ensure that the trampoline instruction sequence | |
9911 is written to memory prior to any attempts at prefetching the code | |
9912 sequence. */ | |
9913 | |
9914 static void | |
9915 pa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) | |
9916 { | |
9917 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); | |
9918 rtx start_addr = gen_reg_rtx (Pmode); | |
9919 rtx end_addr = gen_reg_rtx (Pmode); | |
9920 rtx line_length = gen_reg_rtx (Pmode); | |
9921 rtx r_tramp, tmp; | |
9922 | |
9923 emit_block_move (m_tramp, assemble_trampoline_template (), | |
9924 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); | |
9925 r_tramp = force_reg (Pmode, XEXP (m_tramp, 0)); | |
9926 | |
9927 if (!TARGET_64BIT) | |
9928 { | |
9929 tmp = adjust_address (m_tramp, Pmode, 36); | |
9930 emit_move_insn (tmp, fnaddr); | |
9931 tmp = adjust_address (m_tramp, Pmode, 40); | |
9932 emit_move_insn (tmp, chain_value); | |
9933 | |
9934 /* Create a fat pointer for the trampoline. */ | |
9935 tmp = adjust_address (m_tramp, Pmode, 44); | |
9936 emit_move_insn (tmp, r_tramp); | |
9937 tmp = adjust_address (m_tramp, Pmode, 48); | |
9938 emit_move_insn (tmp, gen_rtx_REG (Pmode, 19)); | |
9939 | |
9940 /* fdc and fic only use registers for the address to flush, | |
9941 they do not accept integer displacements. We align the | |
9942 start and end addresses to the beginning of their respective | |
9943 cache lines to minimize the number of lines flushed. */ | |
9944 emit_insn (gen_andsi3 (start_addr, r_tramp, | |
9945 GEN_INT (-MIN_CACHELINE_SIZE))); | |
9946 tmp = force_reg (Pmode, plus_constant (r_tramp, TRAMPOLINE_CODE_SIZE-1)); | |
9947 emit_insn (gen_andsi3 (end_addr, tmp, | |
9948 GEN_INT (-MIN_CACHELINE_SIZE))); | |
9949 emit_move_insn (line_length, GEN_INT (MIN_CACHELINE_SIZE)); | |
9950 emit_insn (gen_dcacheflushsi (start_addr, end_addr, line_length)); | |
9951 emit_insn (gen_icacheflushsi (start_addr, end_addr, line_length, | |
9952 gen_reg_rtx (Pmode), | |
9953 gen_reg_rtx (Pmode))); | |
9954 } | |
9955 else | |
9956 { | |
9957 tmp = adjust_address (m_tramp, Pmode, 56); | |
9958 emit_move_insn (tmp, fnaddr); | |
9959 tmp = adjust_address (m_tramp, Pmode, 64); | |
9960 emit_move_insn (tmp, chain_value); | |
9961 | |
9962 /* Create a fat pointer for the trampoline. */ | |
9963 tmp = adjust_address (m_tramp, Pmode, 16); | |
9964 emit_move_insn (tmp, force_reg (Pmode, plus_constant (r_tramp, 32))); | |
9965 tmp = adjust_address (m_tramp, Pmode, 24); | |
9966 emit_move_insn (tmp, gen_rtx_REG (Pmode, 27)); | |
9967 | |
9968 /* fdc and fic only use registers for the address to flush, | |
9969 they do not accept integer displacements. We align the | |
9970 start and end addresses to the beginning of their respective | |
9971 cache lines to minimize the number of lines flushed. */ | |
9972 tmp = force_reg (Pmode, plus_constant (r_tramp, 32)); | |
9973 emit_insn (gen_anddi3 (start_addr, tmp, | |
9974 GEN_INT (-MIN_CACHELINE_SIZE))); | |
9975 tmp = force_reg (Pmode, plus_constant (tmp, TRAMPOLINE_CODE_SIZE - 1)); | |
9976 emit_insn (gen_anddi3 (end_addr, tmp, | |
9977 GEN_INT (-MIN_CACHELINE_SIZE))); | |
9978 emit_move_insn (line_length, GEN_INT (MIN_CACHELINE_SIZE)); | |
9979 emit_insn (gen_dcacheflushdi (start_addr, end_addr, line_length)); | |
9980 emit_insn (gen_icacheflushdi (start_addr, end_addr, line_length, | |
9981 gen_reg_rtx (Pmode), | |
9982 gen_reg_rtx (Pmode))); | |
9983 } | |
9984 } | |
9985 | |
9986 /* Perform any machine-specific adjustment in the address of the trampoline. | |
9987 ADDR contains the address that was passed to pa_trampoline_init. | |
9988 Adjust the trampoline address to point to the plabel at offset 44. */ | |
9989 | |
9990 static rtx | |
9991 pa_trampoline_adjust_address (rtx addr) | |
9992 { | |
9993 if (!TARGET_64BIT) | |
9994 addr = memory_address (Pmode, plus_constant (addr, 46)); | |
9995 return addr; | |
9996 } | |
9997 | |
9736 #include "gt-pa.h" | 9998 #include "gt-pa.h" |