190075Sobrien/* Definitions of target machine for GNU compiler. 2169689Skan Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 3132718Skan Free Software Foundation, Inc. 490075Sobrien Contributed by James E. Wilson <wilson@cygnus.com> and 5132718Skan David Mosberger <davidm@hpl.hp.com>. 690075Sobrien 7132718SkanThis file is part of GCC. 890075Sobrien 9132718SkanGCC is free software; you can redistribute it and/or modify 1090075Sobrienit under the terms of the GNU General Public License as published by 1190075Sobrienthe Free Software Foundation; either version 2, or (at your option) 1290075Sobrienany later version. 1390075Sobrien 14132718SkanGCC is distributed in the hope that it will be useful, 1590075Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1690075SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1790075SobrienGNU General Public License for more details. 1890075Sobrien 1990075SobrienYou should have received a copy of the GNU General Public License 20132718Skanalong with GCC; see the file COPYING. If not, write to 21169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor, 22169689SkanBoston, MA 02110-1301, USA. */ 2390075Sobrien 2490075Sobrien#include "config.h" 2590075Sobrien#include "system.h" 26132718Skan#include "coretypes.h" 27132718Skan#include "tm.h" 2890075Sobrien#include "rtl.h" 2990075Sobrien#include "tree.h" 3090075Sobrien#include "regs.h" 3190075Sobrien#include "hard-reg-set.h" 3290075Sobrien#include "real.h" 3390075Sobrien#include "insn-config.h" 3490075Sobrien#include "conditions.h" 3590075Sobrien#include "output.h" 3690075Sobrien#include "insn-attr.h" 3790075Sobrien#include "flags.h" 3890075Sobrien#include "recog.h" 3990075Sobrien#include "expr.h" 4090075Sobrien#include "optabs.h" 4190075Sobrien#include "except.h" 4290075Sobrien#include "function.h" 4390075Sobrien#include "ggc.h" 4490075Sobrien#include "basic-block.h" 4590075Sobrien#include "toplev.h" 4690075Sobrien#include "sched-int.h" 4790075Sobrien#include "timevar.h" 4890075Sobrien#include "target.h" 4990075Sobrien#include "target-def.h" 5096263Sobrien#include "tm_p.h" 51132718Skan#include "hashtab.h" 52117395Skan#include "langhooks.h" 53132718Skan#include "cfglayout.h" 54169689Skan#include "tree-gimple.h" 55169689Skan#include "intl.h" 56169689Skan#include "debug.h" 57169689Skan#include "params.h" 5890075Sobrien 5990075Sobrien/* This is used for communication between ASM_OUTPUT_LABEL and 6090075Sobrien ASM_OUTPUT_LABELREF. */ 6190075Sobrienint ia64_asm_output_label = 0; 6290075Sobrien 6390075Sobrien/* Define the information needed to generate branch and scc insns. This is 6490075Sobrien stored from the compare operation. */ 6590075Sobrienstruct rtx_def * ia64_compare_op0; 6690075Sobrienstruct rtx_def * ia64_compare_op1; 6790075Sobrien 6890075Sobrien/* Register names for ia64_expand_prologue. */ 6990075Sobrienstatic const char * const ia64_reg_numbers[96] = 7090075Sobrien{ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", 7190075Sobrien "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", 7290075Sobrien "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", 7390075Sobrien "r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63", 7490075Sobrien "r64", "r65", "r66", "r67", "r68", "r69", "r70", "r71", 7590075Sobrien "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79", 7690075Sobrien "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", 7790075Sobrien "r88", "r89", "r90", "r91", "r92", "r93", "r94", "r95", 7890075Sobrien "r96", "r97", "r98", "r99", "r100","r101","r102","r103", 7990075Sobrien "r104","r105","r106","r107","r108","r109","r110","r111", 8090075Sobrien "r112","r113","r114","r115","r116","r117","r118","r119", 8190075Sobrien "r120","r121","r122","r123","r124","r125","r126","r127"}; 8290075Sobrien 8390075Sobrien/* ??? These strings could be shared with REGISTER_NAMES. */ 8490075Sobrienstatic const char * const ia64_input_reg_names[8] = 8590075Sobrien{ "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7" }; 8690075Sobrien 8790075Sobrien/* ??? These strings could be shared with REGISTER_NAMES. */ 8890075Sobrienstatic const char * const ia64_local_reg_names[80] = 8990075Sobrien{ "loc0", "loc1", "loc2", "loc3", "loc4", "loc5", "loc6", "loc7", 9090075Sobrien "loc8", "loc9", "loc10","loc11","loc12","loc13","loc14","loc15", 9190075Sobrien "loc16","loc17","loc18","loc19","loc20","loc21","loc22","loc23", 9290075Sobrien "loc24","loc25","loc26","loc27","loc28","loc29","loc30","loc31", 9390075Sobrien "loc32","loc33","loc34","loc35","loc36","loc37","loc38","loc39", 9490075Sobrien "loc40","loc41","loc42","loc43","loc44","loc45","loc46","loc47", 9590075Sobrien "loc48","loc49","loc50","loc51","loc52","loc53","loc54","loc55", 9690075Sobrien "loc56","loc57","loc58","loc59","loc60","loc61","loc62","loc63", 9790075Sobrien "loc64","loc65","loc66","loc67","loc68","loc69","loc70","loc71", 9890075Sobrien "loc72","loc73","loc74","loc75","loc76","loc77","loc78","loc79" }; 9990075Sobrien 10090075Sobrien/* ??? These strings could be shared with REGISTER_NAMES. */ 10190075Sobrienstatic const char * const ia64_output_reg_names[8] = 10290075Sobrien{ "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7" }; 10390075Sobrien 104132718Skan/* Which cpu are we scheduling for. */ 105169689Skanenum processor_type ia64_tune = PROCESSOR_ITANIUM2; 106132718Skan 10790075Sobrien/* Determines whether we run our final scheduling pass or not. We always 10890075Sobrien avoid the normal second scheduling pass. */ 10990075Sobrienstatic int ia64_flag_schedule_insns2; 11090075Sobrien 111169689Skan/* Determines whether we run variable tracking in machine dependent 112169689Skan reorganization. */ 113169689Skanstatic int ia64_flag_var_tracking; 114169689Skan 11590075Sobrien/* Variables which are this size or smaller are put in the sdata/sbss 11690075Sobrien sections. */ 11790075Sobrien 11890075Sobrienunsigned int ia64_section_threshold; 119117395Skan 120132718Skan/* The following variable is used by the DFA insn scheduler. The value is 121132718Skan TRUE if we do insn bundling instead of insn scheduling. */ 122132718Skanint bundling_p = 0; 123132718Skan 124117395Skan/* Structure to be filled in by ia64_compute_frame_size with register 125117395Skan save masks and offsets for the current function. */ 126117395Skan 127117395Skanstruct ia64_frame_info 128117395Skan{ 129117395Skan HOST_WIDE_INT total_size; /* size of the stack frame, not including 130117395Skan the caller's scratch area. */ 131117395Skan HOST_WIDE_INT spill_cfa_off; /* top of the reg spill area from the cfa. */ 132117395Skan HOST_WIDE_INT spill_size; /* size of the gr/br/fr spill area. */ 133117395Skan HOST_WIDE_INT extra_spill_size; /* size of spill area for others. */ 134117395Skan HARD_REG_SET mask; /* mask of saved registers. */ 135132718Skan unsigned int gr_used_mask; /* mask of registers in use as gr spill 136117395Skan registers or long-term scratches. */ 137117395Skan int n_spilled; /* number of spilled registers. */ 138117395Skan int reg_fp; /* register for fp. */ 139117395Skan int reg_save_b0; /* save register for b0. */ 140117395Skan int reg_save_pr; /* save register for prs. */ 141117395Skan int reg_save_ar_pfs; /* save register for ar.pfs. */ 142117395Skan int reg_save_ar_unat; /* save register for ar.unat. */ 143117395Skan int reg_save_ar_lc; /* save register for ar.lc. */ 144117395Skan int reg_save_gp; /* save register for gp. */ 145117395Skan int n_input_regs; /* number of input registers used. */ 146117395Skan int n_local_regs; /* number of local registers used. */ 147117395Skan int n_output_regs; /* number of output registers used. */ 148117395Skan int n_rotate_regs; /* number of rotating registers used. */ 149117395Skan 150117395Skan char need_regstk; /* true if a .regstk directive needed. */ 151117395Skan char initialized; /* true if the data is finalized. */ 152117395Skan}; 153117395Skan 154117395Skan/* Current frame information calculated by ia64_compute_frame_size. */ 155117395Skanstatic struct ia64_frame_info current_frame_info; 15690075Sobrien 157132718Skanstatic int ia64_first_cycle_multipass_dfa_lookahead (void); 158132718Skanstatic void ia64_dependencies_evaluation_hook (rtx, rtx); 159132718Skanstatic void ia64_init_dfa_pre_cycle_insn (void); 160132718Skanstatic rtx ia64_dfa_pre_cycle_insn (void); 161132718Skanstatic int ia64_first_cycle_multipass_dfa_lookahead_guard (rtx); 162169689Skanstatic bool ia64_first_cycle_multipass_dfa_lookahead_guard_spec (rtx); 163132718Skanstatic int ia64_dfa_new_cycle (FILE *, int, rtx, int, int, int *); 164169689Skanstatic void ia64_h_i_d_extended (void); 165169689Skanstatic int ia64_mode_to_int (enum machine_mode); 166169689Skanstatic void ia64_set_sched_flags (spec_info_t); 167169689Skanstatic int ia64_speculate_insn (rtx, ds_t, rtx *); 168169689Skanstatic rtx ia64_gen_spec_insn (rtx, ds_t, int, bool, bool); 169169689Skanstatic bool ia64_needs_block_p (rtx); 170169689Skanstatic rtx ia64_gen_check (rtx, rtx, bool); 171169689Skanstatic int ia64_spec_check_p (rtx); 172169689Skanstatic int ia64_spec_check_src_p (rtx); 173132718Skanstatic rtx gen_tls_get_addr (void); 174132718Skanstatic rtx gen_thread_pointer (void); 175132718Skanstatic int find_gr_spill (int); 176132718Skanstatic int next_scratch_gr_reg (void); 177132718Skanstatic void mark_reg_gr_used_mask (rtx, void *); 178132718Skanstatic void ia64_compute_frame_size (HOST_WIDE_INT); 179132718Skanstatic void setup_spill_pointers (int, rtx, HOST_WIDE_INT); 180132718Skanstatic void finish_spill_pointers (void); 181132718Skanstatic rtx spill_restore_mem (rtx, HOST_WIDE_INT); 182132718Skanstatic void do_spill (rtx (*)(rtx, rtx, rtx), rtx, HOST_WIDE_INT, rtx); 183132718Skanstatic void do_restore (rtx (*)(rtx, rtx, rtx), rtx, HOST_WIDE_INT); 184132718Skanstatic rtx gen_movdi_x (rtx, rtx, rtx); 185132718Skanstatic rtx gen_fr_spill_x (rtx, rtx, rtx); 186132718Skanstatic rtx gen_fr_restore_x (rtx, rtx, rtx); 18790075Sobrien 188169689Skanstatic enum machine_mode hfa_element_mode (tree, bool); 189169689Skanstatic void ia64_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, 190169689Skan tree, int *, int); 191169689Skanstatic int ia64_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, 192169689Skan tree, bool); 193132718Skanstatic bool ia64_function_ok_for_sibcall (tree, tree); 194169689Skanstatic bool ia64_return_in_memory (tree, tree); 195132718Skanstatic bool ia64_rtx_costs (rtx, int, int, int *); 196132718Skanstatic void fix_range (const char *); 197169689Skanstatic bool ia64_handle_option (size_t, const char *, int); 198132718Skanstatic struct machine_function * ia64_init_machine_status (void); 199132718Skanstatic void emit_insn_group_barriers (FILE *); 200132718Skanstatic void emit_all_insn_group_barriers (FILE *); 201132718Skanstatic void final_emit_insn_group_barriers (FILE *); 202132718Skanstatic void emit_predicate_relation_info (void); 203132718Skanstatic void ia64_reorg (void); 204132718Skanstatic bool ia64_in_small_data_p (tree); 205169689Skanstatic void process_epilogue (FILE *, rtx, bool, bool); 206169689Skanstatic int process_set (FILE *, rtx, rtx, bool, bool); 20790075Sobrien 208132718Skanstatic bool ia64_assemble_integer (rtx, unsigned int, int); 209132718Skanstatic void ia64_output_function_prologue (FILE *, HOST_WIDE_INT); 210132718Skanstatic void ia64_output_function_epilogue (FILE *, HOST_WIDE_INT); 211132718Skanstatic void ia64_output_function_end_prologue (FILE *); 21290075Sobrien 213132718Skanstatic int ia64_issue_rate (void); 214169689Skanstatic int ia64_adjust_cost_2 (rtx, int, rtx, int); 215132718Skanstatic void ia64_sched_init (FILE *, int, int); 216169689Skanstatic void ia64_sched_init_global (FILE *, int, int); 217169689Skanstatic void ia64_sched_finish_global (FILE *, int); 218132718Skanstatic void ia64_sched_finish (FILE *, int); 219132718Skanstatic int ia64_dfa_sched_reorder (FILE *, int, rtx *, int *, int, int); 220132718Skanstatic int ia64_sched_reorder (FILE *, int, rtx *, int *, int); 221132718Skanstatic int ia64_sched_reorder2 (FILE *, int, rtx *, int *, int); 222132718Skanstatic int ia64_variable_issue (FILE *, int, rtx, int); 22390075Sobrien 224132718Skanstatic struct bundle_state *get_free_bundle_state (void); 225132718Skanstatic void free_bundle_state (struct bundle_state *); 226132718Skanstatic void initiate_bundle_states (void); 227132718Skanstatic void finish_bundle_states (void); 228132718Skanstatic unsigned bundle_state_hash (const void *); 229132718Skanstatic int bundle_state_eq_p (const void *, const void *); 230132718Skanstatic int insert_bundle_state (struct bundle_state *); 231132718Skanstatic void initiate_bundle_state_table (void); 232132718Skanstatic void finish_bundle_state_table (void); 233132718Skanstatic int try_issue_nops (struct bundle_state *, int); 234132718Skanstatic int try_issue_insn (struct bundle_state *, rtx); 235132718Skanstatic void issue_nops_and_insn (struct bundle_state *, int, rtx, int, int); 236132718Skanstatic int get_max_pos (state_t); 237132718Skanstatic int get_template (state_t, int); 238117395Skan 239132718Skanstatic rtx get_next_important_insn (rtx, rtx); 240132718Skanstatic void bundling (FILE *, int, rtx, rtx); 241132718Skan 242132718Skanstatic void ia64_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, 243132718Skan HOST_WIDE_INT, tree); 244132718Skanstatic void ia64_file_start (void); 245132718Skan 246169689Skanstatic int ia64_hpux_reloc_rw_mask (void) ATTRIBUTE_UNUSED; 247169689Skanstatic int ia64_reloc_rw_mask (void) ATTRIBUTE_UNUSED; 248169689Skanstatic section *ia64_select_rtx_section (enum machine_mode, rtx, 249169689Skan unsigned HOST_WIDE_INT); 250169689Skanstatic void ia64_output_dwarf_dtprel (FILE *, int, rtx) 251117395Skan ATTRIBUTE_UNUSED; 252169689Skanstatic unsigned int ia64_section_type_flags (tree, const char *, int); 253169689Skanstatic void ia64_init_libfuncs (void) 254169689Skan ATTRIBUTE_UNUSED; 255132718Skanstatic void ia64_hpux_init_libfuncs (void) 256132718Skan ATTRIBUTE_UNUSED; 257169689Skanstatic void ia64_sysv4_init_libfuncs (void) 258169689Skan ATTRIBUTE_UNUSED; 259132718Skanstatic void ia64_vms_init_libfuncs (void) 260132718Skan ATTRIBUTE_UNUSED; 261132718Skan 262132718Skanstatic tree ia64_handle_model_attribute (tree *, tree, tree, int, bool *); 263132718Skanstatic void ia64_encode_section_info (tree, rtx, int); 264132718Skanstatic rtx ia64_struct_value_rtx (tree, int); 265169689Skanstatic tree ia64_gimplify_va_arg (tree, tree, tree *, tree *); 266169689Skanstatic bool ia64_scalar_mode_supported_p (enum machine_mode mode); 267169689Skanstatic bool ia64_vector_mode_supported_p (enum machine_mode mode); 268169689Skanstatic bool ia64_cannot_force_const_mem (rtx); 269169689Skanstatic const char *ia64_mangle_fundamental_type (tree); 270169689Skanstatic const char *ia64_invalid_conversion (tree, tree); 271169689Skanstatic const char *ia64_invalid_unary_op (int, tree); 272169689Skanstatic const char *ia64_invalid_binary_op (int, tree, tree); 27390075Sobrien 27496263Sobrien/* Table of valid machine attributes. */ 27596263Sobrienstatic const struct attribute_spec ia64_attribute_table[] = 27696263Sobrien{ 27796263Sobrien /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ 27896263Sobrien { "syscall_linkage", 0, 0, false, true, true, NULL }, 279132718Skan { "model", 1, 1, true, false, false, ia64_handle_model_attribute }, 280132718Skan { NULL, 0, 0, false, false, false, NULL } 28196263Sobrien}; 28296263Sobrien 28390075Sobrien/* Initialize the GCC target structure. */ 28490075Sobrien#undef TARGET_ATTRIBUTE_TABLE 28590075Sobrien#define TARGET_ATTRIBUTE_TABLE ia64_attribute_table 28690075Sobrien 28790075Sobrien#undef TARGET_INIT_BUILTINS 28890075Sobrien#define TARGET_INIT_BUILTINS ia64_init_builtins 28990075Sobrien 29090075Sobrien#undef TARGET_EXPAND_BUILTIN 29190075Sobrien#define TARGET_EXPAND_BUILTIN ia64_expand_builtin 29290075Sobrien 29390075Sobrien#undef TARGET_ASM_BYTE_OP 29490075Sobrien#define TARGET_ASM_BYTE_OP "\tdata1\t" 29590075Sobrien#undef TARGET_ASM_ALIGNED_HI_OP 29690075Sobrien#define TARGET_ASM_ALIGNED_HI_OP "\tdata2\t" 29790075Sobrien#undef TARGET_ASM_ALIGNED_SI_OP 29890075Sobrien#define TARGET_ASM_ALIGNED_SI_OP "\tdata4\t" 29990075Sobrien#undef TARGET_ASM_ALIGNED_DI_OP 30090075Sobrien#define TARGET_ASM_ALIGNED_DI_OP "\tdata8\t" 30190075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP 30290075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\tdata2.ua\t" 30390075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP 30490075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\tdata4.ua\t" 30590075Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP 30690075Sobrien#define TARGET_ASM_UNALIGNED_DI_OP "\tdata8.ua\t" 30790075Sobrien#undef TARGET_ASM_INTEGER 30890075Sobrien#define TARGET_ASM_INTEGER ia64_assemble_integer 30990075Sobrien 31090075Sobrien#undef TARGET_ASM_FUNCTION_PROLOGUE 31190075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE ia64_output_function_prologue 31290075Sobrien#undef TARGET_ASM_FUNCTION_END_PROLOGUE 31390075Sobrien#define TARGET_ASM_FUNCTION_END_PROLOGUE ia64_output_function_end_prologue 31490075Sobrien#undef TARGET_ASM_FUNCTION_EPILOGUE 31590075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE ia64_output_function_epilogue 31690075Sobrien 317117395Skan#undef TARGET_IN_SMALL_DATA_P 318117395Skan#define TARGET_IN_SMALL_DATA_P ia64_in_small_data_p 319117395Skan 320169689Skan#undef TARGET_SCHED_ADJUST_COST_2 321169689Skan#define TARGET_SCHED_ADJUST_COST_2 ia64_adjust_cost_2 32290075Sobrien#undef TARGET_SCHED_ISSUE_RATE 32390075Sobrien#define TARGET_SCHED_ISSUE_RATE ia64_issue_rate 32490075Sobrien#undef TARGET_SCHED_VARIABLE_ISSUE 32590075Sobrien#define TARGET_SCHED_VARIABLE_ISSUE ia64_variable_issue 32690075Sobrien#undef TARGET_SCHED_INIT 32790075Sobrien#define TARGET_SCHED_INIT ia64_sched_init 32890075Sobrien#undef TARGET_SCHED_FINISH 32990075Sobrien#define TARGET_SCHED_FINISH ia64_sched_finish 330169689Skan#undef TARGET_SCHED_INIT_GLOBAL 331169689Skan#define TARGET_SCHED_INIT_GLOBAL ia64_sched_init_global 332169689Skan#undef TARGET_SCHED_FINISH_GLOBAL 333169689Skan#define TARGET_SCHED_FINISH_GLOBAL ia64_sched_finish_global 33490075Sobrien#undef TARGET_SCHED_REORDER 33590075Sobrien#define TARGET_SCHED_REORDER ia64_sched_reorder 33690075Sobrien#undef TARGET_SCHED_REORDER2 33790075Sobrien#define TARGET_SCHED_REORDER2 ia64_sched_reorder2 33890075Sobrien 339132718Skan#undef TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK 340132718Skan#define TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK ia64_dependencies_evaluation_hook 341117395Skan 342132718Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD 343132718Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD ia64_first_cycle_multipass_dfa_lookahead 344132718Skan 345132718Skan#undef TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN 346132718Skan#define TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN ia64_init_dfa_pre_cycle_insn 347132718Skan#undef TARGET_SCHED_DFA_PRE_CYCLE_INSN 348132718Skan#define TARGET_SCHED_DFA_PRE_CYCLE_INSN ia64_dfa_pre_cycle_insn 349132718Skan 350132718Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD 351132718Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD\ 352132718Skan ia64_first_cycle_multipass_dfa_lookahead_guard 353132718Skan 354132718Skan#undef TARGET_SCHED_DFA_NEW_CYCLE 355132718Skan#define TARGET_SCHED_DFA_NEW_CYCLE ia64_dfa_new_cycle 356132718Skan 357169689Skan#undef TARGET_SCHED_H_I_D_EXTENDED 358169689Skan#define TARGET_SCHED_H_I_D_EXTENDED ia64_h_i_d_extended 359169689Skan 360169689Skan#undef TARGET_SCHED_SET_SCHED_FLAGS 361169689Skan#define TARGET_SCHED_SET_SCHED_FLAGS ia64_set_sched_flags 362169689Skan 363169689Skan#undef TARGET_SCHED_SPECULATE_INSN 364169689Skan#define TARGET_SCHED_SPECULATE_INSN ia64_speculate_insn 365169689Skan 366169689Skan#undef TARGET_SCHED_NEEDS_BLOCK_P 367169689Skan#define TARGET_SCHED_NEEDS_BLOCK_P ia64_needs_block_p 368169689Skan 369169689Skan#undef TARGET_SCHED_GEN_CHECK 370169689Skan#define TARGET_SCHED_GEN_CHECK ia64_gen_check 371169689Skan 372169689Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD_SPEC 373169689Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD_SPEC\ 374169689Skan ia64_first_cycle_multipass_dfa_lookahead_guard_spec 375169689Skan 376132718Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL 377132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL ia64_function_ok_for_sibcall 378169689Skan#undef TARGET_ARG_PARTIAL_BYTES 379169689Skan#define TARGET_ARG_PARTIAL_BYTES ia64_arg_partial_bytes 380132718Skan 381117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK 382117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK ia64_output_mi_thunk 383117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 384117395Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true 385117395Skan 386132718Skan#undef TARGET_ASM_FILE_START 387132718Skan#define TARGET_ASM_FILE_START ia64_file_start 388132718Skan 389132718Skan#undef TARGET_RTX_COSTS 390132718Skan#define TARGET_RTX_COSTS ia64_rtx_costs 391132718Skan#undef TARGET_ADDRESS_COST 392132718Skan#define TARGET_ADDRESS_COST hook_int_rtx_0 393132718Skan 394132718Skan#undef TARGET_MACHINE_DEPENDENT_REORG 395132718Skan#define TARGET_MACHINE_DEPENDENT_REORG ia64_reorg 396132718Skan 397132718Skan#undef TARGET_ENCODE_SECTION_INFO 398132718Skan#define TARGET_ENCODE_SECTION_INFO ia64_encode_section_info 399132718Skan 400169689Skan#undef TARGET_SECTION_TYPE_FLAGS 401169689Skan#define TARGET_SECTION_TYPE_FLAGS ia64_section_type_flags 402132718Skan 403169689Skan#ifdef HAVE_AS_TLS 404169689Skan#undef TARGET_ASM_OUTPUT_DWARF_DTPREL 405169689Skan#define TARGET_ASM_OUTPUT_DWARF_DTPREL ia64_output_dwarf_dtprel 406169689Skan#endif 40790075Sobrien 408169689Skan/* ??? ABI doesn't allow us to define this. */ 409169689Skan#if 0 410169689Skan#undef TARGET_PROMOTE_FUNCTION_ARGS 411169689Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true 412169689Skan#endif 41390075Sobrien 414169689Skan/* ??? ABI doesn't allow us to define this. */ 415169689Skan#if 0 416169689Skan#undef TARGET_PROMOTE_FUNCTION_RETURN 417169689Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true 418169689Skan#endif 41990075Sobrien 420169689Skan/* ??? Investigate. */ 421169689Skan#if 0 422169689Skan#undef TARGET_PROMOTE_PROTOTYPES 423169689Skan#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true 424169689Skan#endif 42590075Sobrien 426169689Skan#undef TARGET_STRUCT_VALUE_RTX 427169689Skan#define TARGET_STRUCT_VALUE_RTX ia64_struct_value_rtx 428169689Skan#undef TARGET_RETURN_IN_MEMORY 429169689Skan#define TARGET_RETURN_IN_MEMORY ia64_return_in_memory 430169689Skan#undef TARGET_SETUP_INCOMING_VARARGS 431169689Skan#define TARGET_SETUP_INCOMING_VARARGS ia64_setup_incoming_varargs 432169689Skan#undef TARGET_STRICT_ARGUMENT_NAMING 433169689Skan#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true 434169689Skan#undef TARGET_MUST_PASS_IN_STACK 435169689Skan#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size 436146895Skan 437169689Skan#undef TARGET_GIMPLIFY_VA_ARG_EXPR 438169689Skan#define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg 43990075Sobrien 440169689Skan#undef TARGET_UNWIND_EMIT 441169689Skan#define TARGET_UNWIND_EMIT process_for_unwind_directive 44290075Sobrien 443169689Skan#undef TARGET_SCALAR_MODE_SUPPORTED_P 444169689Skan#define TARGET_SCALAR_MODE_SUPPORTED_P ia64_scalar_mode_supported_p 445169689Skan#undef TARGET_VECTOR_MODE_SUPPORTED_P 446169689Skan#define TARGET_VECTOR_MODE_SUPPORTED_P ia64_vector_mode_supported_p 447146895Skan 448169689Skan/* ia64 architecture manual 4.4.7: ... reads, writes, and flushes may occur 449169689Skan in an order different from the specified program order. */ 450169689Skan#undef TARGET_RELAXED_ORDERING 451169689Skan#define TARGET_RELAXED_ORDERING true 452146895Skan 453169689Skan#undef TARGET_DEFAULT_TARGET_FLAGS 454169689Skan#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | TARGET_CPU_DEFAULT) 455169689Skan#undef TARGET_HANDLE_OPTION 456169689Skan#define TARGET_HANDLE_OPTION ia64_handle_option 457146895Skan 458169689Skan#undef TARGET_CANNOT_FORCE_CONST_MEM 459169689Skan#define TARGET_CANNOT_FORCE_CONST_MEM ia64_cannot_force_const_mem 46090075Sobrien 461169689Skan#undef TARGET_MANGLE_FUNDAMENTAL_TYPE 462169689Skan#define TARGET_MANGLE_FUNDAMENTAL_TYPE ia64_mangle_fundamental_type 46390075Sobrien 464169689Skan#undef TARGET_INVALID_CONVERSION 465169689Skan#define TARGET_INVALID_CONVERSION ia64_invalid_conversion 466169689Skan#undef TARGET_INVALID_UNARY_OP 467169689Skan#define TARGET_INVALID_UNARY_OP ia64_invalid_unary_op 468169689Skan#undef TARGET_INVALID_BINARY_OP 469169689Skan#define TARGET_INVALID_BINARY_OP ia64_invalid_binary_op 470132718Skan 471169689Skanstruct gcc_target targetm = TARGET_INITIALIZER; 47290075Sobrien 473132718Skantypedef enum 474132718Skan { 475132718Skan ADDR_AREA_NORMAL, /* normal address area */ 476132718Skan ADDR_AREA_SMALL /* addressable by "addl" (-2MB < addr < 2MB) */ 477132718Skan } 478132718Skania64_addr_area; 479132718Skan 480132718Skanstatic GTY(()) tree small_ident1; 481132718Skanstatic GTY(()) tree small_ident2; 482132718Skan 483132718Skanstatic void 484132718Skaninit_idents (void) 485132718Skan{ 486132718Skan if (small_ident1 == 0) 487132718Skan { 488132718Skan small_ident1 = get_identifier ("small"); 489132718Skan small_ident2 = get_identifier ("__small__"); 490132718Skan } 491132718Skan} 492132718Skan 493132718Skan/* Retrieve the address area that has been chosen for the given decl. */ 494132718Skan 495132718Skanstatic ia64_addr_area 496132718Skania64_get_addr_area (tree decl) 497132718Skan{ 498132718Skan tree model_attr; 499132718Skan 500132718Skan model_attr = lookup_attribute ("model", DECL_ATTRIBUTES (decl)); 501132718Skan if (model_attr) 502132718Skan { 503132718Skan tree id; 504132718Skan 505132718Skan init_idents (); 506132718Skan id = TREE_VALUE (TREE_VALUE (model_attr)); 507132718Skan if (id == small_ident1 || id == small_ident2) 508132718Skan return ADDR_AREA_SMALL; 509132718Skan } 510132718Skan return ADDR_AREA_NORMAL; 511132718Skan} 512132718Skan 513132718Skanstatic tree 514169689Skania64_handle_model_attribute (tree *node, tree name, tree args, 515169689Skan int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) 516132718Skan{ 517132718Skan ia64_addr_area addr_area = ADDR_AREA_NORMAL; 518132718Skan ia64_addr_area area; 519132718Skan tree arg, decl = *node; 520132718Skan 521132718Skan init_idents (); 522132718Skan arg = TREE_VALUE (args); 523132718Skan if (arg == small_ident1 || arg == small_ident2) 524132718Skan { 525132718Skan addr_area = ADDR_AREA_SMALL; 526132718Skan } 527132718Skan else 528132718Skan { 529169689Skan warning (OPT_Wattributes, "invalid argument of %qs attribute", 530132718Skan IDENTIFIER_POINTER (name)); 531132718Skan *no_add_attrs = true; 532132718Skan } 533132718Skan 534132718Skan switch (TREE_CODE (decl)) 535132718Skan { 536132718Skan case VAR_DECL: 537132718Skan if ((DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) 538132718Skan == FUNCTION_DECL) 539132718Skan && !TREE_STATIC (decl)) 540132718Skan { 541132718Skan error ("%Jan address area attribute cannot be specified for " 542169689Skan "local variables", decl); 543132718Skan *no_add_attrs = true; 544132718Skan } 545132718Skan area = ia64_get_addr_area (decl); 546132718Skan if (area != ADDR_AREA_NORMAL && addr_area != area) 547132718Skan { 548169689Skan error ("address area of %q+D conflicts with previous " 549169689Skan "declaration", decl); 550132718Skan *no_add_attrs = true; 551132718Skan } 552132718Skan break; 553132718Skan 554132718Skan case FUNCTION_DECL: 555132718Skan error ("%Jaddress area attribute cannot be specified for functions", 556169689Skan decl); 557132718Skan *no_add_attrs = true; 558132718Skan break; 559132718Skan 560132718Skan default: 561169689Skan warning (OPT_Wattributes, "%qs attribute ignored", 562169689Skan IDENTIFIER_POINTER (name)); 563132718Skan *no_add_attrs = true; 564132718Skan break; 565132718Skan } 566132718Skan 567132718Skan return NULL_TREE; 568132718Skan} 569132718Skan 570132718Skanstatic void 571132718Skania64_encode_addr_area (tree decl, rtx symbol) 572132718Skan{ 573132718Skan int flags; 574132718Skan 575132718Skan flags = SYMBOL_REF_FLAGS (symbol); 576132718Skan switch (ia64_get_addr_area (decl)) 577132718Skan { 578132718Skan case ADDR_AREA_NORMAL: break; 579132718Skan case ADDR_AREA_SMALL: flags |= SYMBOL_FLAG_SMALL_ADDR; break; 580169689Skan default: gcc_unreachable (); 581132718Skan } 582132718Skan SYMBOL_REF_FLAGS (symbol) = flags; 583132718Skan} 584132718Skan 585132718Skanstatic void 586132718Skania64_encode_section_info (tree decl, rtx rtl, int first) 587132718Skan{ 588132718Skan default_encode_section_info (decl, rtl, first); 589132718Skan 590132718Skan /* Careful not to prod global register variables. */ 591132718Skan if (TREE_CODE (decl) == VAR_DECL 592132718Skan && GET_CODE (DECL_RTL (decl)) == MEM 593132718Skan && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF 594132718Skan && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) 595132718Skan ia64_encode_addr_area (decl, XEXP (rtl, 0)); 596132718Skan} 597132718Skan 598169689Skan/* Implement CONST_OK_FOR_LETTER_P. */ 599169689Skan 600169689Skanbool 601169689Skania64_const_ok_for_letter_p (HOST_WIDE_INT value, char c) 602169689Skan{ 603169689Skan switch (c) 604169689Skan { 605169689Skan case 'I': 606169689Skan return CONST_OK_FOR_I (value); 607169689Skan case 'J': 608169689Skan return CONST_OK_FOR_J (value); 609169689Skan case 'K': 610169689Skan return CONST_OK_FOR_K (value); 611169689Skan case 'L': 612169689Skan return CONST_OK_FOR_L (value); 613169689Skan case 'M': 614169689Skan return CONST_OK_FOR_M (value); 615169689Skan case 'N': 616169689Skan return CONST_OK_FOR_N (value); 617169689Skan case 'O': 618169689Skan return CONST_OK_FOR_O (value); 619169689Skan case 'P': 620169689Skan return CONST_OK_FOR_P (value); 621169689Skan default: 622169689Skan return false; 623169689Skan } 624169689Skan} 625169689Skan 626169689Skan/* Implement CONST_DOUBLE_OK_FOR_LETTER_P. */ 627169689Skan 628169689Skanbool 629169689Skania64_const_double_ok_for_letter_p (rtx value, char c) 630169689Skan{ 631169689Skan switch (c) 632169689Skan { 633169689Skan case 'G': 634169689Skan return CONST_DOUBLE_OK_FOR_G (value); 635169689Skan default: 636169689Skan return false; 637169689Skan } 638169689Skan} 639169689Skan 640169689Skan/* Implement EXTRA_CONSTRAINT. */ 641169689Skan 642169689Skanbool 643169689Skania64_extra_constraint (rtx value, char c) 644169689Skan{ 645169689Skan switch (c) 646169689Skan { 647169689Skan case 'Q': 648169689Skan /* Non-volatile memory for FP_REG loads/stores. */ 649169689Skan return memory_operand(value, VOIDmode) && !MEM_VOLATILE_P (value); 650169689Skan 651169689Skan case 'R': 652169689Skan /* 1..4 for shladd arguments. */ 653169689Skan return (GET_CODE (value) == CONST_INT 654169689Skan && INTVAL (value) >= 1 && INTVAL (value) <= 4); 655169689Skan 656169689Skan case 'S': 657169689Skan /* Non-post-inc memory for asms and other unsavory creatures. */ 658169689Skan return (GET_CODE (value) == MEM 659169689Skan && GET_RTX_CLASS (GET_CODE (XEXP (value, 0))) != RTX_AUTOINC 660169689Skan && (reload_in_progress || memory_operand (value, VOIDmode))); 661169689Skan 662169689Skan case 'T': 663169689Skan /* Symbol ref to small-address-area. */ 664169689Skan return small_addr_symbolic_operand (value, VOIDmode); 665169689Skan 666169689Skan case 'U': 667169689Skan /* Vector zero. */ 668169689Skan return value == CONST0_RTX (GET_MODE (value)); 669169689Skan 670169689Skan case 'W': 671169689Skan /* An integer vector, such that conversion to an integer yields a 672169689Skan value appropriate for an integer 'J' constraint. */ 673169689Skan if (GET_CODE (value) == CONST_VECTOR 674169689Skan && GET_MODE_CLASS (GET_MODE (value)) == MODE_VECTOR_INT) 675169689Skan { 676169689Skan value = simplify_subreg (DImode, value, GET_MODE (value), 0); 677169689Skan return ia64_const_ok_for_letter_p (INTVAL (value), 'J'); 678169689Skan } 679169689Skan return false; 680169689Skan 681169689Skan case 'Y': 682169689Skan /* A V2SF vector containing elements that satisfy 'G'. */ 683169689Skan return 684169689Skan (GET_CODE (value) == CONST_VECTOR 685169689Skan && GET_MODE (value) == V2SFmode 686169689Skan && ia64_const_double_ok_for_letter_p (XVECEXP (value, 0, 0), 'G') 687169689Skan && ia64_const_double_ok_for_letter_p (XVECEXP (value, 0, 1), 'G')); 688169689Skan 689169689Skan default: 690169689Skan return false; 691169689Skan } 692169689Skan} 693169689Skan 69490075Sobrien/* Return 1 if the operands of a move are ok. */ 69590075Sobrien 69690075Sobrienint 697132718Skania64_move_ok (rtx dst, rtx src) 69890075Sobrien{ 69990075Sobrien /* If we're under init_recog_no_volatile, we'll not be able to use 70090075Sobrien memory_operand. So check the code directly and don't worry about 70190075Sobrien the validity of the underlying address, which should have been 70290075Sobrien checked elsewhere anyway. */ 70390075Sobrien if (GET_CODE (dst) != MEM) 70490075Sobrien return 1; 70590075Sobrien if (GET_CODE (src) == MEM) 70690075Sobrien return 0; 70790075Sobrien if (register_operand (src, VOIDmode)) 70890075Sobrien return 1; 70990075Sobrien 71090075Sobrien /* Otherwise, this must be a constant, and that either 0 or 0.0 or 1.0. */ 71190075Sobrien if (INTEGRAL_MODE_P (GET_MODE (dst))) 71290075Sobrien return src == const0_rtx; 71390075Sobrien else 71490075Sobrien return GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src); 71590075Sobrien} 71690075Sobrien 717169689Skan/* Return 1 if the operands are ok for a floating point load pair. */ 718169689Skan 719117395Skanint 720169689Skania64_load_pair_ok (rtx dst, rtx src) 721169689Skan{ 722169689Skan if (GET_CODE (dst) != REG || !FP_REGNO_P (REGNO (dst))) 723169689Skan return 0; 724169689Skan if (GET_CODE (src) != MEM || MEM_VOLATILE_P (src)) 725169689Skan return 0; 726169689Skan switch (GET_CODE (XEXP (src, 0))) 727169689Skan { 728169689Skan case REG: 729169689Skan case POST_INC: 730169689Skan break; 731169689Skan case POST_DEC: 732169689Skan return 0; 733169689Skan case POST_MODIFY: 734169689Skan { 735169689Skan rtx adjust = XEXP (XEXP (XEXP (src, 0), 1), 1); 736169689Skan 737169689Skan if (GET_CODE (adjust) != CONST_INT 738169689Skan || INTVAL (adjust) != GET_MODE_SIZE (GET_MODE (src))) 739169689Skan return 0; 740169689Skan } 741169689Skan break; 742169689Skan default: 743169689Skan abort (); 744169689Skan } 745169689Skan return 1; 746169689Skan} 747169689Skan 748169689Skanint 749132718Skanaddp4_optimize_ok (rtx op1, rtx op2) 750117395Skan{ 751117395Skan return (basereg_operand (op1, GET_MODE(op1)) != 752117395Skan basereg_operand (op2, GET_MODE(op2))); 753117395Skan} 754117395Skan 755132718Skan/* Check if OP is a mask suitable for use with SHIFT in a dep.z instruction. 75690075Sobrien Return the length of the field, or <= 0 on failure. */ 75790075Sobrien 75890075Sobrienint 759132718Skania64_depz_field_mask (rtx rop, rtx rshift) 76090075Sobrien{ 76190075Sobrien unsigned HOST_WIDE_INT op = INTVAL (rop); 76290075Sobrien unsigned HOST_WIDE_INT shift = INTVAL (rshift); 76390075Sobrien 76490075Sobrien /* Get rid of the zero bits we're shifting in. */ 76590075Sobrien op >>= shift; 76690075Sobrien 76790075Sobrien /* We must now have a solid block of 1's at bit 0. */ 76890075Sobrien return exact_log2 (op + 1); 76990075Sobrien} 77090075Sobrien 771169689Skan/* Return the TLS model to use for ADDR. */ 772169689Skan 773169689Skanstatic enum tls_model 774169689Skantls_symbolic_operand_type (rtx addr) 775169689Skan{ 776169689Skan enum tls_model tls_kind = 0; 777169689Skan 778169689Skan if (GET_CODE (addr) == CONST) 779169689Skan { 780169689Skan if (GET_CODE (XEXP (addr, 0)) == PLUS 781169689Skan && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF) 782169689Skan tls_kind = SYMBOL_REF_TLS_MODEL (XEXP (XEXP (addr, 0), 0)); 783169689Skan } 784169689Skan else if (GET_CODE (addr) == SYMBOL_REF) 785169689Skan tls_kind = SYMBOL_REF_TLS_MODEL (addr); 786169689Skan 787169689Skan return tls_kind; 788169689Skan} 789169689Skan 790169689Skan/* Return true if X is a constant that is valid for some immediate 791169689Skan field in an instruction. */ 792169689Skan 793169689Skanbool 794169689Skania64_legitimate_constant_p (rtx x) 795169689Skan{ 796169689Skan switch (GET_CODE (x)) 797169689Skan { 798169689Skan case CONST_INT: 799169689Skan case LABEL_REF: 800169689Skan return true; 801169689Skan 802169689Skan case CONST_DOUBLE: 803169689Skan if (GET_MODE (x) == VOIDmode) 804169689Skan return true; 805169689Skan return CONST_DOUBLE_OK_FOR_G (x); 806169689Skan 807169689Skan case CONST: 808169689Skan case SYMBOL_REF: 809169689Skan /* ??? Short term workaround for PR 28490. We must make the code here 810169689Skan match the code in ia64_expand_move and move_operand, even though they 811169689Skan are both technically wrong. */ 812169689Skan if (tls_symbolic_operand_type (x) == 0) 813169689Skan { 814169689Skan HOST_WIDE_INT addend = 0; 815169689Skan rtx op = x; 816169689Skan 817169689Skan if (GET_CODE (op) == CONST 818169689Skan && GET_CODE (XEXP (op, 0)) == PLUS 819169689Skan && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) 820169689Skan { 821169689Skan addend = INTVAL (XEXP (XEXP (op, 0), 1)); 822169689Skan op = XEXP (XEXP (op, 0), 0); 823169689Skan } 824169689Skan 825169689Skan if (any_offset_symbol_operand (op, GET_MODE (op)) 826169689Skan || function_operand (op, GET_MODE (op))) 827169689Skan return true; 828169689Skan if (aligned_offset_symbol_operand (op, GET_MODE (op))) 829169689Skan return (addend & 0x3fff) == 0; 830169689Skan return false; 831169689Skan } 832169689Skan return false; 833169689Skan 834169689Skan case CONST_VECTOR: 835169689Skan { 836169689Skan enum machine_mode mode = GET_MODE (x); 837169689Skan 838169689Skan if (mode == V2SFmode) 839169689Skan return ia64_extra_constraint (x, 'Y'); 840169689Skan 841169689Skan return (GET_MODE_CLASS (mode) == MODE_VECTOR_INT 842169689Skan && GET_MODE_SIZE (mode) <= 8); 843169689Skan } 844169689Skan 845169689Skan default: 846169689Skan return false; 847169689Skan } 848169689Skan} 849169689Skan 850169689Skan/* Don't allow TLS addresses to get spilled to memory. */ 851169689Skan 852169689Skanstatic bool 853169689Skania64_cannot_force_const_mem (rtx x) 854169689Skan{ 855169689Skan return tls_symbolic_operand_type (x) != 0; 856169689Skan} 857169689Skan 85890075Sobrien/* Expand a symbolic constant load. */ 85990075Sobrien 860169689Skanbool 861132718Skania64_expand_load_address (rtx dest, rtx src) 86290075Sobrien{ 863169689Skan gcc_assert (GET_CODE (dest) == REG); 86490075Sobrien 865132718Skan /* ILP32 mode still loads 64-bits of data from the GOT. This avoids 866132718Skan having to pointer-extend the value afterward. Other forms of address 867132718Skan computation below are also more natural to compute as 64-bit quantities. 868132718Skan If we've been given an SImode destination register, change it. */ 869132718Skan if (GET_MODE (dest) != Pmode) 870169689Skan dest = gen_rtx_REG_offset (dest, Pmode, REGNO (dest), 0); 87190075Sobrien 872169689Skan if (TARGET_NO_PIC) 873169689Skan return false; 874169689Skan if (small_addr_symbolic_operand (src, VOIDmode)) 875169689Skan return false; 876169689Skan 877169689Skan if (TARGET_AUTO_PIC) 878169689Skan emit_insn (gen_load_gprel64 (dest, src)); 879132718Skan else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (src)) 880169689Skan emit_insn (gen_load_fptr (dest, src)); 881132718Skan else if (sdata_symbolic_operand (src, VOIDmode)) 882169689Skan emit_insn (gen_load_gprel (dest, src)); 883169689Skan else 884132718Skan { 885169689Skan HOST_WIDE_INT addend = 0; 886169689Skan rtx tmp; 887117395Skan 888169689Skan /* We did split constant offsets in ia64_expand_move, and we did try 889169689Skan to keep them split in move_operand, but we also allowed reload to 890169689Skan rematerialize arbitrary constants rather than spill the value to 891169689Skan the stack and reload it. So we have to be prepared here to split 892169689Skan them apart again. */ 893169689Skan if (GET_CODE (src) == CONST) 894169689Skan { 895169689Skan HOST_WIDE_INT hi, lo; 89690075Sobrien 897169689Skan hi = INTVAL (XEXP (XEXP (src, 0), 1)); 898169689Skan lo = ((hi & 0x3fff) ^ 0x2000) - 0x2000; 899169689Skan hi = hi - lo; 90090075Sobrien 901169689Skan if (lo != 0) 902169689Skan { 903169689Skan addend = lo; 904169689Skan src = plus_constant (XEXP (XEXP (src, 0), 0), hi); 905169689Skan } 906169689Skan } 90790075Sobrien 908132718Skan tmp = gen_rtx_HIGH (Pmode, src); 909132718Skan tmp = gen_rtx_PLUS (Pmode, tmp, pic_offset_table_rtx); 910132718Skan emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); 91190075Sobrien 912169689Skan tmp = gen_rtx_LO_SUM (Pmode, dest, src); 913132718Skan emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); 914169689Skan 915169689Skan if (addend) 916169689Skan { 917169689Skan tmp = gen_rtx_PLUS (Pmode, dest, GEN_INT (addend)); 918169689Skan emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); 919169689Skan } 920117395Skan } 921169689Skan 922169689Skan return true; 92390075Sobrien} 92490075Sobrien 925117395Skanstatic GTY(()) rtx gen_tls_tga; 926117395Skanstatic rtx 927132718Skangen_tls_get_addr (void) 928117395Skan{ 929117395Skan if (!gen_tls_tga) 930132718Skan gen_tls_tga = init_one_libfunc ("__tls_get_addr"); 931117395Skan return gen_tls_tga; 932117395Skan} 933117395Skan 934117395Skanstatic GTY(()) rtx thread_pointer_rtx; 935117395Skanstatic rtx 936132718Skangen_thread_pointer (void) 937117395Skan{ 938117395Skan if (!thread_pointer_rtx) 939169689Skan thread_pointer_rtx = gen_rtx_REG (Pmode, 13); 940117395Skan return thread_pointer_rtx; 941117395Skan} 942117395Skan 943132718Skanstatic rtx 944169689Skania64_expand_tls_address (enum tls_model tls_kind, rtx op0, rtx op1, 945169689Skan rtx orig_op1, HOST_WIDE_INT addend) 94690075Sobrien{ 947132718Skan rtx tga_op1, tga_op2, tga_ret, tga_eqv, tmp, insns; 948132718Skan rtx orig_op0 = op0; 949169689Skan HOST_WIDE_INT addend_lo, addend_hi; 95090075Sobrien 951132718Skan switch (tls_kind) 95290075Sobrien { 953132718Skan case TLS_MODEL_GLOBAL_DYNAMIC: 954132718Skan start_sequence (); 95590075Sobrien 956132718Skan tga_op1 = gen_reg_rtx (Pmode); 957169689Skan emit_insn (gen_load_dtpmod (tga_op1, op1)); 958117395Skan 959132718Skan tga_op2 = gen_reg_rtx (Pmode); 960169689Skan emit_insn (gen_load_dtprel (tga_op2, op1)); 961117395Skan 962132718Skan tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX, 963132718Skan LCT_CONST, Pmode, 2, tga_op1, 964132718Skan Pmode, tga_op2, Pmode); 965117395Skan 966132718Skan insns = get_insns (); 967132718Skan end_sequence (); 968117395Skan 969132718Skan if (GET_MODE (op0) != Pmode) 970132718Skan op0 = tga_ret; 971132718Skan emit_libcall_block (insns, op0, tga_ret, op1); 972132718Skan break; 973117395Skan 974132718Skan case TLS_MODEL_LOCAL_DYNAMIC: 975132718Skan /* ??? This isn't the completely proper way to do local-dynamic 976132718Skan If the call to __tls_get_addr is used only by a single symbol, 977132718Skan then we should (somehow) move the dtprel to the second arg 978132718Skan to avoid the extra add. */ 979132718Skan start_sequence (); 980117395Skan 981132718Skan tga_op1 = gen_reg_rtx (Pmode); 982169689Skan emit_insn (gen_load_dtpmod (tga_op1, op1)); 983117395Skan 984132718Skan tga_op2 = const0_rtx; 985117395Skan 986132718Skan tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX, 987132718Skan LCT_CONST, Pmode, 2, tga_op1, 988132718Skan Pmode, tga_op2, Pmode); 989117395Skan 990132718Skan insns = get_insns (); 991132718Skan end_sequence (); 992117395Skan 993132718Skan tga_eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), 994132718Skan UNSPEC_LD_BASE); 995132718Skan tmp = gen_reg_rtx (Pmode); 996132718Skan emit_libcall_block (insns, tmp, tga_ret, tga_eqv); 997117395Skan 998132718Skan if (!register_operand (op0, Pmode)) 999132718Skan op0 = gen_reg_rtx (Pmode); 1000132718Skan if (TARGET_TLS64) 1001132718Skan { 1002132718Skan emit_insn (gen_load_dtprel (op0, op1)); 1003132718Skan emit_insn (gen_adddi3 (op0, tmp, op0)); 1004132718Skan } 1005132718Skan else 1006169689Skan emit_insn (gen_add_dtprel (op0, op1, tmp)); 1007132718Skan break; 1008117395Skan 1009132718Skan case TLS_MODEL_INITIAL_EXEC: 1010169689Skan addend_lo = ((addend & 0x3fff) ^ 0x2000) - 0x2000; 1011169689Skan addend_hi = addend - addend_lo; 1012169689Skan 1013169689Skan op1 = plus_constant (op1, addend_hi); 1014169689Skan addend = addend_lo; 1015169689Skan 1016132718Skan tmp = gen_reg_rtx (Pmode); 1017169689Skan emit_insn (gen_load_tprel (tmp, op1)); 1018117395Skan 1019132718Skan if (!register_operand (op0, Pmode)) 1020132718Skan op0 = gen_reg_rtx (Pmode); 1021132718Skan emit_insn (gen_adddi3 (op0, tmp, gen_thread_pointer ())); 1022132718Skan break; 1023117395Skan 1024132718Skan case TLS_MODEL_LOCAL_EXEC: 1025132718Skan if (!register_operand (op0, Pmode)) 1026132718Skan op0 = gen_reg_rtx (Pmode); 1027169689Skan 1028169689Skan op1 = orig_op1; 1029169689Skan addend = 0; 1030132718Skan if (TARGET_TLS64) 1031132718Skan { 1032132718Skan emit_insn (gen_load_tprel (op0, op1)); 1033169689Skan emit_insn (gen_adddi3 (op0, op0, gen_thread_pointer ())); 1034132718Skan } 1035132718Skan else 1036169689Skan emit_insn (gen_add_tprel (op0, op1, gen_thread_pointer ())); 1037132718Skan break; 1038117395Skan 1039132718Skan default: 1040169689Skan gcc_unreachable (); 1041132718Skan } 1042122180Skan 1043169689Skan if (addend) 1044169689Skan op0 = expand_simple_binop (Pmode, PLUS, op0, GEN_INT (addend), 1045169689Skan orig_op0, 1, OPTAB_DIRECT); 1046132718Skan if (orig_op0 == op0) 1047132718Skan return NULL_RTX; 1048132718Skan if (GET_MODE (orig_op0) == Pmode) 1049132718Skan return op0; 1050132718Skan return gen_lowpart (GET_MODE (orig_op0), op0); 1051132718Skan} 1052117395Skan 1053132718Skanrtx 1054132718Skania64_expand_move (rtx op0, rtx op1) 1055132718Skan{ 1056132718Skan enum machine_mode mode = GET_MODE (op0); 1057117395Skan 1058132718Skan if (!reload_in_progress && !reload_completed && !ia64_move_ok (op0, op1)) 1059132718Skan op1 = force_reg (mode, op1); 1060117395Skan 1061132718Skan if ((mode == Pmode || mode == ptr_mode) && symbolic_operand (op1, VOIDmode)) 1062132718Skan { 1063169689Skan HOST_WIDE_INT addend = 0; 1064132718Skan enum tls_model tls_kind; 1065169689Skan rtx sym = op1; 1066132718Skan 1067169689Skan if (GET_CODE (op1) == CONST 1068169689Skan && GET_CODE (XEXP (op1, 0)) == PLUS 1069169689Skan && GET_CODE (XEXP (XEXP (op1, 0), 1)) == CONST_INT) 1070132718Skan { 1071169689Skan addend = INTVAL (XEXP (XEXP (op1, 0), 1)); 1072169689Skan sym = XEXP (XEXP (op1, 0), 0); 1073117395Skan } 1074169689Skan 1075169689Skan tls_kind = tls_symbolic_operand_type (sym); 1076169689Skan if (tls_kind) 1077169689Skan return ia64_expand_tls_address (tls_kind, op0, sym, op1, addend); 1078169689Skan 1079169689Skan if (any_offset_symbol_operand (sym, mode)) 1080169689Skan addend = 0; 1081169689Skan else if (aligned_offset_symbol_operand (sym, mode)) 1082169689Skan { 1083169689Skan HOST_WIDE_INT addend_lo, addend_hi; 1084169689Skan 1085169689Skan addend_lo = ((addend & 0x3fff) ^ 0x2000) - 0x2000; 1086169689Skan addend_hi = addend - addend_lo; 1087169689Skan 1088169689Skan if (addend_lo != 0) 1089169689Skan { 1090169689Skan op1 = plus_constant (sym, addend_hi); 1091169689Skan addend = addend_lo; 1092169689Skan } 1093169689Skan else 1094169689Skan addend = 0; 1095169689Skan } 1096169689Skan else 1097169689Skan op1 = sym; 1098169689Skan 1099169689Skan if (reload_completed) 1100169689Skan { 1101169689Skan /* We really should have taken care of this offset earlier. */ 1102169689Skan gcc_assert (addend == 0); 1103169689Skan if (ia64_expand_load_address (op0, op1)) 1104169689Skan return NULL_RTX; 1105169689Skan } 1106169689Skan 1107169689Skan if (addend) 1108169689Skan { 1109169689Skan rtx subtarget = no_new_pseudos ? op0 : gen_reg_rtx (mode); 1110169689Skan 1111169689Skan emit_insn (gen_rtx_SET (VOIDmode, subtarget, op1)); 1112169689Skan 1113169689Skan op1 = expand_simple_binop (mode, PLUS, subtarget, 1114169689Skan GEN_INT (addend), op0, 1, OPTAB_DIRECT); 1115169689Skan if (op0 == op1) 1116169689Skan return NULL_RTX; 1117169689Skan } 111890075Sobrien } 111990075Sobrien 1120117395Skan return op1; 112190075Sobrien} 112290075Sobrien 1123132718Skan/* Split a move from OP1 to OP0 conditional on COND. */ 112490075Sobrien 1125132718Skanvoid 1126132718Skania64_emit_cond_move (rtx op0, rtx op1, rtx cond) 112790075Sobrien{ 1128132718Skan rtx insn, first = get_last_insn (); 1129132718Skan 1130132718Skan emit_move_insn (op0, op1); 1131132718Skan 1132132718Skan for (insn = get_last_insn (); insn != first; insn = PREV_INSN (insn)) 1133132718Skan if (INSN_P (insn)) 1134132718Skan PATTERN (insn) = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), 1135132718Skan PATTERN (insn)); 1136132718Skan} 1137132718Skan 1138132718Skan/* Split a post-reload TImode or TFmode reference into two DImode 1139132718Skan components. This is made extra difficult by the fact that we do 1140132718Skan not get any scratch registers to work with, because reload cannot 1141132718Skan be prevented from giving us a scratch that overlaps the register 1142132718Skan pair involved. So instead, when addressing memory, we tweak the 1143132718Skan pointer register up and back down with POST_INCs. Or up and not 1144132718Skan back down when we can get away with it. 1145132718Skan 1146132718Skan REVERSED is true when the loads must be done in reversed order 1147132718Skan (high word first) for correctness. DEAD is true when the pointer 1148132718Skan dies with the second insn we generate and therefore the second 1149132718Skan address must not carry a postmodify. 1150132718Skan 1151132718Skan May return an insn which is to be emitted after the moves. */ 1152132718Skan 1153132718Skanstatic rtx 1154132718Skania64_split_tmode (rtx out[2], rtx in, bool reversed, bool dead) 1155132718Skan{ 1156132718Skan rtx fixup = 0; 1157132718Skan 115890075Sobrien switch (GET_CODE (in)) 115990075Sobrien { 116090075Sobrien case REG: 1161132718Skan out[reversed] = gen_rtx_REG (DImode, REGNO (in)); 1162132718Skan out[!reversed] = gen_rtx_REG (DImode, REGNO (in) + 1); 1163132718Skan break; 116490075Sobrien 1165132718Skan case CONST_INT: 1166132718Skan case CONST_DOUBLE: 1167132718Skan /* Cannot occur reversed. */ 1168169689Skan gcc_assert (!reversed); 1169132718Skan 1170132718Skan if (GET_MODE (in) != TFmode) 1171132718Skan split_double (in, &out[0], &out[1]); 1172132718Skan else 1173132718Skan /* split_double does not understand how to split a TFmode 1174132718Skan quantity into a pair of DImode constants. */ 1175132718Skan { 1176132718Skan REAL_VALUE_TYPE r; 1177132718Skan unsigned HOST_WIDE_INT p[2]; 1178132718Skan long l[4]; /* TFmode is 128 bits */ 1179132718Skan 1180132718Skan REAL_VALUE_FROM_CONST_DOUBLE (r, in); 1181132718Skan real_to_target (l, &r, TFmode); 1182132718Skan 1183132718Skan if (FLOAT_WORDS_BIG_ENDIAN) 1184132718Skan { 1185132718Skan p[0] = (((unsigned HOST_WIDE_INT) l[0]) << 32) + l[1]; 1186132718Skan p[1] = (((unsigned HOST_WIDE_INT) l[2]) << 32) + l[3]; 1187132718Skan } 1188132718Skan else 1189132718Skan { 1190132718Skan p[0] = (((unsigned HOST_WIDE_INT) l[3]) << 32) + l[2]; 1191132718Skan p[1] = (((unsigned HOST_WIDE_INT) l[1]) << 32) + l[0]; 1192132718Skan } 1193132718Skan out[0] = GEN_INT (p[0]); 1194132718Skan out[1] = GEN_INT (p[1]); 1195132718Skan } 1196132718Skan break; 1197132718Skan 119890075Sobrien case MEM: 119990075Sobrien { 120090075Sobrien rtx base = XEXP (in, 0); 1201132718Skan rtx offset; 120290075Sobrien 120390075Sobrien switch (GET_CODE (base)) 120490075Sobrien { 120590075Sobrien case REG: 1206132718Skan if (!reversed) 1207132718Skan { 1208132718Skan out[0] = adjust_automodify_address 1209132718Skan (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); 1210132718Skan out[1] = adjust_automodify_address 1211132718Skan (in, DImode, dead ? 0 : gen_rtx_POST_DEC (Pmode, base), 8); 1212132718Skan } 1213132718Skan else 1214132718Skan { 1215132718Skan /* Reversal requires a pre-increment, which can only 1216132718Skan be done as a separate insn. */ 1217132718Skan emit_insn (gen_adddi3 (base, base, GEN_INT (8))); 1218132718Skan out[0] = adjust_automodify_address 1219132718Skan (in, DImode, gen_rtx_POST_DEC (Pmode, base), 8); 1220132718Skan out[1] = adjust_address (in, DImode, 0); 1221132718Skan } 122290075Sobrien break; 122390075Sobrien 122490075Sobrien case POST_INC: 1225169689Skan gcc_assert (!reversed && !dead); 1226169689Skan 1227132718Skan /* Just do the increment in two steps. */ 1228132718Skan out[0] = adjust_automodify_address (in, DImode, 0, 0); 1229132718Skan out[1] = adjust_automodify_address (in, DImode, 0, 8); 123090075Sobrien break; 1231132718Skan 123290075Sobrien case POST_DEC: 1233169689Skan gcc_assert (!reversed && !dead); 1234169689Skan 1235132718Skan /* Add 8, subtract 24. */ 123690075Sobrien base = XEXP (base, 0); 1237132718Skan out[0] = adjust_automodify_address 1238132718Skan (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); 1239132718Skan out[1] = adjust_automodify_address 1240132718Skan (in, DImode, 1241132718Skan gen_rtx_POST_MODIFY (Pmode, base, plus_constant (base, -24)), 1242132718Skan 8); 124390075Sobrien break; 1244132718Skan 1245132718Skan case POST_MODIFY: 1246169689Skan gcc_assert (!reversed && !dead); 1247169689Skan 1248132718Skan /* Extract and adjust the modification. This case is 1249132718Skan trickier than the others, because we might have an 1250132718Skan index register, or we might have a combined offset that 1251132718Skan doesn't fit a signed 9-bit displacement field. We can 1252132718Skan assume the incoming expression is already legitimate. */ 1253132718Skan offset = XEXP (base, 1); 1254132718Skan base = XEXP (base, 0); 1255132718Skan 1256132718Skan out[0] = adjust_automodify_address 1257132718Skan (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); 1258132718Skan 1259132718Skan if (GET_CODE (XEXP (offset, 1)) == REG) 1260132718Skan { 1261132718Skan /* Can't adjust the postmodify to match. Emit the 1262132718Skan original, then a separate addition insn. */ 1263132718Skan out[1] = adjust_automodify_address (in, DImode, 0, 8); 1264132718Skan fixup = gen_adddi3 (base, base, GEN_INT (-8)); 1265132718Skan } 1266132718Skan else 1267132718Skan { 1268169689Skan gcc_assert (GET_CODE (XEXP (offset, 1)) == CONST_INT); 1269169689Skan if (INTVAL (XEXP (offset, 1)) < -256 + 8) 1270169689Skan { 1271169689Skan /* Again the postmodify cannot be made to match, 1272169689Skan but in this case it's more efficient to get rid 1273169689Skan of the postmodify entirely and fix up with an 1274169689Skan add insn. */ 1275169689Skan out[1] = adjust_automodify_address (in, DImode, base, 8); 1276169689Skan fixup = gen_adddi3 1277169689Skan (base, base, GEN_INT (INTVAL (XEXP (offset, 1)) - 8)); 1278169689Skan } 1279169689Skan else 1280169689Skan { 1281169689Skan /* Combined offset still fits in the displacement field. 1282169689Skan (We cannot overflow it at the high end.) */ 1283169689Skan out[1] = adjust_automodify_address 1284169689Skan (in, DImode, gen_rtx_POST_MODIFY 1285169689Skan (Pmode, base, gen_rtx_PLUS 1286169689Skan (Pmode, base, 1287169689Skan GEN_INT (INTVAL (XEXP (offset, 1)) - 8))), 1288169689Skan 8); 1289169689Skan } 1290132718Skan } 1291132718Skan break; 1292132718Skan 129390075Sobrien default: 1294169689Skan gcc_unreachable (); 129590075Sobrien } 1296132718Skan break; 129790075Sobrien } 129890075Sobrien 129990075Sobrien default: 1300169689Skan gcc_unreachable (); 130190075Sobrien } 1302132718Skan 1303132718Skan return fixup; 130490075Sobrien} 130590075Sobrien 1306132718Skan/* Split a TImode or TFmode move instruction after reload. 1307132718Skan This is used by *movtf_internal and *movti_internal. */ 1308132718Skanvoid 1309132718Skania64_split_tmode_move (rtx operands[]) 1310132718Skan{ 1311132718Skan rtx in[2], out[2], insn; 1312132718Skan rtx fixup[2]; 1313132718Skan bool dead = false; 1314132718Skan bool reversed = false; 1315132718Skan 1316132718Skan /* It is possible for reload to decide to overwrite a pointer with 1317132718Skan the value it points to. In that case we have to do the loads in 1318132718Skan the appropriate order so that the pointer is not destroyed too 1319132718Skan early. Also we must not generate a postmodify for that second 1320169689Skan load, or rws_access_regno will die. */ 1321132718Skan if (GET_CODE (operands[1]) == MEM 1322132718Skan && reg_overlap_mentioned_p (operands[0], operands[1])) 1323132718Skan { 1324132718Skan rtx base = XEXP (operands[1], 0); 1325132718Skan while (GET_CODE (base) != REG) 1326132718Skan base = XEXP (base, 0); 1327132718Skan 1328132718Skan if (REGNO (base) == REGNO (operands[0])) 1329132718Skan reversed = true; 1330132718Skan dead = true; 1331132718Skan } 1332132718Skan /* Another reason to do the moves in reversed order is if the first 1333132718Skan element of the target register pair is also the second element of 1334132718Skan the source register pair. */ 1335132718Skan if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG 1336132718Skan && REGNO (operands[0]) == REGNO (operands[1]) + 1) 1337132718Skan reversed = true; 1338132718Skan 1339132718Skan fixup[0] = ia64_split_tmode (in, operands[1], reversed, dead); 1340132718Skan fixup[1] = ia64_split_tmode (out, operands[0], reversed, dead); 1341132718Skan 1342132718Skan#define MAYBE_ADD_REG_INC_NOTE(INSN, EXP) \ 1343132718Skan if (GET_CODE (EXP) == MEM \ 1344132718Skan && (GET_CODE (XEXP (EXP, 0)) == POST_MODIFY \ 1345132718Skan || GET_CODE (XEXP (EXP, 0)) == POST_INC \ 1346132718Skan || GET_CODE (XEXP (EXP, 0)) == POST_DEC)) \ 1347132718Skan REG_NOTES (INSN) = gen_rtx_EXPR_LIST (REG_INC, \ 1348132718Skan XEXP (XEXP (EXP, 0), 0), \ 1349132718Skan REG_NOTES (INSN)) 1350132718Skan 1351132718Skan insn = emit_insn (gen_rtx_SET (VOIDmode, out[0], in[0])); 1352132718Skan MAYBE_ADD_REG_INC_NOTE (insn, in[0]); 1353132718Skan MAYBE_ADD_REG_INC_NOTE (insn, out[0]); 1354132718Skan 1355132718Skan insn = emit_insn (gen_rtx_SET (VOIDmode, out[1], in[1])); 1356132718Skan MAYBE_ADD_REG_INC_NOTE (insn, in[1]); 1357132718Skan MAYBE_ADD_REG_INC_NOTE (insn, out[1]); 1358132718Skan 1359132718Skan if (fixup[0]) 1360132718Skan emit_insn (fixup[0]); 1361132718Skan if (fixup[1]) 1362132718Skan emit_insn (fixup[1]); 1363132718Skan 1364132718Skan#undef MAYBE_ADD_REG_INC_NOTE 1365132718Skan} 1366132718Skan 1367132718Skan/* ??? Fixing GR->FR XFmode moves during reload is hard. You need to go 136890075Sobrien through memory plus an extra GR scratch register. Except that you can 136990075Sobrien either get the first from SECONDARY_MEMORY_NEEDED or the second from 137090075Sobrien SECONDARY_RELOAD_CLASS, but not both. 137190075Sobrien 137290075Sobrien We got into problems in the first place by allowing a construct like 1373132718Skan (subreg:XF (reg:TI)), which we got from a union containing a long double. 137490075Sobrien This solution attempts to prevent this situation from occurring. When 137590075Sobrien we see something like the above, we spill the inner register to memory. */ 137690075Sobrien 1377169689Skanstatic rtx 1378169689Skanspill_xfmode_rfmode_operand (rtx in, int force, enum machine_mode mode) 137990075Sobrien{ 138090075Sobrien if (GET_CODE (in) == SUBREG 138190075Sobrien && GET_MODE (SUBREG_REG (in)) == TImode 138290075Sobrien && GET_CODE (SUBREG_REG (in)) == REG) 138390075Sobrien { 1384169689Skan rtx memt = assign_stack_temp (TImode, 16, 0); 1385169689Skan emit_move_insn (memt, SUBREG_REG (in)); 1386169689Skan return adjust_address (memt, mode, 0); 138790075Sobrien } 138890075Sobrien else if (force && GET_CODE (in) == REG) 138990075Sobrien { 1390169689Skan rtx memx = assign_stack_temp (mode, 16, 0); 1391169689Skan emit_move_insn (memx, in); 1392169689Skan return memx; 139390075Sobrien } 139490075Sobrien else 139590075Sobrien return in; 139690075Sobrien} 139790075Sobrien 1398169689Skan/* Expand the movxf or movrf pattern (MODE says which) with the given 1399169689Skan OPERANDS, returning true if the pattern should then invoke 1400169689Skan DONE. */ 1401169689Skan 1402169689Skanbool 1403169689Skania64_expand_movxf_movrf (enum machine_mode mode, rtx operands[]) 1404169689Skan{ 1405169689Skan rtx op0 = operands[0]; 1406169689Skan 1407169689Skan if (GET_CODE (op0) == SUBREG) 1408169689Skan op0 = SUBREG_REG (op0); 1409169689Skan 1410169689Skan /* We must support XFmode loads into general registers for stdarg/vararg, 1411169689Skan unprototyped calls, and a rare case where a long double is passed as 1412169689Skan an argument after a float HFA fills the FP registers. We split them into 1413169689Skan DImode loads for convenience. We also need to support XFmode stores 1414169689Skan for the last case. This case does not happen for stdarg/vararg routines, 1415169689Skan because we do a block store to memory of unnamed arguments. */ 1416169689Skan 1417169689Skan if (GET_CODE (op0) == REG && GR_REGNO_P (REGNO (op0))) 1418169689Skan { 1419169689Skan rtx out[2]; 1420169689Skan 1421169689Skan /* We're hoping to transform everything that deals with XFmode 1422169689Skan quantities and GR registers early in the compiler. */ 1423169689Skan gcc_assert (!no_new_pseudos); 1424169689Skan 1425169689Skan /* Struct to register can just use TImode instead. */ 1426169689Skan if ((GET_CODE (operands[1]) == SUBREG 1427169689Skan && GET_MODE (SUBREG_REG (operands[1])) == TImode) 1428169689Skan || (GET_CODE (operands[1]) == REG 1429169689Skan && GR_REGNO_P (REGNO (operands[1])))) 1430169689Skan { 1431169689Skan rtx op1 = operands[1]; 1432169689Skan 1433169689Skan if (GET_CODE (op1) == SUBREG) 1434169689Skan op1 = SUBREG_REG (op1); 1435169689Skan else 1436169689Skan op1 = gen_rtx_REG (TImode, REGNO (op1)); 1437169689Skan 1438169689Skan emit_move_insn (gen_rtx_REG (TImode, REGNO (op0)), op1); 1439169689Skan return true; 1440169689Skan } 1441169689Skan 1442169689Skan if (GET_CODE (operands[1]) == CONST_DOUBLE) 1443169689Skan { 1444169689Skan /* Don't word-swap when reading in the constant. */ 1445169689Skan emit_move_insn (gen_rtx_REG (DImode, REGNO (op0)), 1446169689Skan operand_subword (operands[1], WORDS_BIG_ENDIAN, 1447169689Skan 0, mode)); 1448169689Skan emit_move_insn (gen_rtx_REG (DImode, REGNO (op0) + 1), 1449169689Skan operand_subword (operands[1], !WORDS_BIG_ENDIAN, 1450169689Skan 0, mode)); 1451169689Skan return true; 1452169689Skan } 1453169689Skan 1454169689Skan /* If the quantity is in a register not known to be GR, spill it. */ 1455169689Skan if (register_operand (operands[1], mode)) 1456169689Skan operands[1] = spill_xfmode_rfmode_operand (operands[1], 1, mode); 1457169689Skan 1458169689Skan gcc_assert (GET_CODE (operands[1]) == MEM); 1459169689Skan 1460169689Skan /* Don't word-swap when reading in the value. */ 1461169689Skan out[0] = gen_rtx_REG (DImode, REGNO (op0)); 1462169689Skan out[1] = gen_rtx_REG (DImode, REGNO (op0) + 1); 1463169689Skan 1464169689Skan emit_move_insn (out[0], adjust_address (operands[1], DImode, 0)); 1465169689Skan emit_move_insn (out[1], adjust_address (operands[1], DImode, 8)); 1466169689Skan return true; 1467169689Skan } 1468169689Skan 1469169689Skan if (GET_CODE (operands[1]) == REG && GR_REGNO_P (REGNO (operands[1]))) 1470169689Skan { 1471169689Skan /* We're hoping to transform everything that deals with XFmode 1472169689Skan quantities and GR registers early in the compiler. */ 1473169689Skan gcc_assert (!no_new_pseudos); 1474169689Skan 1475169689Skan /* Op0 can't be a GR_REG here, as that case is handled above. 1476169689Skan If op0 is a register, then we spill op1, so that we now have a 1477169689Skan MEM operand. This requires creating an XFmode subreg of a TImode reg 1478169689Skan to force the spill. */ 1479169689Skan if (register_operand (operands[0], mode)) 1480169689Skan { 1481169689Skan rtx op1 = gen_rtx_REG (TImode, REGNO (operands[1])); 1482169689Skan op1 = gen_rtx_SUBREG (mode, op1, 0); 1483169689Skan operands[1] = spill_xfmode_rfmode_operand (op1, 0, mode); 1484169689Skan } 1485169689Skan 1486169689Skan else 1487169689Skan { 1488169689Skan rtx in[2]; 1489169689Skan 1490169689Skan gcc_assert (GET_CODE (operands[0]) == MEM); 1491169689Skan 1492169689Skan /* Don't word-swap when writing out the value. */ 1493169689Skan in[0] = gen_rtx_REG (DImode, REGNO (operands[1])); 1494169689Skan in[1] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1); 1495169689Skan 1496169689Skan emit_move_insn (adjust_address (operands[0], DImode, 0), in[0]); 1497169689Skan emit_move_insn (adjust_address (operands[0], DImode, 8), in[1]); 1498169689Skan return true; 1499169689Skan } 1500169689Skan } 1501169689Skan 1502169689Skan if (!reload_in_progress && !reload_completed) 1503169689Skan { 1504169689Skan operands[1] = spill_xfmode_rfmode_operand (operands[1], 0, mode); 1505169689Skan 1506169689Skan if (GET_MODE (op0) == TImode && GET_CODE (op0) == REG) 1507169689Skan { 1508169689Skan rtx memt, memx, in = operands[1]; 1509169689Skan if (CONSTANT_P (in)) 1510169689Skan in = validize_mem (force_const_mem (mode, in)); 1511169689Skan if (GET_CODE (in) == MEM) 1512169689Skan memt = adjust_address (in, TImode, 0); 1513169689Skan else 1514169689Skan { 1515169689Skan memt = assign_stack_temp (TImode, 16, 0); 1516169689Skan memx = adjust_address (memt, mode, 0); 1517169689Skan emit_move_insn (memx, in); 1518169689Skan } 1519169689Skan emit_move_insn (op0, memt); 1520169689Skan return true; 1521169689Skan } 1522169689Skan 1523169689Skan if (!ia64_move_ok (operands[0], operands[1])) 1524169689Skan operands[1] = force_reg (mode, operands[1]); 1525169689Skan } 1526169689Skan 1527169689Skan return false; 1528169689Skan} 1529169689Skan 153090075Sobrien/* Emit comparison instruction if necessary, returning the expression 153190075Sobrien that holds the compare result in the proper mode. */ 153290075Sobrien 1533132718Skanstatic GTY(()) rtx cmptf_libfunc; 1534132718Skan 153590075Sobrienrtx 1536132718Skania64_expand_compare (enum rtx_code code, enum machine_mode mode) 153790075Sobrien{ 153890075Sobrien rtx op0 = ia64_compare_op0, op1 = ia64_compare_op1; 153990075Sobrien rtx cmp; 154090075Sobrien 154190075Sobrien /* If we have a BImode input, then we already have a compare result, and 154290075Sobrien do not need to emit another comparison. */ 154390075Sobrien if (GET_MODE (op0) == BImode) 154490075Sobrien { 1545169689Skan gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx); 1546169689Skan cmp = op0; 154790075Sobrien } 1548132718Skan /* HPUX TFmode compare requires a library call to _U_Qfcmp, which takes a 1549132718Skan magic number as its third argument, that indicates what to do. 1550132718Skan The return value is an integer to be compared against zero. */ 1551169689Skan else if (GET_MODE (op0) == TFmode) 1552132718Skan { 1553132718Skan enum qfcmp_magic { 1554132718Skan QCMP_INV = 1, /* Raise FP_INVALID on SNaN as a side effect. */ 1555132718Skan QCMP_UNORD = 2, 1556132718Skan QCMP_EQ = 4, 1557132718Skan QCMP_LT = 8, 1558132718Skan QCMP_GT = 16 1559132718Skan } magic; 1560132718Skan enum rtx_code ncode; 1561132718Skan rtx ret, insns; 1562169689Skan 1563169689Skan gcc_assert (cmptf_libfunc && GET_MODE (op1) == TFmode); 1564132718Skan switch (code) 1565132718Skan { 1566132718Skan /* 1 = equal, 0 = not equal. Equality operators do 1567132718Skan not raise FP_INVALID when given an SNaN operand. */ 1568132718Skan case EQ: magic = QCMP_EQ; ncode = NE; break; 1569132718Skan case NE: magic = QCMP_EQ; ncode = EQ; break; 1570132718Skan /* isunordered() from C99. */ 1571132718Skan case UNORDERED: magic = QCMP_UNORD; ncode = NE; break; 1572169689Skan case ORDERED: magic = QCMP_UNORD; ncode = EQ; break; 1573132718Skan /* Relational operators raise FP_INVALID when given 1574132718Skan an SNaN operand. */ 1575132718Skan case LT: magic = QCMP_LT |QCMP_INV; ncode = NE; break; 1576132718Skan case LE: magic = QCMP_LT|QCMP_EQ|QCMP_INV; ncode = NE; break; 1577132718Skan case GT: magic = QCMP_GT |QCMP_INV; ncode = NE; break; 1578132718Skan case GE: magic = QCMP_GT|QCMP_EQ|QCMP_INV; ncode = NE; break; 1579132718Skan /* FUTURE: Implement UNEQ, UNLT, UNLE, UNGT, UNGE, LTGT. 1580132718Skan Expanders for buneq etc. weuld have to be added to ia64.md 1581132718Skan for this to be useful. */ 1582169689Skan default: gcc_unreachable (); 1583132718Skan } 1584132718Skan 1585132718Skan start_sequence (); 1586132718Skan 1587132718Skan ret = emit_library_call_value (cmptf_libfunc, 0, LCT_CONST, DImode, 3, 1588132718Skan op0, TFmode, op1, TFmode, 1589132718Skan GEN_INT (magic), DImode); 1590132718Skan cmp = gen_reg_rtx (BImode); 1591132718Skan emit_insn (gen_rtx_SET (VOIDmode, cmp, 1592132718Skan gen_rtx_fmt_ee (ncode, BImode, 1593132718Skan ret, const0_rtx))); 1594132718Skan 1595132718Skan insns = get_insns (); 1596132718Skan end_sequence (); 1597132718Skan 1598132718Skan emit_libcall_block (insns, cmp, cmp, 1599132718Skan gen_rtx_fmt_ee (code, BImode, op0, op1)); 1600132718Skan code = NE; 1601132718Skan } 160290075Sobrien else 160390075Sobrien { 160490075Sobrien cmp = gen_reg_rtx (BImode); 160590075Sobrien emit_insn (gen_rtx_SET (VOIDmode, cmp, 160690075Sobrien gen_rtx_fmt_ee (code, BImode, op0, op1))); 160790075Sobrien code = NE; 160890075Sobrien } 160990075Sobrien 161090075Sobrien return gen_rtx_fmt_ee (code, mode, cmp, const0_rtx); 161190075Sobrien} 161290075Sobrien 1613169689Skan/* Generate an integral vector comparison. Return true if the condition has 1614169689Skan been reversed, and so the sense of the comparison should be inverted. */ 1615169689Skan 1616169689Skanstatic bool 1617169689Skania64_expand_vecint_compare (enum rtx_code code, enum machine_mode mode, 1618169689Skan rtx dest, rtx op0, rtx op1) 1619169689Skan{ 1620169689Skan bool negate = false; 1621169689Skan rtx x; 1622169689Skan 1623169689Skan /* Canonicalize the comparison to EQ, GT, GTU. */ 1624169689Skan switch (code) 1625169689Skan { 1626169689Skan case EQ: 1627169689Skan case GT: 1628169689Skan case GTU: 1629169689Skan break; 1630169689Skan 1631169689Skan case NE: 1632169689Skan case LE: 1633169689Skan case LEU: 1634169689Skan code = reverse_condition (code); 1635169689Skan negate = true; 1636169689Skan break; 1637169689Skan 1638169689Skan case GE: 1639169689Skan case GEU: 1640169689Skan code = reverse_condition (code); 1641169689Skan negate = true; 1642169689Skan /* FALLTHRU */ 1643169689Skan 1644169689Skan case LT: 1645169689Skan case LTU: 1646169689Skan code = swap_condition (code); 1647169689Skan x = op0, op0 = op1, op1 = x; 1648169689Skan break; 1649169689Skan 1650169689Skan default: 1651169689Skan gcc_unreachable (); 1652169689Skan } 1653169689Skan 1654169689Skan /* Unsigned parallel compare is not supported by the hardware. Play some 1655169689Skan tricks to turn this into a signed comparison against 0. */ 1656169689Skan if (code == GTU) 1657169689Skan { 1658169689Skan switch (mode) 1659169689Skan { 1660169689Skan case V2SImode: 1661169689Skan { 1662169689Skan rtx t1, t2, mask; 1663169689Skan 1664169689Skan /* Perform a parallel modulo subtraction. */ 1665169689Skan t1 = gen_reg_rtx (V2SImode); 1666169689Skan emit_insn (gen_subv2si3 (t1, op0, op1)); 1667169689Skan 1668169689Skan /* Extract the original sign bit of op0. */ 1669169689Skan mask = GEN_INT (-0x80000000); 1670169689Skan mask = gen_rtx_CONST_VECTOR (V2SImode, gen_rtvec (2, mask, mask)); 1671169689Skan mask = force_reg (V2SImode, mask); 1672169689Skan t2 = gen_reg_rtx (V2SImode); 1673169689Skan emit_insn (gen_andv2si3 (t2, op0, mask)); 1674169689Skan 1675169689Skan /* XOR it back into the result of the subtraction. This results 1676169689Skan in the sign bit set iff we saw unsigned underflow. */ 1677169689Skan x = gen_reg_rtx (V2SImode); 1678169689Skan emit_insn (gen_xorv2si3 (x, t1, t2)); 1679169689Skan 1680169689Skan code = GT; 1681169689Skan op0 = x; 1682169689Skan op1 = CONST0_RTX (mode); 1683169689Skan } 1684169689Skan break; 1685169689Skan 1686169689Skan case V8QImode: 1687169689Skan case V4HImode: 1688169689Skan /* Perform a parallel unsigned saturating subtraction. */ 1689169689Skan x = gen_reg_rtx (mode); 1690169689Skan emit_insn (gen_rtx_SET (VOIDmode, x, 1691169689Skan gen_rtx_US_MINUS (mode, op0, op1))); 1692169689Skan 1693169689Skan code = EQ; 1694169689Skan op0 = x; 1695169689Skan op1 = CONST0_RTX (mode); 1696169689Skan negate = !negate; 1697169689Skan break; 1698169689Skan 1699169689Skan default: 1700169689Skan gcc_unreachable (); 1701169689Skan } 1702169689Skan } 1703169689Skan 1704169689Skan x = gen_rtx_fmt_ee (code, mode, op0, op1); 1705169689Skan emit_insn (gen_rtx_SET (VOIDmode, dest, x)); 1706169689Skan 1707169689Skan return negate; 1708169689Skan} 1709169689Skan 1710169689Skan/* Emit an integral vector conditional move. */ 1711169689Skan 1712169689Skanvoid 1713169689Skania64_expand_vecint_cmov (rtx operands[]) 1714169689Skan{ 1715169689Skan enum machine_mode mode = GET_MODE (operands[0]); 1716169689Skan enum rtx_code code = GET_CODE (operands[3]); 1717169689Skan bool negate; 1718169689Skan rtx cmp, x, ot, of; 1719169689Skan 1720169689Skan cmp = gen_reg_rtx (mode); 1721169689Skan negate = ia64_expand_vecint_compare (code, mode, cmp, 1722169689Skan operands[4], operands[5]); 1723169689Skan 1724169689Skan ot = operands[1+negate]; 1725169689Skan of = operands[2-negate]; 1726169689Skan 1727169689Skan if (ot == CONST0_RTX (mode)) 1728169689Skan { 1729169689Skan if (of == CONST0_RTX (mode)) 1730169689Skan { 1731169689Skan emit_move_insn (operands[0], ot); 1732169689Skan return; 1733169689Skan } 1734169689Skan 1735169689Skan x = gen_rtx_NOT (mode, cmp); 1736169689Skan x = gen_rtx_AND (mode, x, of); 1737169689Skan emit_insn (gen_rtx_SET (VOIDmode, operands[0], x)); 1738169689Skan } 1739169689Skan else if (of == CONST0_RTX (mode)) 1740169689Skan { 1741169689Skan x = gen_rtx_AND (mode, cmp, ot); 1742169689Skan emit_insn (gen_rtx_SET (VOIDmode, operands[0], x)); 1743169689Skan } 1744169689Skan else 1745169689Skan { 1746169689Skan rtx t, f; 1747169689Skan 1748169689Skan t = gen_reg_rtx (mode); 1749169689Skan x = gen_rtx_AND (mode, cmp, operands[1+negate]); 1750169689Skan emit_insn (gen_rtx_SET (VOIDmode, t, x)); 1751169689Skan 1752169689Skan f = gen_reg_rtx (mode); 1753169689Skan x = gen_rtx_NOT (mode, cmp); 1754169689Skan x = gen_rtx_AND (mode, x, operands[2-negate]); 1755169689Skan emit_insn (gen_rtx_SET (VOIDmode, f, x)); 1756169689Skan 1757169689Skan x = gen_rtx_IOR (mode, t, f); 1758169689Skan emit_insn (gen_rtx_SET (VOIDmode, operands[0], x)); 1759169689Skan } 1760169689Skan} 1761169689Skan 1762169689Skan/* Emit an integral vector min or max operation. Return true if all done. */ 1763169689Skan 1764169689Skanbool 1765169689Skania64_expand_vecint_minmax (enum rtx_code code, enum machine_mode mode, 1766169689Skan rtx operands[]) 1767169689Skan{ 1768169689Skan rtx xops[6]; 1769169689Skan 1770169689Skan /* These four combinations are supported directly. */ 1771169689Skan if (mode == V8QImode && (code == UMIN || code == UMAX)) 1772169689Skan return false; 1773169689Skan if (mode == V4HImode && (code == SMIN || code == SMAX)) 1774169689Skan return false; 1775169689Skan 1776169689Skan /* This combination can be implemented with only saturating subtraction. */ 1777169689Skan if (mode == V4HImode && code == UMAX) 1778169689Skan { 1779169689Skan rtx x, tmp = gen_reg_rtx (mode); 1780169689Skan 1781169689Skan x = gen_rtx_US_MINUS (mode, operands[1], operands[2]); 1782169689Skan emit_insn (gen_rtx_SET (VOIDmode, tmp, x)); 1783169689Skan 1784169689Skan emit_insn (gen_addv4hi3 (operands[0], tmp, operands[2])); 1785169689Skan return true; 1786169689Skan } 1787169689Skan 1788169689Skan /* Everything else implemented via vector comparisons. */ 1789169689Skan xops[0] = operands[0]; 1790169689Skan xops[4] = xops[1] = operands[1]; 1791169689Skan xops[5] = xops[2] = operands[2]; 1792169689Skan 1793169689Skan switch (code) 1794169689Skan { 1795169689Skan case UMIN: 1796169689Skan code = LTU; 1797169689Skan break; 1798169689Skan case UMAX: 1799169689Skan code = GTU; 1800169689Skan break; 1801169689Skan case SMIN: 1802169689Skan code = LT; 1803169689Skan break; 1804169689Skan case SMAX: 1805169689Skan code = GT; 1806169689Skan break; 1807169689Skan default: 1808169689Skan gcc_unreachable (); 1809169689Skan } 1810169689Skan xops[3] = gen_rtx_fmt_ee (code, VOIDmode, operands[1], operands[2]); 1811169689Skan 1812169689Skan ia64_expand_vecint_cmov (xops); 1813169689Skan return true; 1814169689Skan} 1815169689Skan 1816169689Skan/* Emit an integral vector widening sum operations. */ 1817169689Skan 1818169689Skanvoid 1819169689Skania64_expand_widen_sum (rtx operands[3], bool unsignedp) 1820169689Skan{ 1821169689Skan rtx l, h, x, s; 1822169689Skan enum machine_mode wmode, mode; 1823169689Skan rtx (*unpack_l) (rtx, rtx, rtx); 1824169689Skan rtx (*unpack_h) (rtx, rtx, rtx); 1825169689Skan rtx (*plus) (rtx, rtx, rtx); 1826169689Skan 1827169689Skan wmode = GET_MODE (operands[0]); 1828169689Skan mode = GET_MODE (operands[1]); 1829169689Skan 1830169689Skan switch (mode) 1831169689Skan { 1832169689Skan case V8QImode: 1833169689Skan unpack_l = gen_unpack1_l; 1834169689Skan unpack_h = gen_unpack1_h; 1835169689Skan plus = gen_addv4hi3; 1836169689Skan break; 1837169689Skan case V4HImode: 1838169689Skan unpack_l = gen_unpack2_l; 1839169689Skan unpack_h = gen_unpack2_h; 1840169689Skan plus = gen_addv2si3; 1841169689Skan break; 1842169689Skan default: 1843169689Skan gcc_unreachable (); 1844169689Skan } 1845169689Skan 1846169689Skan /* Fill in x with the sign extension of each element in op1. */ 1847169689Skan if (unsignedp) 1848169689Skan x = CONST0_RTX (mode); 1849169689Skan else 1850169689Skan { 1851169689Skan bool neg; 1852169689Skan 1853169689Skan x = gen_reg_rtx (mode); 1854169689Skan 1855169689Skan neg = ia64_expand_vecint_compare (LT, mode, x, operands[1], 1856169689Skan CONST0_RTX (mode)); 1857169689Skan gcc_assert (!neg); 1858169689Skan } 1859169689Skan 1860169689Skan l = gen_reg_rtx (wmode); 1861169689Skan h = gen_reg_rtx (wmode); 1862169689Skan s = gen_reg_rtx (wmode); 1863169689Skan 1864169689Skan emit_insn (unpack_l (gen_lowpart (mode, l), operands[1], x)); 1865169689Skan emit_insn (unpack_h (gen_lowpart (mode, h), operands[1], x)); 1866169689Skan emit_insn (plus (s, l, operands[2])); 1867169689Skan emit_insn (plus (operands[0], h, s)); 1868169689Skan} 1869169689Skan 1870169689Skan/* Emit a signed or unsigned V8QI dot product operation. */ 1871169689Skan 1872169689Skanvoid 1873169689Skania64_expand_dot_prod_v8qi (rtx operands[4], bool unsignedp) 1874169689Skan{ 1875169689Skan rtx l1, l2, h1, h2, x1, x2, p1, p2, p3, p4, s1, s2, s3; 1876169689Skan 1877169689Skan /* Fill in x1 and x2 with the sign extension of each element. */ 1878169689Skan if (unsignedp) 1879169689Skan x1 = x2 = CONST0_RTX (V8QImode); 1880169689Skan else 1881169689Skan { 1882169689Skan bool neg; 1883169689Skan 1884169689Skan x1 = gen_reg_rtx (V8QImode); 1885169689Skan x2 = gen_reg_rtx (V8QImode); 1886169689Skan 1887169689Skan neg = ia64_expand_vecint_compare (LT, V8QImode, x1, operands[1], 1888169689Skan CONST0_RTX (V8QImode)); 1889169689Skan gcc_assert (!neg); 1890169689Skan neg = ia64_expand_vecint_compare (LT, V8QImode, x2, operands[2], 1891169689Skan CONST0_RTX (V8QImode)); 1892169689Skan gcc_assert (!neg); 1893169689Skan } 1894169689Skan 1895169689Skan l1 = gen_reg_rtx (V4HImode); 1896169689Skan l2 = gen_reg_rtx (V4HImode); 1897169689Skan h1 = gen_reg_rtx (V4HImode); 1898169689Skan h2 = gen_reg_rtx (V4HImode); 1899169689Skan 1900169689Skan emit_insn (gen_unpack1_l (gen_lowpart (V8QImode, l1), operands[1], x1)); 1901169689Skan emit_insn (gen_unpack1_l (gen_lowpart (V8QImode, l2), operands[2], x2)); 1902169689Skan emit_insn (gen_unpack1_h (gen_lowpart (V8QImode, h1), operands[1], x1)); 1903169689Skan emit_insn (gen_unpack1_h (gen_lowpart (V8QImode, h2), operands[2], x2)); 1904169689Skan 1905169689Skan p1 = gen_reg_rtx (V2SImode); 1906169689Skan p2 = gen_reg_rtx (V2SImode); 1907169689Skan p3 = gen_reg_rtx (V2SImode); 1908169689Skan p4 = gen_reg_rtx (V2SImode); 1909169689Skan emit_insn (gen_pmpy2_r (p1, l1, l2)); 1910169689Skan emit_insn (gen_pmpy2_l (p2, l1, l2)); 1911169689Skan emit_insn (gen_pmpy2_r (p3, h1, h2)); 1912169689Skan emit_insn (gen_pmpy2_l (p4, h1, h2)); 1913169689Skan 1914169689Skan s1 = gen_reg_rtx (V2SImode); 1915169689Skan s2 = gen_reg_rtx (V2SImode); 1916169689Skan s3 = gen_reg_rtx (V2SImode); 1917169689Skan emit_insn (gen_addv2si3 (s1, p1, p2)); 1918169689Skan emit_insn (gen_addv2si3 (s2, p3, p4)); 1919169689Skan emit_insn (gen_addv2si3 (s3, s1, operands[3])); 1920169689Skan emit_insn (gen_addv2si3 (operands[0], s2, s3)); 1921169689Skan} 1922169689Skan 192390075Sobrien/* Emit the appropriate sequence for a call. */ 1924132718Skan 192590075Sobrienvoid 1926132718Skania64_expand_call (rtx retval, rtx addr, rtx nextarg ATTRIBUTE_UNUSED, 1927132718Skan int sibcall_p) 192890075Sobrien{ 1929117395Skan rtx insn, b0; 193090075Sobrien 193190075Sobrien addr = XEXP (addr, 0); 1932132718Skan addr = convert_memory_address (DImode, addr); 193390075Sobrien b0 = gen_rtx_REG (DImode, R_BR (0)); 193490075Sobrien 1935117395Skan /* ??? Should do this for functions known to bind local too. */ 193690075Sobrien if (TARGET_NO_PIC || TARGET_AUTO_PIC) 193790075Sobrien { 193890075Sobrien if (sibcall_p) 1939117395Skan insn = gen_sibcall_nogp (addr); 194090075Sobrien else if (! retval) 1941117395Skan insn = gen_call_nogp (addr, b0); 194290075Sobrien else 1943117395Skan insn = gen_call_value_nogp (retval, addr, b0); 1944117395Skan insn = emit_call_insn (insn); 194590075Sobrien } 1946117395Skan else 1947117395Skan { 1948117395Skan if (sibcall_p) 1949117395Skan insn = gen_sibcall_gp (addr); 1950117395Skan else if (! retval) 1951117395Skan insn = gen_call_gp (addr, b0); 1952117395Skan else 1953117395Skan insn = gen_call_value_gp (retval, addr, b0); 1954117395Skan insn = emit_call_insn (insn); 195590075Sobrien 1956117395Skan use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); 1957117395Skan } 195896263Sobrien 1959117395Skan if (sibcall_p) 1960119256Skan use_reg (&CALL_INSN_FUNCTION_USAGE (insn), b0); 1961117395Skan} 1962132718Skan 1963117395Skanvoid 1964132718Skania64_reload_gp (void) 1965117395Skan{ 1966117395Skan rtx tmp; 1967117395Skan 1968117395Skan if (current_frame_info.reg_save_gp) 1969117395Skan tmp = gen_rtx_REG (DImode, current_frame_info.reg_save_gp); 197090075Sobrien else 1971117395Skan { 1972117395Skan HOST_WIDE_INT offset; 197390075Sobrien 1974117395Skan offset = (current_frame_info.spill_cfa_off 1975117395Skan + current_frame_info.spill_size); 1976117395Skan if (frame_pointer_needed) 1977117395Skan { 1978117395Skan tmp = hard_frame_pointer_rtx; 1979117395Skan offset = -offset; 1980117395Skan } 1981117395Skan else 1982117395Skan { 1983117395Skan tmp = stack_pointer_rtx; 1984117395Skan offset = current_frame_info.total_size - offset; 1985117395Skan } 198696263Sobrien 1987117395Skan if (CONST_OK_FOR_I (offset)) 1988117395Skan emit_insn (gen_adddi3 (pic_offset_table_rtx, 1989117395Skan tmp, GEN_INT (offset))); 1990117395Skan else 1991117395Skan { 1992117395Skan emit_move_insn (pic_offset_table_rtx, GEN_INT (offset)); 1993117395Skan emit_insn (gen_adddi3 (pic_offset_table_rtx, 1994117395Skan pic_offset_table_rtx, tmp)); 1995117395Skan } 1996117395Skan 1997117395Skan tmp = gen_rtx_MEM (DImode, pic_offset_table_rtx); 1998117395Skan } 1999117395Skan 2000117395Skan emit_move_insn (pic_offset_table_rtx, tmp); 2001117395Skan} 2002117395Skan 2003117395Skanvoid 2004132718Skania64_split_call (rtx retval, rtx addr, rtx retaddr, rtx scratch_r, 2005132718Skan rtx scratch_b, int noreturn_p, int sibcall_p) 2006117395Skan{ 2007117395Skan rtx insn; 2008117395Skan bool is_desc = false; 2009117395Skan 2010117395Skan /* If we find we're calling through a register, then we're actually 2011117395Skan calling through a descriptor, so load up the values. */ 2012119256Skan if (REG_P (addr) && GR_REGNO_P (REGNO (addr))) 201390075Sobrien { 2014117395Skan rtx tmp; 2015117395Skan bool addr_dead_p; 2016117395Skan 2017117395Skan /* ??? We are currently constrained to *not* use peep2, because 2018132718Skan we can legitimately change the global lifetime of the GP 2019132718Skan (in the form of killing where previously live). This is 2020117395Skan because a call through a descriptor doesn't use the previous 2021117395Skan value of the GP, while a direct call does, and we do not 2022117395Skan commit to either form until the split here. 2023117395Skan 2024117395Skan That said, this means that we lack precise life info for 2025117395Skan whether ADDR is dead after this call. This is not terribly 2026117395Skan important, since we can fix things up essentially for free 2027117395Skan with the POST_DEC below, but it's nice to not use it when we 2028117395Skan can immediately tell it's not necessary. */ 2029117395Skan addr_dead_p = ((noreturn_p || sibcall_p 2030117395Skan || TEST_HARD_REG_BIT (regs_invalidated_by_call, 2031117395Skan REGNO (addr))) 2032117395Skan && !FUNCTION_ARG_REGNO_P (REGNO (addr))); 2033117395Skan 2034117395Skan /* Load the code address into scratch_b. */ 2035117395Skan tmp = gen_rtx_POST_INC (Pmode, addr); 2036117395Skan tmp = gen_rtx_MEM (Pmode, tmp); 2037117395Skan emit_move_insn (scratch_r, tmp); 2038117395Skan emit_move_insn (scratch_b, scratch_r); 2039117395Skan 2040117395Skan /* Load the GP address. If ADDR is not dead here, then we must 2041117395Skan revert the change made above via the POST_INCREMENT. */ 2042117395Skan if (!addr_dead_p) 2043117395Skan tmp = gen_rtx_POST_DEC (Pmode, addr); 2044117395Skan else 2045117395Skan tmp = addr; 2046117395Skan tmp = gen_rtx_MEM (Pmode, tmp); 2047117395Skan emit_move_insn (pic_offset_table_rtx, tmp); 2048117395Skan 2049117395Skan is_desc = true; 2050117395Skan addr = scratch_b; 205190075Sobrien } 205290075Sobrien 205396263Sobrien if (sibcall_p) 2054117395Skan insn = gen_sibcall_nogp (addr); 2055117395Skan else if (retval) 2056117395Skan insn = gen_call_value_nogp (retval, addr, retaddr); 205796263Sobrien else 2058117395Skan insn = gen_call_nogp (addr, retaddr); 205996263Sobrien emit_call_insn (insn); 206090075Sobrien 2061117395Skan if ((!TARGET_CONST_GP || is_desc) && !noreturn_p && !sibcall_p) 2062117395Skan ia64_reload_gp (); 206390075Sobrien} 2064169689Skan 2065169689Skan/* Expand an atomic operation. We want to perform MEM <CODE>= VAL atomically. 2066169689Skan 2067169689Skan This differs from the generic code in that we know about the zero-extending 2068169689Skan properties of cmpxchg, and the zero-extending requirements of ar.ccv. We 2069169689Skan also know that ld.acq+cmpxchg.rel equals a full barrier. 2070169689Skan 2071169689Skan The loop we want to generate looks like 2072169689Skan 2073169689Skan cmp_reg = mem; 2074169689Skan label: 2075169689Skan old_reg = cmp_reg; 2076169689Skan new_reg = cmp_reg op val; 2077169689Skan cmp_reg = compare-and-swap(mem, old_reg, new_reg) 2078169689Skan if (cmp_reg != old_reg) 2079169689Skan goto label; 2080169689Skan 2081169689Skan Note that we only do the plain load from memory once. Subsequent 2082169689Skan iterations use the value loaded by the compare-and-swap pattern. */ 2083169689Skan 2084169689Skanvoid 2085169689Skania64_expand_atomic_op (enum rtx_code code, rtx mem, rtx val, 2086169689Skan rtx old_dst, rtx new_dst) 2087169689Skan{ 2088169689Skan enum machine_mode mode = GET_MODE (mem); 2089169689Skan rtx old_reg, new_reg, cmp_reg, ar_ccv, label; 2090169689Skan enum insn_code icode; 2091169689Skan 2092169689Skan /* Special case for using fetchadd. */ 2093169689Skan if ((mode == SImode || mode == DImode) 2094169689Skan && (code == PLUS || code == MINUS) 2095169689Skan && fetchadd_operand (val, mode)) 2096169689Skan { 2097169689Skan if (code == MINUS) 2098169689Skan val = GEN_INT (-INTVAL (val)); 2099169689Skan 2100169689Skan if (!old_dst) 2101169689Skan old_dst = gen_reg_rtx (mode); 2102169689Skan 2103169689Skan emit_insn (gen_memory_barrier ()); 2104169689Skan 2105169689Skan if (mode == SImode) 2106169689Skan icode = CODE_FOR_fetchadd_acq_si; 2107169689Skan else 2108169689Skan icode = CODE_FOR_fetchadd_acq_di; 2109169689Skan emit_insn (GEN_FCN (icode) (old_dst, mem, val)); 2110169689Skan 2111169689Skan if (new_dst) 2112169689Skan { 2113169689Skan new_reg = expand_simple_binop (mode, PLUS, old_dst, val, new_dst, 2114169689Skan true, OPTAB_WIDEN); 2115169689Skan if (new_reg != new_dst) 2116169689Skan emit_move_insn (new_dst, new_reg); 2117169689Skan } 2118169689Skan return; 2119169689Skan } 2120169689Skan 2121169689Skan /* Because of the volatile mem read, we get an ld.acq, which is the 2122169689Skan front half of the full barrier. The end half is the cmpxchg.rel. */ 2123169689Skan gcc_assert (MEM_VOLATILE_P (mem)); 2124169689Skan 2125169689Skan old_reg = gen_reg_rtx (DImode); 2126169689Skan cmp_reg = gen_reg_rtx (DImode); 2127169689Skan label = gen_label_rtx (); 2128169689Skan 2129169689Skan if (mode != DImode) 2130169689Skan { 2131169689Skan val = simplify_gen_subreg (DImode, val, mode, 0); 2132169689Skan emit_insn (gen_extend_insn (cmp_reg, mem, DImode, mode, 1)); 2133169689Skan } 2134169689Skan else 2135169689Skan emit_move_insn (cmp_reg, mem); 2136169689Skan 2137169689Skan emit_label (label); 2138169689Skan 2139169689Skan ar_ccv = gen_rtx_REG (DImode, AR_CCV_REGNUM); 2140169689Skan emit_move_insn (old_reg, cmp_reg); 2141169689Skan emit_move_insn (ar_ccv, cmp_reg); 2142169689Skan 2143169689Skan if (old_dst) 2144169689Skan emit_move_insn (old_dst, gen_lowpart (mode, cmp_reg)); 2145169689Skan 2146169689Skan new_reg = cmp_reg; 2147169689Skan if (code == NOT) 2148169689Skan { 2149169689Skan new_reg = expand_simple_unop (DImode, NOT, new_reg, NULL_RTX, true); 2150169689Skan code = AND; 2151169689Skan } 2152169689Skan new_reg = expand_simple_binop (DImode, code, new_reg, val, NULL_RTX, 2153169689Skan true, OPTAB_DIRECT); 2154169689Skan 2155169689Skan if (mode != DImode) 2156169689Skan new_reg = gen_lowpart (mode, new_reg); 2157169689Skan if (new_dst) 2158169689Skan emit_move_insn (new_dst, new_reg); 2159169689Skan 2160169689Skan switch (mode) 2161169689Skan { 2162169689Skan case QImode: icode = CODE_FOR_cmpxchg_rel_qi; break; 2163169689Skan case HImode: icode = CODE_FOR_cmpxchg_rel_hi; break; 2164169689Skan case SImode: icode = CODE_FOR_cmpxchg_rel_si; break; 2165169689Skan case DImode: icode = CODE_FOR_cmpxchg_rel_di; break; 2166169689Skan default: 2167169689Skan gcc_unreachable (); 2168169689Skan } 2169169689Skan 2170169689Skan emit_insn (GEN_FCN (icode) (cmp_reg, mem, ar_ccv, new_reg)); 2171169689Skan 2172169689Skan emit_cmp_and_jump_insns (cmp_reg, old_reg, NE, NULL, DImode, true, label); 2173169689Skan} 217490075Sobrien 217590075Sobrien/* Begin the assembly file. */ 217690075Sobrien 2177132718Skanstatic void 2178132718Skania64_file_start (void) 2179132718Skan{ 2180169689Skan /* Variable tracking should be run after all optimizations which change order 2181169689Skan of insns. It also needs a valid CFG. This can't be done in 2182169689Skan ia64_override_options, because flag_var_tracking is finalized after 2183169689Skan that. */ 2184169689Skan ia64_flag_var_tracking = flag_var_tracking; 2185169689Skan flag_var_tracking = 0; 2186169689Skan 2187132718Skan default_file_start (); 2188132718Skan emit_safe_across_calls (); 2189132718Skan} 2190132718Skan 219190075Sobrienvoid 2192132718Skanemit_safe_across_calls (void) 219390075Sobrien{ 219490075Sobrien unsigned int rs, re; 219590075Sobrien int out_state; 219690075Sobrien 219790075Sobrien rs = 1; 219890075Sobrien out_state = 0; 219990075Sobrien while (1) 220090075Sobrien { 220190075Sobrien while (rs < 64 && call_used_regs[PR_REG (rs)]) 220290075Sobrien rs++; 220390075Sobrien if (rs >= 64) 220490075Sobrien break; 220590075Sobrien for (re = rs + 1; re < 64 && ! call_used_regs[PR_REG (re)]; re++) 220690075Sobrien continue; 220790075Sobrien if (out_state == 0) 220890075Sobrien { 2209132718Skan fputs ("\t.pred.safe_across_calls ", asm_out_file); 221090075Sobrien out_state = 1; 221190075Sobrien } 221290075Sobrien else 2213132718Skan fputc (',', asm_out_file); 221490075Sobrien if (re == rs + 1) 2215132718Skan fprintf (asm_out_file, "p%u", rs); 221690075Sobrien else 2217132718Skan fprintf (asm_out_file, "p%u-p%u", rs, re - 1); 221890075Sobrien rs = re + 1; 221990075Sobrien } 222090075Sobrien if (out_state) 2221132718Skan fputc ('\n', asm_out_file); 222290075Sobrien} 222390075Sobrien 222490075Sobrien/* Helper function for ia64_compute_frame_size: find an appropriate general 222590075Sobrien register to spill some special register to. SPECIAL_SPILL_MASK contains 222690075Sobrien bits in GR0 to GR31 that have already been allocated by this routine. 222790075Sobrien TRY_LOCALS is true if we should attempt to locate a local regnum. */ 222890075Sobrien 222990075Sobrienstatic int 2230132718Skanfind_gr_spill (int try_locals) 223190075Sobrien{ 223290075Sobrien int regno; 223390075Sobrien 223490075Sobrien /* If this is a leaf function, first try an otherwise unused 223590075Sobrien call-clobbered register. */ 223690075Sobrien if (current_function_is_leaf) 223790075Sobrien { 223890075Sobrien for (regno = GR_REG (1); regno <= GR_REG (31); regno++) 223990075Sobrien if (! regs_ever_live[regno] 224090075Sobrien && call_used_regs[regno] 224190075Sobrien && ! fixed_regs[regno] 224290075Sobrien && ! global_regs[regno] 224390075Sobrien && ((current_frame_info.gr_used_mask >> regno) & 1) == 0) 224490075Sobrien { 224590075Sobrien current_frame_info.gr_used_mask |= 1 << regno; 224690075Sobrien return regno; 224790075Sobrien } 224890075Sobrien } 224990075Sobrien 225090075Sobrien if (try_locals) 225190075Sobrien { 225290075Sobrien regno = current_frame_info.n_local_regs; 225390075Sobrien /* If there is a frame pointer, then we can't use loc79, because 225490075Sobrien that is HARD_FRAME_POINTER_REGNUM. In particular, see the 225590075Sobrien reg_name switching code in ia64_expand_prologue. */ 225690075Sobrien if (regno < (80 - frame_pointer_needed)) 225790075Sobrien { 225890075Sobrien current_frame_info.n_local_regs = regno + 1; 225990075Sobrien return LOC_REG (0) + regno; 226090075Sobrien } 226190075Sobrien } 226290075Sobrien 226390075Sobrien /* Failed to find a general register to spill to. Must use stack. */ 226490075Sobrien return 0; 226590075Sobrien} 226690075Sobrien 226790075Sobrien/* In order to make for nice schedules, we try to allocate every temporary 226890075Sobrien to a different register. We must of course stay away from call-saved, 226990075Sobrien fixed, and global registers. We must also stay away from registers 227090075Sobrien allocated in current_frame_info.gr_used_mask, since those include regs 227190075Sobrien used all through the prologue. 227290075Sobrien 227390075Sobrien Any register allocated here must be used immediately. The idea is to 227490075Sobrien aid scheduling, not to solve data flow problems. */ 227590075Sobrien 227690075Sobrienstatic int last_scratch_gr_reg; 227790075Sobrien 227890075Sobrienstatic int 2279132718Skannext_scratch_gr_reg (void) 228090075Sobrien{ 228190075Sobrien int i, regno; 228290075Sobrien 228390075Sobrien for (i = 0; i < 32; ++i) 228490075Sobrien { 228590075Sobrien regno = (last_scratch_gr_reg + i + 1) & 31; 228690075Sobrien if (call_used_regs[regno] 228790075Sobrien && ! fixed_regs[regno] 228890075Sobrien && ! global_regs[regno] 228990075Sobrien && ((current_frame_info.gr_used_mask >> regno) & 1) == 0) 229090075Sobrien { 229190075Sobrien last_scratch_gr_reg = regno; 229290075Sobrien return regno; 229390075Sobrien } 229490075Sobrien } 229590075Sobrien 229690075Sobrien /* There must be _something_ available. */ 2297169689Skan gcc_unreachable (); 229890075Sobrien} 229990075Sobrien 230090075Sobrien/* Helper function for ia64_compute_frame_size, called through 230190075Sobrien diddle_return_value. Mark REG in current_frame_info.gr_used_mask. */ 230290075Sobrien 230390075Sobrienstatic void 2304132718Skanmark_reg_gr_used_mask (rtx reg, void *data ATTRIBUTE_UNUSED) 230590075Sobrien{ 230690075Sobrien unsigned int regno = REGNO (reg); 230790075Sobrien if (regno < 32) 230890075Sobrien { 2309169689Skan unsigned int i, n = hard_regno_nregs[regno][GET_MODE (reg)]; 231090075Sobrien for (i = 0; i < n; ++i) 231190075Sobrien current_frame_info.gr_used_mask |= 1 << (regno + i); 231290075Sobrien } 231390075Sobrien} 231490075Sobrien 231590075Sobrien/* Returns the number of bytes offset between the frame pointer and the stack 231690075Sobrien pointer for the current function. SIZE is the number of bytes of space 231790075Sobrien needed for local variables. */ 231890075Sobrien 231990075Sobrienstatic void 2320132718Skania64_compute_frame_size (HOST_WIDE_INT size) 232190075Sobrien{ 232290075Sobrien HOST_WIDE_INT total_size; 232390075Sobrien HOST_WIDE_INT spill_size = 0; 232490075Sobrien HOST_WIDE_INT extra_spill_size = 0; 232590075Sobrien HOST_WIDE_INT pretend_args_size; 232690075Sobrien HARD_REG_SET mask; 232790075Sobrien int n_spilled = 0; 232890075Sobrien int spilled_gr_p = 0; 232990075Sobrien int spilled_fr_p = 0; 233090075Sobrien unsigned int regno; 233190075Sobrien int i; 233290075Sobrien 233390075Sobrien if (current_frame_info.initialized) 233490075Sobrien return; 233590075Sobrien 233690075Sobrien memset (¤t_frame_info, 0, sizeof current_frame_info); 233790075Sobrien CLEAR_HARD_REG_SET (mask); 233890075Sobrien 233990075Sobrien /* Don't allocate scratches to the return register. */ 234090075Sobrien diddle_return_value (mark_reg_gr_used_mask, NULL); 234190075Sobrien 234290075Sobrien /* Don't allocate scratches to the EH scratch registers. */ 234390075Sobrien if (cfun->machine->ia64_eh_epilogue_sp) 234490075Sobrien mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_sp, NULL); 234590075Sobrien if (cfun->machine->ia64_eh_epilogue_bsp) 234690075Sobrien mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_bsp, NULL); 234790075Sobrien 234890075Sobrien /* Find the size of the register stack frame. We have only 80 local 234990075Sobrien registers, because we reserve 8 for the inputs and 8 for the 235090075Sobrien outputs. */ 235190075Sobrien 235290075Sobrien /* Skip HARD_FRAME_POINTER_REGNUM (loc79) when frame_pointer_needed, 235390075Sobrien since we'll be adjusting that down later. */ 235490075Sobrien regno = LOC_REG (78) + ! frame_pointer_needed; 235590075Sobrien for (; regno >= LOC_REG (0); regno--) 235690075Sobrien if (regs_ever_live[regno]) 235790075Sobrien break; 235890075Sobrien current_frame_info.n_local_regs = regno - LOC_REG (0) + 1; 235990075Sobrien 236090075Sobrien /* For functions marked with the syscall_linkage attribute, we must mark 236190075Sobrien all eight input registers as in use, so that locals aren't visible to 236290075Sobrien the caller. */ 236390075Sobrien 236490075Sobrien if (cfun->machine->n_varargs > 0 236590075Sobrien || lookup_attribute ("syscall_linkage", 236690075Sobrien TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) 236790075Sobrien current_frame_info.n_input_regs = 8; 236890075Sobrien else 236990075Sobrien { 237090075Sobrien for (regno = IN_REG (7); regno >= IN_REG (0); regno--) 237190075Sobrien if (regs_ever_live[regno]) 237290075Sobrien break; 237390075Sobrien current_frame_info.n_input_regs = regno - IN_REG (0) + 1; 237490075Sobrien } 237590075Sobrien 237690075Sobrien for (regno = OUT_REG (7); regno >= OUT_REG (0); regno--) 237790075Sobrien if (regs_ever_live[regno]) 237890075Sobrien break; 237990075Sobrien i = regno - OUT_REG (0) + 1; 238090075Sobrien 2381169689Skan#ifndef PROFILE_HOOK 238290075Sobrien /* When -p profiling, we need one output register for the mcount argument. 2383132718Skan Likewise for -a profiling for the bb_init_func argument. For -ax 238490075Sobrien profiling, we need two output registers for the two bb_init_trace_func 238590075Sobrien arguments. */ 238690075Sobrien if (current_function_profile) 238790075Sobrien i = MAX (i, 1); 2388169689Skan#endif 238990075Sobrien current_frame_info.n_output_regs = i; 239090075Sobrien 239190075Sobrien /* ??? No rotating register support yet. */ 239290075Sobrien current_frame_info.n_rotate_regs = 0; 239390075Sobrien 239490075Sobrien /* Discover which registers need spilling, and how much room that 2395132718Skan will take. Begin with floating point and general registers, 239690075Sobrien which will always wind up on the stack. */ 239790075Sobrien 239890075Sobrien for (regno = FR_REG (2); regno <= FR_REG (127); regno++) 239990075Sobrien if (regs_ever_live[regno] && ! call_used_regs[regno]) 240090075Sobrien { 240190075Sobrien SET_HARD_REG_BIT (mask, regno); 240290075Sobrien spill_size += 16; 240390075Sobrien n_spilled += 1; 240490075Sobrien spilled_fr_p = 1; 240590075Sobrien } 240690075Sobrien 240790075Sobrien for (regno = GR_REG (1); regno <= GR_REG (31); regno++) 240890075Sobrien if (regs_ever_live[regno] && ! call_used_regs[regno]) 240990075Sobrien { 241090075Sobrien SET_HARD_REG_BIT (mask, regno); 241190075Sobrien spill_size += 8; 241290075Sobrien n_spilled += 1; 241390075Sobrien spilled_gr_p = 1; 241490075Sobrien } 241590075Sobrien 241690075Sobrien for (regno = BR_REG (1); regno <= BR_REG (7); regno++) 241790075Sobrien if (regs_ever_live[regno] && ! call_used_regs[regno]) 241890075Sobrien { 241990075Sobrien SET_HARD_REG_BIT (mask, regno); 242090075Sobrien spill_size += 8; 242190075Sobrien n_spilled += 1; 242290075Sobrien } 242390075Sobrien 242490075Sobrien /* Now come all special registers that might get saved in other 242590075Sobrien general registers. */ 2426132718Skan 242790075Sobrien if (frame_pointer_needed) 242890075Sobrien { 242990075Sobrien current_frame_info.reg_fp = find_gr_spill (1); 243090075Sobrien /* If we did not get a register, then we take LOC79. This is guaranteed 243190075Sobrien to be free, even if regs_ever_live is already set, because this is 243290075Sobrien HARD_FRAME_POINTER_REGNUM. This requires incrementing n_local_regs, 243390075Sobrien as we don't count loc79 above. */ 243490075Sobrien if (current_frame_info.reg_fp == 0) 243590075Sobrien { 243690075Sobrien current_frame_info.reg_fp = LOC_REG (79); 243790075Sobrien current_frame_info.n_local_regs++; 243890075Sobrien } 243990075Sobrien } 244090075Sobrien 244190075Sobrien if (! current_function_is_leaf) 244290075Sobrien { 244390075Sobrien /* Emit a save of BR0 if we call other functions. Do this even 244490075Sobrien if this function doesn't return, as EH depends on this to be 244590075Sobrien able to unwind the stack. */ 244690075Sobrien SET_HARD_REG_BIT (mask, BR_REG (0)); 244790075Sobrien 244890075Sobrien current_frame_info.reg_save_b0 = find_gr_spill (1); 244990075Sobrien if (current_frame_info.reg_save_b0 == 0) 245090075Sobrien { 2451169689Skan extra_spill_size += 8; 245290075Sobrien n_spilled += 1; 245390075Sobrien } 245490075Sobrien 245590075Sobrien /* Similarly for ar.pfs. */ 245690075Sobrien SET_HARD_REG_BIT (mask, AR_PFS_REGNUM); 245790075Sobrien current_frame_info.reg_save_ar_pfs = find_gr_spill (1); 245890075Sobrien if (current_frame_info.reg_save_ar_pfs == 0) 245990075Sobrien { 246090075Sobrien extra_spill_size += 8; 246190075Sobrien n_spilled += 1; 246290075Sobrien } 2463117395Skan 2464117395Skan /* Similarly for gp. Note that if we're calling setjmp, the stacked 2465117395Skan registers are clobbered, so we fall back to the stack. */ 2466117395Skan current_frame_info.reg_save_gp 2467117395Skan = (current_function_calls_setjmp ? 0 : find_gr_spill (1)); 2468117395Skan if (current_frame_info.reg_save_gp == 0) 2469117395Skan { 2470117395Skan SET_HARD_REG_BIT (mask, GR_REG (1)); 2471117395Skan spill_size += 8; 2472117395Skan n_spilled += 1; 2473117395Skan } 247490075Sobrien } 247590075Sobrien else 247690075Sobrien { 247790075Sobrien if (regs_ever_live[BR_REG (0)] && ! call_used_regs[BR_REG (0)]) 247890075Sobrien { 247990075Sobrien SET_HARD_REG_BIT (mask, BR_REG (0)); 2480169689Skan extra_spill_size += 8; 248190075Sobrien n_spilled += 1; 248290075Sobrien } 2483117395Skan 2484117395Skan if (regs_ever_live[AR_PFS_REGNUM]) 2485117395Skan { 2486117395Skan SET_HARD_REG_BIT (mask, AR_PFS_REGNUM); 2487117395Skan current_frame_info.reg_save_ar_pfs = find_gr_spill (1); 2488117395Skan if (current_frame_info.reg_save_ar_pfs == 0) 2489117395Skan { 2490117395Skan extra_spill_size += 8; 2491117395Skan n_spilled += 1; 2492117395Skan } 2493117395Skan } 249490075Sobrien } 249590075Sobrien 249690075Sobrien /* Unwind descriptor hackery: things are most efficient if we allocate 249790075Sobrien consecutive GR save registers for RP, PFS, FP in that order. However, 249890075Sobrien it is absolutely critical that FP get the only hard register that's 249990075Sobrien guaranteed to be free, so we allocated it first. If all three did 250090075Sobrien happen to be allocated hard regs, and are consecutive, rearrange them 250190075Sobrien into the preferred order now. */ 250290075Sobrien if (current_frame_info.reg_fp != 0 250390075Sobrien && current_frame_info.reg_save_b0 == current_frame_info.reg_fp + 1 250490075Sobrien && current_frame_info.reg_save_ar_pfs == current_frame_info.reg_fp + 2) 250590075Sobrien { 250690075Sobrien current_frame_info.reg_save_b0 = current_frame_info.reg_fp; 250790075Sobrien current_frame_info.reg_save_ar_pfs = current_frame_info.reg_fp + 1; 250890075Sobrien current_frame_info.reg_fp = current_frame_info.reg_fp + 2; 250990075Sobrien } 251090075Sobrien 251190075Sobrien /* See if we need to store the predicate register block. */ 251290075Sobrien for (regno = PR_REG (0); regno <= PR_REG (63); regno++) 251390075Sobrien if (regs_ever_live[regno] && ! call_used_regs[regno]) 251490075Sobrien break; 251590075Sobrien if (regno <= PR_REG (63)) 251690075Sobrien { 251790075Sobrien SET_HARD_REG_BIT (mask, PR_REG (0)); 251890075Sobrien current_frame_info.reg_save_pr = find_gr_spill (1); 251990075Sobrien if (current_frame_info.reg_save_pr == 0) 252090075Sobrien { 252190075Sobrien extra_spill_size += 8; 252290075Sobrien n_spilled += 1; 252390075Sobrien } 252490075Sobrien 252590075Sobrien /* ??? Mark them all as used so that register renaming and such 252690075Sobrien are free to use them. */ 252790075Sobrien for (regno = PR_REG (0); regno <= PR_REG (63); regno++) 252890075Sobrien regs_ever_live[regno] = 1; 252990075Sobrien } 253090075Sobrien 253190075Sobrien /* If we're forced to use st8.spill, we're forced to save and restore 2532117395Skan ar.unat as well. The check for existing liveness allows inline asm 2533117395Skan to touch ar.unat. */ 2534117395Skan if (spilled_gr_p || cfun->machine->n_varargs 2535117395Skan || regs_ever_live[AR_UNAT_REGNUM]) 253690075Sobrien { 253790075Sobrien regs_ever_live[AR_UNAT_REGNUM] = 1; 253890075Sobrien SET_HARD_REG_BIT (mask, AR_UNAT_REGNUM); 253990075Sobrien current_frame_info.reg_save_ar_unat = find_gr_spill (spill_size == 0); 254090075Sobrien if (current_frame_info.reg_save_ar_unat == 0) 254190075Sobrien { 254290075Sobrien extra_spill_size += 8; 254390075Sobrien n_spilled += 1; 254490075Sobrien } 254590075Sobrien } 254690075Sobrien 254790075Sobrien if (regs_ever_live[AR_LC_REGNUM]) 254890075Sobrien { 254990075Sobrien SET_HARD_REG_BIT (mask, AR_LC_REGNUM); 255090075Sobrien current_frame_info.reg_save_ar_lc = find_gr_spill (spill_size == 0); 255190075Sobrien if (current_frame_info.reg_save_ar_lc == 0) 255290075Sobrien { 255390075Sobrien extra_spill_size += 8; 255490075Sobrien n_spilled += 1; 255590075Sobrien } 255690075Sobrien } 255790075Sobrien 255890075Sobrien /* If we have an odd number of words of pretend arguments written to 255990075Sobrien the stack, then the FR save area will be unaligned. We round the 256090075Sobrien size of this area up to keep things 16 byte aligned. */ 256190075Sobrien if (spilled_fr_p) 256290075Sobrien pretend_args_size = IA64_STACK_ALIGN (current_function_pretend_args_size); 256390075Sobrien else 256490075Sobrien pretend_args_size = current_function_pretend_args_size; 256590075Sobrien 256690075Sobrien total_size = (spill_size + extra_spill_size + size + pretend_args_size 256790075Sobrien + current_function_outgoing_args_size); 256890075Sobrien total_size = IA64_STACK_ALIGN (total_size); 256990075Sobrien 257090075Sobrien /* We always use the 16-byte scratch area provided by the caller, but 257190075Sobrien if we are a leaf function, there's no one to which we need to provide 257290075Sobrien a scratch area. */ 257390075Sobrien if (current_function_is_leaf) 257490075Sobrien total_size = MAX (0, total_size - 16); 257590075Sobrien 257690075Sobrien current_frame_info.total_size = total_size; 257790075Sobrien current_frame_info.spill_cfa_off = pretend_args_size - 16; 257890075Sobrien current_frame_info.spill_size = spill_size; 257990075Sobrien current_frame_info.extra_spill_size = extra_spill_size; 258090075Sobrien COPY_HARD_REG_SET (current_frame_info.mask, mask); 258190075Sobrien current_frame_info.n_spilled = n_spilled; 258290075Sobrien current_frame_info.initialized = reload_completed; 258390075Sobrien} 258490075Sobrien 258590075Sobrien/* Compute the initial difference between the specified pair of registers. */ 258690075Sobrien 258790075SobrienHOST_WIDE_INT 2588132718Skania64_initial_elimination_offset (int from, int to) 258990075Sobrien{ 259090075Sobrien HOST_WIDE_INT offset; 259190075Sobrien 259290075Sobrien ia64_compute_frame_size (get_frame_size ()); 259390075Sobrien switch (from) 259490075Sobrien { 259590075Sobrien case FRAME_POINTER_REGNUM: 2596169689Skan switch (to) 259790075Sobrien { 2598169689Skan case HARD_FRAME_POINTER_REGNUM: 259990075Sobrien if (current_function_is_leaf) 260090075Sobrien offset = -current_frame_info.total_size; 260190075Sobrien else 260290075Sobrien offset = -(current_frame_info.total_size 260390075Sobrien - current_function_outgoing_args_size - 16); 2604169689Skan break; 2605169689Skan 2606169689Skan case STACK_POINTER_REGNUM: 260790075Sobrien if (current_function_is_leaf) 260890075Sobrien offset = 0; 260990075Sobrien else 261090075Sobrien offset = 16 + current_function_outgoing_args_size; 2611169689Skan break; 2612169689Skan 2613169689Skan default: 2614169689Skan gcc_unreachable (); 261590075Sobrien } 261690075Sobrien break; 261790075Sobrien 261890075Sobrien case ARG_POINTER_REGNUM: 261990075Sobrien /* Arguments start above the 16 byte save area, unless stdarg 262090075Sobrien in which case we store through the 16 byte save area. */ 2621169689Skan switch (to) 2622169689Skan { 2623169689Skan case HARD_FRAME_POINTER_REGNUM: 2624169689Skan offset = 16 - current_function_pretend_args_size; 2625169689Skan break; 2626169689Skan 2627169689Skan case STACK_POINTER_REGNUM: 2628169689Skan offset = (current_frame_info.total_size 2629169689Skan + 16 - current_function_pretend_args_size); 2630169689Skan break; 2631169689Skan 2632169689Skan default: 2633169689Skan gcc_unreachable (); 2634169689Skan } 263590075Sobrien break; 263690075Sobrien 263790075Sobrien default: 2638169689Skan gcc_unreachable (); 263990075Sobrien } 264090075Sobrien 264190075Sobrien return offset; 264290075Sobrien} 264390075Sobrien 264490075Sobrien/* If there are more than a trivial number of register spills, we use 264590075Sobrien two interleaved iterators so that we can get two memory references 264690075Sobrien per insn group. 264790075Sobrien 264890075Sobrien In order to simplify things in the prologue and epilogue expanders, 264990075Sobrien we use helper functions to fix up the memory references after the 265090075Sobrien fact with the appropriate offsets to a POST_MODIFY memory mode. 265190075Sobrien The following data structure tracks the state of the two iterators 265290075Sobrien while insns are being emitted. */ 265390075Sobrien 265490075Sobrienstruct spill_fill_data 265590075Sobrien{ 265690075Sobrien rtx init_after; /* point at which to emit initializations */ 265790075Sobrien rtx init_reg[2]; /* initial base register */ 265890075Sobrien rtx iter_reg[2]; /* the iterator registers */ 265990075Sobrien rtx *prev_addr[2]; /* address of last memory use */ 266090075Sobrien rtx prev_insn[2]; /* the insn corresponding to prev_addr */ 266190075Sobrien HOST_WIDE_INT prev_off[2]; /* last offset */ 266290075Sobrien int n_iter; /* number of iterators in use */ 266390075Sobrien int next_iter; /* next iterator to use */ 266490075Sobrien unsigned int save_gr_used_mask; 266590075Sobrien}; 266690075Sobrien 266790075Sobrienstatic struct spill_fill_data spill_fill_data; 266890075Sobrien 266990075Sobrienstatic void 2670132718Skansetup_spill_pointers (int n_spills, rtx init_reg, HOST_WIDE_INT cfa_off) 267190075Sobrien{ 267290075Sobrien int i; 267390075Sobrien 267490075Sobrien spill_fill_data.init_after = get_last_insn (); 267590075Sobrien spill_fill_data.init_reg[0] = init_reg; 267690075Sobrien spill_fill_data.init_reg[1] = init_reg; 267790075Sobrien spill_fill_data.prev_addr[0] = NULL; 267890075Sobrien spill_fill_data.prev_addr[1] = NULL; 267990075Sobrien spill_fill_data.prev_insn[0] = NULL; 268090075Sobrien spill_fill_data.prev_insn[1] = NULL; 268190075Sobrien spill_fill_data.prev_off[0] = cfa_off; 268290075Sobrien spill_fill_data.prev_off[1] = cfa_off; 268390075Sobrien spill_fill_data.next_iter = 0; 268490075Sobrien spill_fill_data.save_gr_used_mask = current_frame_info.gr_used_mask; 268590075Sobrien 268690075Sobrien spill_fill_data.n_iter = 1 + (n_spills > 2); 268790075Sobrien for (i = 0; i < spill_fill_data.n_iter; ++i) 268890075Sobrien { 268990075Sobrien int regno = next_scratch_gr_reg (); 269090075Sobrien spill_fill_data.iter_reg[i] = gen_rtx_REG (DImode, regno); 269190075Sobrien current_frame_info.gr_used_mask |= 1 << regno; 269290075Sobrien } 269390075Sobrien} 269490075Sobrien 269590075Sobrienstatic void 2696132718Skanfinish_spill_pointers (void) 269790075Sobrien{ 269890075Sobrien current_frame_info.gr_used_mask = spill_fill_data.save_gr_used_mask; 269990075Sobrien} 270090075Sobrien 270190075Sobrienstatic rtx 2702132718Skanspill_restore_mem (rtx reg, HOST_WIDE_INT cfa_off) 270390075Sobrien{ 270490075Sobrien int iter = spill_fill_data.next_iter; 270590075Sobrien HOST_WIDE_INT disp = spill_fill_data.prev_off[iter] - cfa_off; 270690075Sobrien rtx disp_rtx = GEN_INT (disp); 270790075Sobrien rtx mem; 270890075Sobrien 270990075Sobrien if (spill_fill_data.prev_addr[iter]) 271090075Sobrien { 271190075Sobrien if (CONST_OK_FOR_N (disp)) 271290075Sobrien { 271390075Sobrien *spill_fill_data.prev_addr[iter] 271490075Sobrien = gen_rtx_POST_MODIFY (DImode, spill_fill_data.iter_reg[iter], 271590075Sobrien gen_rtx_PLUS (DImode, 271690075Sobrien spill_fill_data.iter_reg[iter], 271790075Sobrien disp_rtx)); 271890075Sobrien REG_NOTES (spill_fill_data.prev_insn[iter]) 271990075Sobrien = gen_rtx_EXPR_LIST (REG_INC, spill_fill_data.iter_reg[iter], 272090075Sobrien REG_NOTES (spill_fill_data.prev_insn[iter])); 272190075Sobrien } 272290075Sobrien else 272390075Sobrien { 272490075Sobrien /* ??? Could use register post_modify for loads. */ 272590075Sobrien if (! CONST_OK_FOR_I (disp)) 272690075Sobrien { 272790075Sobrien rtx tmp = gen_rtx_REG (DImode, next_scratch_gr_reg ()); 272890075Sobrien emit_move_insn (tmp, disp_rtx); 272990075Sobrien disp_rtx = tmp; 273090075Sobrien } 273190075Sobrien emit_insn (gen_adddi3 (spill_fill_data.iter_reg[iter], 273290075Sobrien spill_fill_data.iter_reg[iter], disp_rtx)); 273390075Sobrien } 273490075Sobrien } 273590075Sobrien /* Micro-optimization: if we've created a frame pointer, it's at 273690075Sobrien CFA 0, which may allow the real iterator to be initialized lower, 273790075Sobrien slightly increasing parallelism. Also, if there are few saves 273890075Sobrien it may eliminate the iterator entirely. */ 273990075Sobrien else if (disp == 0 274090075Sobrien && spill_fill_data.init_reg[iter] == stack_pointer_rtx 274190075Sobrien && frame_pointer_needed) 274290075Sobrien { 274390075Sobrien mem = gen_rtx_MEM (GET_MODE (reg), hard_frame_pointer_rtx); 274490075Sobrien set_mem_alias_set (mem, get_varargs_alias_set ()); 274590075Sobrien return mem; 274690075Sobrien } 274790075Sobrien else 274890075Sobrien { 274990075Sobrien rtx seq, insn; 275090075Sobrien 275190075Sobrien if (disp == 0) 275290075Sobrien seq = gen_movdi (spill_fill_data.iter_reg[iter], 275390075Sobrien spill_fill_data.init_reg[iter]); 275490075Sobrien else 275590075Sobrien { 275690075Sobrien start_sequence (); 275790075Sobrien 275890075Sobrien if (! CONST_OK_FOR_I (disp)) 275990075Sobrien { 276090075Sobrien rtx tmp = gen_rtx_REG (DImode, next_scratch_gr_reg ()); 276190075Sobrien emit_move_insn (tmp, disp_rtx); 276290075Sobrien disp_rtx = tmp; 276390075Sobrien } 276490075Sobrien 276590075Sobrien emit_insn (gen_adddi3 (spill_fill_data.iter_reg[iter], 276690075Sobrien spill_fill_data.init_reg[iter], 276790075Sobrien disp_rtx)); 276890075Sobrien 2769117395Skan seq = get_insns (); 277090075Sobrien end_sequence (); 277190075Sobrien } 277290075Sobrien 277390075Sobrien /* Careful for being the first insn in a sequence. */ 277490075Sobrien if (spill_fill_data.init_after) 277590075Sobrien insn = emit_insn_after (seq, spill_fill_data.init_after); 277690075Sobrien else 277790075Sobrien { 277890075Sobrien rtx first = get_insns (); 277990075Sobrien if (first) 278090075Sobrien insn = emit_insn_before (seq, first); 278190075Sobrien else 278290075Sobrien insn = emit_insn (seq); 278390075Sobrien } 278490075Sobrien spill_fill_data.init_after = insn; 278590075Sobrien 278690075Sobrien /* If DISP is 0, we may or may not have a further adjustment 278790075Sobrien afterward. If we do, then the load/store insn may be modified 278890075Sobrien to be a post-modify. If we don't, then this copy may be 278990075Sobrien eliminated by copyprop_hardreg_forward, which makes this 279090075Sobrien insn garbage, which runs afoul of the sanity check in 279190075Sobrien propagate_one_insn. So mark this insn as legal to delete. */ 279290075Sobrien if (disp == 0) 279390075Sobrien REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, 279490075Sobrien REG_NOTES (insn)); 279590075Sobrien } 279690075Sobrien 279790075Sobrien mem = gen_rtx_MEM (GET_MODE (reg), spill_fill_data.iter_reg[iter]); 279890075Sobrien 279990075Sobrien /* ??? Not all of the spills are for varargs, but some of them are. 280090075Sobrien The rest of the spills belong in an alias set of their own. But 280190075Sobrien it doesn't actually hurt to include them here. */ 280290075Sobrien set_mem_alias_set (mem, get_varargs_alias_set ()); 280390075Sobrien 280490075Sobrien spill_fill_data.prev_addr[iter] = &XEXP (mem, 0); 280590075Sobrien spill_fill_data.prev_off[iter] = cfa_off; 280690075Sobrien 280790075Sobrien if (++iter >= spill_fill_data.n_iter) 280890075Sobrien iter = 0; 280990075Sobrien spill_fill_data.next_iter = iter; 281090075Sobrien 281190075Sobrien return mem; 281290075Sobrien} 281390075Sobrien 281490075Sobrienstatic void 2815132718Skando_spill (rtx (*move_fn) (rtx, rtx, rtx), rtx reg, HOST_WIDE_INT cfa_off, 2816132718Skan rtx frame_reg) 281790075Sobrien{ 281890075Sobrien int iter = spill_fill_data.next_iter; 281990075Sobrien rtx mem, insn; 282090075Sobrien 282190075Sobrien mem = spill_restore_mem (reg, cfa_off); 282290075Sobrien insn = emit_insn ((*move_fn) (mem, reg, GEN_INT (cfa_off))); 282390075Sobrien spill_fill_data.prev_insn[iter] = insn; 282490075Sobrien 282590075Sobrien if (frame_reg) 282690075Sobrien { 282790075Sobrien rtx base; 282890075Sobrien HOST_WIDE_INT off; 282990075Sobrien 283090075Sobrien RTX_FRAME_RELATED_P (insn) = 1; 283190075Sobrien 2832132718Skan /* Don't even pretend that the unwind code can intuit its way 283390075Sobrien through a pair of interleaved post_modify iterators. Just 283490075Sobrien provide the correct answer. */ 283590075Sobrien 283690075Sobrien if (frame_pointer_needed) 283790075Sobrien { 283890075Sobrien base = hard_frame_pointer_rtx; 283990075Sobrien off = - cfa_off; 284090075Sobrien } 284190075Sobrien else 284290075Sobrien { 284390075Sobrien base = stack_pointer_rtx; 284490075Sobrien off = current_frame_info.total_size - cfa_off; 284590075Sobrien } 284690075Sobrien 284790075Sobrien REG_NOTES (insn) 284890075Sobrien = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 284990075Sobrien gen_rtx_SET (VOIDmode, 285090075Sobrien gen_rtx_MEM (GET_MODE (reg), 285190075Sobrien plus_constant (base, off)), 285290075Sobrien frame_reg), 285390075Sobrien REG_NOTES (insn)); 285490075Sobrien } 285590075Sobrien} 285690075Sobrien 285790075Sobrienstatic void 2858132718Skando_restore (rtx (*move_fn) (rtx, rtx, rtx), rtx reg, HOST_WIDE_INT cfa_off) 285990075Sobrien{ 286090075Sobrien int iter = spill_fill_data.next_iter; 286190075Sobrien rtx insn; 286290075Sobrien 286390075Sobrien insn = emit_insn ((*move_fn) (reg, spill_restore_mem (reg, cfa_off), 286490075Sobrien GEN_INT (cfa_off))); 286590075Sobrien spill_fill_data.prev_insn[iter] = insn; 286690075Sobrien} 286790075Sobrien 286890075Sobrien/* Wrapper functions that discards the CONST_INT spill offset. These 286990075Sobrien exist so that we can give gr_spill/gr_fill the offset they need and 2870132718Skan use a consistent function interface. */ 287190075Sobrien 287290075Sobrienstatic rtx 2873132718Skangen_movdi_x (rtx dest, rtx src, rtx offset ATTRIBUTE_UNUSED) 287490075Sobrien{ 287590075Sobrien return gen_movdi (dest, src); 287690075Sobrien} 287790075Sobrien 287890075Sobrienstatic rtx 2879132718Skangen_fr_spill_x (rtx dest, rtx src, rtx offset ATTRIBUTE_UNUSED) 288090075Sobrien{ 288190075Sobrien return gen_fr_spill (dest, src); 288290075Sobrien} 288390075Sobrien 288490075Sobrienstatic rtx 2885132718Skangen_fr_restore_x (rtx dest, rtx src, rtx offset ATTRIBUTE_UNUSED) 288690075Sobrien{ 288790075Sobrien return gen_fr_restore (dest, src); 288890075Sobrien} 288990075Sobrien 289090075Sobrien/* Called after register allocation to add any instructions needed for the 289190075Sobrien prologue. Using a prologue insn is favored compared to putting all of the 289290075Sobrien instructions in output_function_prologue(), since it allows the scheduler 289390075Sobrien to intermix instructions with the saves of the caller saved registers. In 289490075Sobrien some cases, it might be necessary to emit a barrier instruction as the last 289590075Sobrien insn to prevent such scheduling. 289690075Sobrien 289790075Sobrien Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1 289890075Sobrien so that the debug info generation code can handle them properly. 289990075Sobrien 290090075Sobrien The register save area is layed out like so: 290190075Sobrien cfa+16 290290075Sobrien [ varargs spill area ] 290390075Sobrien [ fr register spill area ] 290490075Sobrien [ br register spill area ] 290590075Sobrien [ ar register spill area ] 290690075Sobrien [ pr register spill area ] 290790075Sobrien [ gr register spill area ] */ 290890075Sobrien 290990075Sobrien/* ??? Get inefficient code when the frame size is larger than can fit in an 291090075Sobrien adds instruction. */ 291190075Sobrien 291290075Sobrienvoid 2913132718Skania64_expand_prologue (void) 291490075Sobrien{ 291590075Sobrien rtx insn, ar_pfs_save_reg, ar_unat_save_reg; 291690075Sobrien int i, epilogue_p, regno, alt_regno, cfa_off, n_varargs; 291790075Sobrien rtx reg, alt_reg; 291890075Sobrien 291990075Sobrien ia64_compute_frame_size (get_frame_size ()); 292090075Sobrien last_scratch_gr_reg = 15; 292190075Sobrien 292290075Sobrien /* If there is no epilogue, then we don't need some prologue insns. 292390075Sobrien We need to avoid emitting the dead prologue insns, because flow 292490075Sobrien will complain about them. */ 292590075Sobrien if (optimize) 292690075Sobrien { 292790075Sobrien edge e; 2928169689Skan edge_iterator ei; 292990075Sobrien 2930169689Skan FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) 293190075Sobrien if ((e->flags & EDGE_FAKE) == 0 293290075Sobrien && (e->flags & EDGE_FALLTHRU) != 0) 293390075Sobrien break; 293490075Sobrien epilogue_p = (e != NULL); 293590075Sobrien } 293690075Sobrien else 293790075Sobrien epilogue_p = 1; 293890075Sobrien 293990075Sobrien /* Set the local, input, and output register names. We need to do this 294090075Sobrien for GNU libc, which creates crti.S/crtn.S by splitting initfini.c in 294190075Sobrien half. If we use in/loc/out register names, then we get assembler errors 294290075Sobrien in crtn.S because there is no alloc insn or regstk directive in there. */ 294390075Sobrien if (! TARGET_REG_NAMES) 294490075Sobrien { 294590075Sobrien int inputs = current_frame_info.n_input_regs; 294690075Sobrien int locals = current_frame_info.n_local_regs; 294790075Sobrien int outputs = current_frame_info.n_output_regs; 294890075Sobrien 294990075Sobrien for (i = 0; i < inputs; i++) 295090075Sobrien reg_names[IN_REG (i)] = ia64_reg_numbers[i]; 295190075Sobrien for (i = 0; i < locals; i++) 295290075Sobrien reg_names[LOC_REG (i)] = ia64_reg_numbers[inputs + i]; 295390075Sobrien for (i = 0; i < outputs; i++) 295490075Sobrien reg_names[OUT_REG (i)] = ia64_reg_numbers[inputs + locals + i]; 295590075Sobrien } 295690075Sobrien 295790075Sobrien /* Set the frame pointer register name. The regnum is logically loc79, 295890075Sobrien but of course we'll not have allocated that many locals. Rather than 295990075Sobrien worrying about renumbering the existing rtxs, we adjust the name. */ 296090075Sobrien /* ??? This code means that we can never use one local register when 296190075Sobrien there is a frame pointer. loc79 gets wasted in this case, as it is 296290075Sobrien renamed to a register that will never be used. See also the try_locals 296390075Sobrien code in find_gr_spill. */ 296490075Sobrien if (current_frame_info.reg_fp) 296590075Sobrien { 296690075Sobrien const char *tmp = reg_names[HARD_FRAME_POINTER_REGNUM]; 296790075Sobrien reg_names[HARD_FRAME_POINTER_REGNUM] 296890075Sobrien = reg_names[current_frame_info.reg_fp]; 296990075Sobrien reg_names[current_frame_info.reg_fp] = tmp; 297090075Sobrien } 297190075Sobrien 297290075Sobrien /* We don't need an alloc instruction if we've used no outputs or locals. */ 297390075Sobrien if (current_frame_info.n_local_regs == 0 297490075Sobrien && current_frame_info.n_output_regs == 0 2975117395Skan && current_frame_info.n_input_regs <= current_function_args_info.int_regs 2976117395Skan && !TEST_HARD_REG_BIT (current_frame_info.mask, AR_PFS_REGNUM)) 297790075Sobrien { 297890075Sobrien /* If there is no alloc, but there are input registers used, then we 297990075Sobrien need a .regstk directive. */ 298090075Sobrien current_frame_info.need_regstk = (TARGET_REG_NAMES != 0); 298190075Sobrien ar_pfs_save_reg = NULL_RTX; 298290075Sobrien } 298390075Sobrien else 298490075Sobrien { 298590075Sobrien current_frame_info.need_regstk = 0; 298690075Sobrien 298790075Sobrien if (current_frame_info.reg_save_ar_pfs) 298890075Sobrien regno = current_frame_info.reg_save_ar_pfs; 298990075Sobrien else 299090075Sobrien regno = next_scratch_gr_reg (); 299190075Sobrien ar_pfs_save_reg = gen_rtx_REG (DImode, regno); 299290075Sobrien 2993132718Skan insn = emit_insn (gen_alloc (ar_pfs_save_reg, 299490075Sobrien GEN_INT (current_frame_info.n_input_regs), 299590075Sobrien GEN_INT (current_frame_info.n_local_regs), 299690075Sobrien GEN_INT (current_frame_info.n_output_regs), 299790075Sobrien GEN_INT (current_frame_info.n_rotate_regs))); 299890075Sobrien RTX_FRAME_RELATED_P (insn) = (current_frame_info.reg_save_ar_pfs != 0); 299990075Sobrien } 300090075Sobrien 300190075Sobrien /* Set up frame pointer, stack pointer, and spill iterators. */ 300290075Sobrien 300390075Sobrien n_varargs = cfun->machine->n_varargs; 300490075Sobrien setup_spill_pointers (current_frame_info.n_spilled + n_varargs, 300590075Sobrien stack_pointer_rtx, 0); 300690075Sobrien 300790075Sobrien if (frame_pointer_needed) 300890075Sobrien { 300990075Sobrien insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); 301090075Sobrien RTX_FRAME_RELATED_P (insn) = 1; 301190075Sobrien } 301290075Sobrien 301390075Sobrien if (current_frame_info.total_size != 0) 301490075Sobrien { 301590075Sobrien rtx frame_size_rtx = GEN_INT (- current_frame_info.total_size); 301690075Sobrien rtx offset; 301790075Sobrien 301890075Sobrien if (CONST_OK_FOR_I (- current_frame_info.total_size)) 301990075Sobrien offset = frame_size_rtx; 302090075Sobrien else 302190075Sobrien { 302290075Sobrien regno = next_scratch_gr_reg (); 3023132718Skan offset = gen_rtx_REG (DImode, regno); 302490075Sobrien emit_move_insn (offset, frame_size_rtx); 302590075Sobrien } 302690075Sobrien 302790075Sobrien insn = emit_insn (gen_adddi3 (stack_pointer_rtx, 302890075Sobrien stack_pointer_rtx, offset)); 302990075Sobrien 303090075Sobrien if (! frame_pointer_needed) 303190075Sobrien { 303290075Sobrien RTX_FRAME_RELATED_P (insn) = 1; 303390075Sobrien if (GET_CODE (offset) != CONST_INT) 303490075Sobrien { 303590075Sobrien REG_NOTES (insn) 303690075Sobrien = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 303790075Sobrien gen_rtx_SET (VOIDmode, 303890075Sobrien stack_pointer_rtx, 303990075Sobrien gen_rtx_PLUS (DImode, 304090075Sobrien stack_pointer_rtx, 304190075Sobrien frame_size_rtx)), 304290075Sobrien REG_NOTES (insn)); 304390075Sobrien } 304490075Sobrien } 304590075Sobrien 304690075Sobrien /* ??? At this point we must generate a magic insn that appears to 304790075Sobrien modify the stack pointer, the frame pointer, and all spill 304890075Sobrien iterators. This would allow the most scheduling freedom. For 304990075Sobrien now, just hard stop. */ 305090075Sobrien emit_insn (gen_blockage ()); 305190075Sobrien } 305290075Sobrien 305390075Sobrien /* Must copy out ar.unat before doing any integer spills. */ 305490075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM)) 305590075Sobrien { 305690075Sobrien if (current_frame_info.reg_save_ar_unat) 305790075Sobrien ar_unat_save_reg 305890075Sobrien = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_unat); 305990075Sobrien else 306090075Sobrien { 306190075Sobrien alt_regno = next_scratch_gr_reg (); 306290075Sobrien ar_unat_save_reg = gen_rtx_REG (DImode, alt_regno); 306390075Sobrien current_frame_info.gr_used_mask |= 1 << alt_regno; 306490075Sobrien } 306590075Sobrien 306690075Sobrien reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); 306790075Sobrien insn = emit_move_insn (ar_unat_save_reg, reg); 306890075Sobrien RTX_FRAME_RELATED_P (insn) = (current_frame_info.reg_save_ar_unat != 0); 306990075Sobrien 307090075Sobrien /* Even if we're not going to generate an epilogue, we still 307190075Sobrien need to save the register so that EH works. */ 307290075Sobrien if (! epilogue_p && current_frame_info.reg_save_ar_unat) 307390075Sobrien emit_insn (gen_prologue_use (ar_unat_save_reg)); 307490075Sobrien } 307590075Sobrien else 307690075Sobrien ar_unat_save_reg = NULL_RTX; 307790075Sobrien 307890075Sobrien /* Spill all varargs registers. Do this before spilling any GR registers, 307990075Sobrien since we want the UNAT bits for the GR registers to override the UNAT 308090075Sobrien bits from varargs, which we don't care about. */ 308190075Sobrien 308290075Sobrien cfa_off = -16; 308390075Sobrien for (regno = GR_ARG_FIRST + 7; n_varargs > 0; --n_varargs, --regno) 308490075Sobrien { 308590075Sobrien reg = gen_rtx_REG (DImode, regno); 308690075Sobrien do_spill (gen_gr_spill, reg, cfa_off += 8, NULL_RTX); 308790075Sobrien } 308890075Sobrien 308990075Sobrien /* Locate the bottom of the register save area. */ 309090075Sobrien cfa_off = (current_frame_info.spill_cfa_off 309190075Sobrien + current_frame_info.spill_size 309290075Sobrien + current_frame_info.extra_spill_size); 309390075Sobrien 309490075Sobrien /* Save the predicate register block either in a register or in memory. */ 309590075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, PR_REG (0))) 309690075Sobrien { 309790075Sobrien reg = gen_rtx_REG (DImode, PR_REG (0)); 309890075Sobrien if (current_frame_info.reg_save_pr != 0) 309990075Sobrien { 310090075Sobrien alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_pr); 310190075Sobrien insn = emit_move_insn (alt_reg, reg); 310290075Sobrien 310390075Sobrien /* ??? Denote pr spill/fill by a DImode move that modifies all 310490075Sobrien 64 hard registers. */ 310590075Sobrien RTX_FRAME_RELATED_P (insn) = 1; 310690075Sobrien REG_NOTES (insn) 310790075Sobrien = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 310890075Sobrien gen_rtx_SET (VOIDmode, alt_reg, reg), 310990075Sobrien REG_NOTES (insn)); 311090075Sobrien 311190075Sobrien /* Even if we're not going to generate an epilogue, we still 311290075Sobrien need to save the register so that EH works. */ 311390075Sobrien if (! epilogue_p) 311490075Sobrien emit_insn (gen_prologue_use (alt_reg)); 311590075Sobrien } 311690075Sobrien else 311790075Sobrien { 311890075Sobrien alt_regno = next_scratch_gr_reg (); 311990075Sobrien alt_reg = gen_rtx_REG (DImode, alt_regno); 312090075Sobrien insn = emit_move_insn (alt_reg, reg); 312190075Sobrien do_spill (gen_movdi_x, alt_reg, cfa_off, reg); 312290075Sobrien cfa_off -= 8; 312390075Sobrien } 312490075Sobrien } 312590075Sobrien 312690075Sobrien /* Handle AR regs in numerical order. All of them get special handling. */ 312790075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM) 312890075Sobrien && current_frame_info.reg_save_ar_unat == 0) 312990075Sobrien { 313090075Sobrien reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); 313190075Sobrien do_spill (gen_movdi_x, ar_unat_save_reg, cfa_off, reg); 313290075Sobrien cfa_off -= 8; 313390075Sobrien } 313490075Sobrien 313590075Sobrien /* The alloc insn already copied ar.pfs into a general register. The 313690075Sobrien only thing we have to do now is copy that register to a stack slot 313790075Sobrien if we'd not allocated a local register for the job. */ 3138117395Skan if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_PFS_REGNUM) 3139117395Skan && current_frame_info.reg_save_ar_pfs == 0) 314090075Sobrien { 314190075Sobrien reg = gen_rtx_REG (DImode, AR_PFS_REGNUM); 314290075Sobrien do_spill (gen_movdi_x, ar_pfs_save_reg, cfa_off, reg); 314390075Sobrien cfa_off -= 8; 314490075Sobrien } 314590075Sobrien 314690075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_LC_REGNUM)) 314790075Sobrien { 314890075Sobrien reg = gen_rtx_REG (DImode, AR_LC_REGNUM); 314990075Sobrien if (current_frame_info.reg_save_ar_lc != 0) 315090075Sobrien { 315190075Sobrien alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_lc); 315290075Sobrien insn = emit_move_insn (alt_reg, reg); 315390075Sobrien RTX_FRAME_RELATED_P (insn) = 1; 315490075Sobrien 315590075Sobrien /* Even if we're not going to generate an epilogue, we still 315690075Sobrien need to save the register so that EH works. */ 315790075Sobrien if (! epilogue_p) 315890075Sobrien emit_insn (gen_prologue_use (alt_reg)); 315990075Sobrien } 316090075Sobrien else 316190075Sobrien { 316290075Sobrien alt_regno = next_scratch_gr_reg (); 316390075Sobrien alt_reg = gen_rtx_REG (DImode, alt_regno); 316490075Sobrien emit_move_insn (alt_reg, reg); 316590075Sobrien do_spill (gen_movdi_x, alt_reg, cfa_off, reg); 316690075Sobrien cfa_off -= 8; 316790075Sobrien } 316890075Sobrien } 316990075Sobrien 3170169689Skan /* Save the return pointer. */ 3171169689Skan if (TEST_HARD_REG_BIT (current_frame_info.mask, BR_REG (0))) 3172169689Skan { 3173169689Skan reg = gen_rtx_REG (DImode, BR_REG (0)); 3174169689Skan if (current_frame_info.reg_save_b0 != 0) 3175169689Skan { 3176169689Skan alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_b0); 3177169689Skan insn = emit_move_insn (alt_reg, reg); 3178169689Skan RTX_FRAME_RELATED_P (insn) = 1; 3179169689Skan 3180169689Skan /* Even if we're not going to generate an epilogue, we still 3181169689Skan need to save the register so that EH works. */ 3182169689Skan if (! epilogue_p) 3183169689Skan emit_insn (gen_prologue_use (alt_reg)); 3184169689Skan } 3185169689Skan else 3186169689Skan { 3187169689Skan alt_regno = next_scratch_gr_reg (); 3188169689Skan alt_reg = gen_rtx_REG (DImode, alt_regno); 3189169689Skan emit_move_insn (alt_reg, reg); 3190169689Skan do_spill (gen_movdi_x, alt_reg, cfa_off, reg); 3191169689Skan cfa_off -= 8; 3192169689Skan } 3193169689Skan } 3194169689Skan 3195117395Skan if (current_frame_info.reg_save_gp) 3196117395Skan { 3197117395Skan insn = emit_move_insn (gen_rtx_REG (DImode, 3198117395Skan current_frame_info.reg_save_gp), 3199117395Skan pic_offset_table_rtx); 3200117395Skan /* We don't know for sure yet if this is actually needed, since 3201117395Skan we've not split the PIC call patterns. If all of the calls 3202117395Skan are indirect, and not followed by any uses of the gp, then 3203117395Skan this save is dead. Allow it to go away. */ 3204117395Skan REG_NOTES (insn) 3205117395Skan = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, REG_NOTES (insn)); 3206117395Skan } 3207117395Skan 320890075Sobrien /* We should now be at the base of the gr/br/fr spill area. */ 3209169689Skan gcc_assert (cfa_off == (current_frame_info.spill_cfa_off 3210169689Skan + current_frame_info.spill_size)); 321190075Sobrien 321290075Sobrien /* Spill all general registers. */ 321390075Sobrien for (regno = GR_REG (1); regno <= GR_REG (31); ++regno) 321490075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) 321590075Sobrien { 321690075Sobrien reg = gen_rtx_REG (DImode, regno); 321790075Sobrien do_spill (gen_gr_spill, reg, cfa_off, reg); 321890075Sobrien cfa_off -= 8; 321990075Sobrien } 322090075Sobrien 322190075Sobrien /* Spill the rest of the BR registers. */ 322290075Sobrien for (regno = BR_REG (1); regno <= BR_REG (7); ++regno) 322390075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) 322490075Sobrien { 322590075Sobrien alt_regno = next_scratch_gr_reg (); 322690075Sobrien alt_reg = gen_rtx_REG (DImode, alt_regno); 322790075Sobrien reg = gen_rtx_REG (DImode, regno); 322890075Sobrien emit_move_insn (alt_reg, reg); 322990075Sobrien do_spill (gen_movdi_x, alt_reg, cfa_off, reg); 323090075Sobrien cfa_off -= 8; 323190075Sobrien } 323290075Sobrien 323390075Sobrien /* Align the frame and spill all FR registers. */ 323490075Sobrien for (regno = FR_REG (2); regno <= FR_REG (127); ++regno) 323590075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) 323690075Sobrien { 3237169689Skan gcc_assert (!(cfa_off & 15)); 3238132718Skan reg = gen_rtx_REG (XFmode, regno); 323990075Sobrien do_spill (gen_fr_spill_x, reg, cfa_off, reg); 324090075Sobrien cfa_off -= 16; 324190075Sobrien } 324290075Sobrien 3243169689Skan gcc_assert (cfa_off == current_frame_info.spill_cfa_off); 324490075Sobrien 324590075Sobrien finish_spill_pointers (); 324690075Sobrien} 324790075Sobrien 324890075Sobrien/* Called after register allocation to add any instructions needed for the 324990075Sobrien epilogue. Using an epilogue insn is favored compared to putting all of the 325090075Sobrien instructions in output_function_prologue(), since it allows the scheduler 325190075Sobrien to intermix instructions with the saves of the caller saved registers. In 325290075Sobrien some cases, it might be necessary to emit a barrier instruction as the last 325390075Sobrien insn to prevent such scheduling. */ 325490075Sobrien 325590075Sobrienvoid 3256132718Skania64_expand_epilogue (int sibcall_p) 325790075Sobrien{ 325890075Sobrien rtx insn, reg, alt_reg, ar_unat_save_reg; 325990075Sobrien int regno, alt_regno, cfa_off; 326090075Sobrien 326190075Sobrien ia64_compute_frame_size (get_frame_size ()); 326290075Sobrien 326390075Sobrien /* If there is a frame pointer, then we use it instead of the stack 326490075Sobrien pointer, so that the stack pointer does not need to be valid when 326590075Sobrien the epilogue starts. See EXIT_IGNORE_STACK. */ 326690075Sobrien if (frame_pointer_needed) 326790075Sobrien setup_spill_pointers (current_frame_info.n_spilled, 326890075Sobrien hard_frame_pointer_rtx, 0); 326990075Sobrien else 3270132718Skan setup_spill_pointers (current_frame_info.n_spilled, stack_pointer_rtx, 327190075Sobrien current_frame_info.total_size); 327290075Sobrien 327390075Sobrien if (current_frame_info.total_size != 0) 327490075Sobrien { 327590075Sobrien /* ??? At this point we must generate a magic insn that appears to 327690075Sobrien modify the spill iterators and the frame pointer. This would 327790075Sobrien allow the most scheduling freedom. For now, just hard stop. */ 327890075Sobrien emit_insn (gen_blockage ()); 327990075Sobrien } 328090075Sobrien 328190075Sobrien /* Locate the bottom of the register save area. */ 328290075Sobrien cfa_off = (current_frame_info.spill_cfa_off 328390075Sobrien + current_frame_info.spill_size 328490075Sobrien + current_frame_info.extra_spill_size); 328590075Sobrien 328690075Sobrien /* Restore the predicate registers. */ 328790075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, PR_REG (0))) 328890075Sobrien { 328990075Sobrien if (current_frame_info.reg_save_pr != 0) 329090075Sobrien alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_pr); 329190075Sobrien else 329290075Sobrien { 329390075Sobrien alt_regno = next_scratch_gr_reg (); 329490075Sobrien alt_reg = gen_rtx_REG (DImode, alt_regno); 329590075Sobrien do_restore (gen_movdi_x, alt_reg, cfa_off); 329690075Sobrien cfa_off -= 8; 329790075Sobrien } 329890075Sobrien reg = gen_rtx_REG (DImode, PR_REG (0)); 329990075Sobrien emit_move_insn (reg, alt_reg); 330090075Sobrien } 330190075Sobrien 330290075Sobrien /* Restore the application registers. */ 330390075Sobrien 330490075Sobrien /* Load the saved unat from the stack, but do not restore it until 330590075Sobrien after the GRs have been restored. */ 330690075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM)) 330790075Sobrien { 330890075Sobrien if (current_frame_info.reg_save_ar_unat != 0) 330990075Sobrien ar_unat_save_reg 331090075Sobrien = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_unat); 331190075Sobrien else 331290075Sobrien { 331390075Sobrien alt_regno = next_scratch_gr_reg (); 331490075Sobrien ar_unat_save_reg = gen_rtx_REG (DImode, alt_regno); 331590075Sobrien current_frame_info.gr_used_mask |= 1 << alt_regno; 331690075Sobrien do_restore (gen_movdi_x, ar_unat_save_reg, cfa_off); 331790075Sobrien cfa_off -= 8; 331890075Sobrien } 331990075Sobrien } 332090075Sobrien else 332190075Sobrien ar_unat_save_reg = NULL_RTX; 3322132718Skan 332390075Sobrien if (current_frame_info.reg_save_ar_pfs != 0) 332490075Sobrien { 332590075Sobrien alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_pfs); 332690075Sobrien reg = gen_rtx_REG (DImode, AR_PFS_REGNUM); 332790075Sobrien emit_move_insn (reg, alt_reg); 332890075Sobrien } 3329119256Skan else if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_PFS_REGNUM)) 333090075Sobrien { 333190075Sobrien alt_regno = next_scratch_gr_reg (); 333290075Sobrien alt_reg = gen_rtx_REG (DImode, alt_regno); 333390075Sobrien do_restore (gen_movdi_x, alt_reg, cfa_off); 333490075Sobrien cfa_off -= 8; 333590075Sobrien reg = gen_rtx_REG (DImode, AR_PFS_REGNUM); 333690075Sobrien emit_move_insn (reg, alt_reg); 333790075Sobrien } 333890075Sobrien 333990075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_LC_REGNUM)) 334090075Sobrien { 334190075Sobrien if (current_frame_info.reg_save_ar_lc != 0) 334290075Sobrien alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_lc); 334390075Sobrien else 334490075Sobrien { 334590075Sobrien alt_regno = next_scratch_gr_reg (); 334690075Sobrien alt_reg = gen_rtx_REG (DImode, alt_regno); 334790075Sobrien do_restore (gen_movdi_x, alt_reg, cfa_off); 334890075Sobrien cfa_off -= 8; 334990075Sobrien } 335090075Sobrien reg = gen_rtx_REG (DImode, AR_LC_REGNUM); 335190075Sobrien emit_move_insn (reg, alt_reg); 335290075Sobrien } 335390075Sobrien 3354169689Skan /* Restore the return pointer. */ 3355169689Skan if (TEST_HARD_REG_BIT (current_frame_info.mask, BR_REG (0))) 3356169689Skan { 3357169689Skan if (current_frame_info.reg_save_b0 != 0) 3358169689Skan alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_b0); 3359169689Skan else 3360169689Skan { 3361169689Skan alt_regno = next_scratch_gr_reg (); 3362169689Skan alt_reg = gen_rtx_REG (DImode, alt_regno); 3363169689Skan do_restore (gen_movdi_x, alt_reg, cfa_off); 3364169689Skan cfa_off -= 8; 3365169689Skan } 3366169689Skan reg = gen_rtx_REG (DImode, BR_REG (0)); 3367169689Skan emit_move_insn (reg, alt_reg); 3368169689Skan } 3369169689Skan 337090075Sobrien /* We should now be at the base of the gr/br/fr spill area. */ 3371169689Skan gcc_assert (cfa_off == (current_frame_info.spill_cfa_off 3372169689Skan + current_frame_info.spill_size)); 337390075Sobrien 3374117395Skan /* The GP may be stored on the stack in the prologue, but it's 3375117395Skan never restored in the epilogue. Skip the stack slot. */ 3376117395Skan if (TEST_HARD_REG_BIT (current_frame_info.mask, GR_REG (1))) 3377117395Skan cfa_off -= 8; 3378117395Skan 337990075Sobrien /* Restore all general registers. */ 3380117395Skan for (regno = GR_REG (2); regno <= GR_REG (31); ++regno) 338190075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) 338290075Sobrien { 338390075Sobrien reg = gen_rtx_REG (DImode, regno); 338490075Sobrien do_restore (gen_gr_restore, reg, cfa_off); 338590075Sobrien cfa_off -= 8; 338690075Sobrien } 3387132718Skan 3388169689Skan /* Restore the branch registers. */ 338990075Sobrien for (regno = BR_REG (1); regno <= BR_REG (7); ++regno) 339090075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) 339190075Sobrien { 339290075Sobrien alt_regno = next_scratch_gr_reg (); 339390075Sobrien alt_reg = gen_rtx_REG (DImode, alt_regno); 339490075Sobrien do_restore (gen_movdi_x, alt_reg, cfa_off); 339590075Sobrien cfa_off -= 8; 339690075Sobrien reg = gen_rtx_REG (DImode, regno); 339790075Sobrien emit_move_insn (reg, alt_reg); 339890075Sobrien } 339990075Sobrien 340090075Sobrien /* Restore floating point registers. */ 340190075Sobrien for (regno = FR_REG (2); regno <= FR_REG (127); ++regno) 340290075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) 340390075Sobrien { 3404169689Skan gcc_assert (!(cfa_off & 15)); 3405132718Skan reg = gen_rtx_REG (XFmode, regno); 340690075Sobrien do_restore (gen_fr_restore_x, reg, cfa_off); 340790075Sobrien cfa_off -= 16; 340890075Sobrien } 340990075Sobrien 341090075Sobrien /* Restore ar.unat for real. */ 341190075Sobrien if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM)) 341290075Sobrien { 341390075Sobrien reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); 341490075Sobrien emit_move_insn (reg, ar_unat_save_reg); 341590075Sobrien } 341690075Sobrien 3417169689Skan gcc_assert (cfa_off == current_frame_info.spill_cfa_off); 341890075Sobrien 341990075Sobrien finish_spill_pointers (); 342090075Sobrien 342190075Sobrien if (current_frame_info.total_size || cfun->machine->ia64_eh_epilogue_sp) 342290075Sobrien { 342390075Sobrien /* ??? At this point we must generate a magic insn that appears to 342490075Sobrien modify the spill iterators, the stack pointer, and the frame 342590075Sobrien pointer. This would allow the most scheduling freedom. For now, 342690075Sobrien just hard stop. */ 342790075Sobrien emit_insn (gen_blockage ()); 342890075Sobrien } 342990075Sobrien 343090075Sobrien if (cfun->machine->ia64_eh_epilogue_sp) 343190075Sobrien emit_move_insn (stack_pointer_rtx, cfun->machine->ia64_eh_epilogue_sp); 343290075Sobrien else if (frame_pointer_needed) 343390075Sobrien { 343490075Sobrien insn = emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); 343590075Sobrien RTX_FRAME_RELATED_P (insn) = 1; 343690075Sobrien } 343790075Sobrien else if (current_frame_info.total_size) 343890075Sobrien { 343990075Sobrien rtx offset, frame_size_rtx; 344090075Sobrien 344190075Sobrien frame_size_rtx = GEN_INT (current_frame_info.total_size); 344290075Sobrien if (CONST_OK_FOR_I (current_frame_info.total_size)) 344390075Sobrien offset = frame_size_rtx; 344490075Sobrien else 344590075Sobrien { 344690075Sobrien regno = next_scratch_gr_reg (); 344790075Sobrien offset = gen_rtx_REG (DImode, regno); 344890075Sobrien emit_move_insn (offset, frame_size_rtx); 344990075Sobrien } 345090075Sobrien 345190075Sobrien insn = emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, 345290075Sobrien offset)); 345390075Sobrien 345490075Sobrien RTX_FRAME_RELATED_P (insn) = 1; 345590075Sobrien if (GET_CODE (offset) != CONST_INT) 345690075Sobrien { 345790075Sobrien REG_NOTES (insn) 345890075Sobrien = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, 345990075Sobrien gen_rtx_SET (VOIDmode, 346090075Sobrien stack_pointer_rtx, 346190075Sobrien gen_rtx_PLUS (DImode, 346290075Sobrien stack_pointer_rtx, 346390075Sobrien frame_size_rtx)), 346490075Sobrien REG_NOTES (insn)); 346590075Sobrien } 346690075Sobrien } 346790075Sobrien 346890075Sobrien if (cfun->machine->ia64_eh_epilogue_bsp) 346990075Sobrien emit_insn (gen_set_bsp (cfun->machine->ia64_eh_epilogue_bsp)); 3470132718Skan 347190075Sobrien if (! sibcall_p) 347290075Sobrien emit_jump_insn (gen_return_internal (gen_rtx_REG (DImode, BR_REG (0)))); 347390075Sobrien else 347490075Sobrien { 347590075Sobrien int fp = GR_REG (2); 347690075Sobrien /* We need a throw away register here, r0 and r1 are reserved, so r2 is the 3477132718Skan first available call clobbered register. If there was a frame_pointer 3478132718Skan register, we may have swapped the names of r2 and HARD_FRAME_POINTER_REGNUM, 347990075Sobrien so we have to make sure we're using the string "r2" when emitting 3480132718Skan the register name for the assembler. */ 348190075Sobrien if (current_frame_info.reg_fp && current_frame_info.reg_fp == GR_REG (2)) 348290075Sobrien fp = HARD_FRAME_POINTER_REGNUM; 348390075Sobrien 348490075Sobrien /* We must emit an alloc to force the input registers to become output 348590075Sobrien registers. Otherwise, if the callee tries to pass its parameters 348690075Sobrien through to another call without an intervening alloc, then these 348790075Sobrien values get lost. */ 348890075Sobrien /* ??? We don't need to preserve all input registers. We only need to 348990075Sobrien preserve those input registers used as arguments to the sibling call. 349090075Sobrien It is unclear how to compute that number here. */ 349190075Sobrien if (current_frame_info.n_input_regs != 0) 3492146895Skan { 3493146895Skan rtx n_inputs = GEN_INT (current_frame_info.n_input_regs); 3494146895Skan insn = emit_insn (gen_alloc (gen_rtx_REG (DImode, fp), 3495146895Skan const0_rtx, const0_rtx, 3496146895Skan n_inputs, const0_rtx)); 3497146895Skan RTX_FRAME_RELATED_P (insn) = 1; 3498146895Skan } 349990075Sobrien } 350090075Sobrien} 350190075Sobrien 350290075Sobrien/* Return 1 if br.ret can do all the work required to return from a 350390075Sobrien function. */ 350490075Sobrien 350590075Sobrienint 3506132718Skania64_direct_return (void) 350790075Sobrien{ 350890075Sobrien if (reload_completed && ! frame_pointer_needed) 350990075Sobrien { 351090075Sobrien ia64_compute_frame_size (get_frame_size ()); 351190075Sobrien 351290075Sobrien return (current_frame_info.total_size == 0 351390075Sobrien && current_frame_info.n_spilled == 0 351490075Sobrien && current_frame_info.reg_save_b0 == 0 351590075Sobrien && current_frame_info.reg_save_pr == 0 351690075Sobrien && current_frame_info.reg_save_ar_pfs == 0 351790075Sobrien && current_frame_info.reg_save_ar_unat == 0 351890075Sobrien && current_frame_info.reg_save_ar_lc == 0); 351990075Sobrien } 352090075Sobrien return 0; 352190075Sobrien} 352290075Sobrien 3523122180Skan/* Return the magic cookie that we use to hold the return address 3524122180Skan during early compilation. */ 3525122180Skan 3526122180Skanrtx 3527132718Skania64_return_addr_rtx (HOST_WIDE_INT count, rtx frame ATTRIBUTE_UNUSED) 3528122180Skan{ 3529122180Skan if (count != 0) 3530122180Skan return NULL; 3531122180Skan return gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_RET_ADDR); 3532122180Skan} 3533122180Skan 3534122180Skan/* Split this value after reload, now that we know where the return 3535122180Skan address is saved. */ 3536122180Skan 3537122180Skanvoid 3538132718Skania64_split_return_addr_rtx (rtx dest) 3539122180Skan{ 3540122180Skan rtx src; 3541122180Skan 3542122180Skan if (TEST_HARD_REG_BIT (current_frame_info.mask, BR_REG (0))) 3543122180Skan { 3544122180Skan if (current_frame_info.reg_save_b0 != 0) 3545122180Skan src = gen_rtx_REG (DImode, current_frame_info.reg_save_b0); 3546122180Skan else 3547122180Skan { 3548122180Skan HOST_WIDE_INT off; 3549122180Skan unsigned int regno; 3550122180Skan 3551122180Skan /* Compute offset from CFA for BR0. */ 3552122180Skan /* ??? Must be kept in sync with ia64_expand_prologue. */ 3553122180Skan off = (current_frame_info.spill_cfa_off 3554122180Skan + current_frame_info.spill_size); 3555122180Skan for (regno = GR_REG (1); regno <= GR_REG (31); ++regno) 3556122180Skan if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) 3557122180Skan off -= 8; 3558122180Skan 3559122180Skan /* Convert CFA offset to a register based offset. */ 3560122180Skan if (frame_pointer_needed) 3561122180Skan src = hard_frame_pointer_rtx; 3562122180Skan else 3563122180Skan { 3564122180Skan src = stack_pointer_rtx; 3565122180Skan off += current_frame_info.total_size; 3566122180Skan } 3567122180Skan 3568122180Skan /* Load address into scratch register. */ 3569122180Skan if (CONST_OK_FOR_I (off)) 3570122180Skan emit_insn (gen_adddi3 (dest, src, GEN_INT (off))); 3571122180Skan else 3572122180Skan { 3573122180Skan emit_move_insn (dest, GEN_INT (off)); 3574122180Skan emit_insn (gen_adddi3 (dest, src, dest)); 3575122180Skan } 3576122180Skan 3577122180Skan src = gen_rtx_MEM (Pmode, dest); 3578122180Skan } 3579122180Skan } 3580122180Skan else 3581122180Skan src = gen_rtx_REG (DImode, BR_REG (0)); 3582122180Skan 3583122180Skan emit_move_insn (dest, src); 3584122180Skan} 3585122180Skan 358690075Sobrienint 3587132718Skania64_hard_regno_rename_ok (int from, int to) 358890075Sobrien{ 358990075Sobrien /* Don't clobber any of the registers we reserved for the prologue. */ 359090075Sobrien if (to == current_frame_info.reg_fp 359190075Sobrien || to == current_frame_info.reg_save_b0 359290075Sobrien || to == current_frame_info.reg_save_pr 359390075Sobrien || to == current_frame_info.reg_save_ar_pfs 359490075Sobrien || to == current_frame_info.reg_save_ar_unat 359590075Sobrien || to == current_frame_info.reg_save_ar_lc) 359690075Sobrien return 0; 359790075Sobrien 359890075Sobrien if (from == current_frame_info.reg_fp 359990075Sobrien || from == current_frame_info.reg_save_b0 360090075Sobrien || from == current_frame_info.reg_save_pr 360190075Sobrien || from == current_frame_info.reg_save_ar_pfs 360290075Sobrien || from == current_frame_info.reg_save_ar_unat 360390075Sobrien || from == current_frame_info.reg_save_ar_lc) 360490075Sobrien return 0; 360590075Sobrien 360690075Sobrien /* Don't use output registers outside the register frame. */ 360790075Sobrien if (OUT_REGNO_P (to) && to >= OUT_REG (current_frame_info.n_output_regs)) 360890075Sobrien return 0; 360990075Sobrien 361090075Sobrien /* Retain even/oddness on predicate register pairs. */ 361190075Sobrien if (PR_REGNO_P (from) && PR_REGNO_P (to)) 361290075Sobrien return (from & 1) == (to & 1); 361390075Sobrien 361490075Sobrien return 1; 361590075Sobrien} 361690075Sobrien 361790075Sobrien/* Target hook for assembling integer objects. Handle word-sized 361890075Sobrien aligned objects and detect the cases when @fptr is needed. */ 361990075Sobrien 362090075Sobrienstatic bool 3621132718Skania64_assemble_integer (rtx x, unsigned int size, int aligned_p) 362290075Sobrien{ 3623132718Skan if (size == POINTER_SIZE / BITS_PER_UNIT 362490075Sobrien && !(TARGET_NO_PIC || TARGET_AUTO_PIC) 362590075Sobrien && GET_CODE (x) == SYMBOL_REF 3626132718Skan && SYMBOL_REF_FUNCTION_P (x)) 362790075Sobrien { 3628146895Skan static const char * const directive[2][2] = { 3629146895Skan /* 64-bit pointer */ /* 32-bit pointer */ 3630146895Skan { "\tdata8.ua\t@fptr(", "\tdata4.ua\t@fptr("}, /* unaligned */ 3631146895Skan { "\tdata8\t@fptr(", "\tdata4\t@fptr("} /* aligned */ 3632146895Skan }; 3633146895Skan fputs (directive[(aligned_p != 0)][POINTER_SIZE == 32], asm_out_file); 363490075Sobrien output_addr_const (asm_out_file, x); 363590075Sobrien fputs (")\n", asm_out_file); 363690075Sobrien return true; 363790075Sobrien } 363890075Sobrien return default_assemble_integer (x, size, aligned_p); 363990075Sobrien} 364090075Sobrien 364190075Sobrien/* Emit the function prologue. */ 364290075Sobrien 364390075Sobrienstatic void 3644132718Skania64_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) 364590075Sobrien{ 364690075Sobrien int mask, grsave, grsave_prev; 364790075Sobrien 364890075Sobrien if (current_frame_info.need_regstk) 364990075Sobrien fprintf (file, "\t.regstk %d, %d, %d, %d\n", 365090075Sobrien current_frame_info.n_input_regs, 365190075Sobrien current_frame_info.n_local_regs, 365290075Sobrien current_frame_info.n_output_regs, 365390075Sobrien current_frame_info.n_rotate_regs); 365490075Sobrien 365590075Sobrien if (!flag_unwind_tables && (!flag_exceptions || USING_SJLJ_EXCEPTIONS)) 365690075Sobrien return; 365790075Sobrien 365890075Sobrien /* Emit the .prologue directive. */ 365990075Sobrien 366090075Sobrien mask = 0; 366190075Sobrien grsave = grsave_prev = 0; 366290075Sobrien if (current_frame_info.reg_save_b0 != 0) 366390075Sobrien { 366490075Sobrien mask |= 8; 366590075Sobrien grsave = grsave_prev = current_frame_info.reg_save_b0; 366690075Sobrien } 366790075Sobrien if (current_frame_info.reg_save_ar_pfs != 0 366890075Sobrien && (grsave_prev == 0 366990075Sobrien || current_frame_info.reg_save_ar_pfs == grsave_prev + 1)) 367090075Sobrien { 367190075Sobrien mask |= 4; 367290075Sobrien if (grsave_prev == 0) 367390075Sobrien grsave = current_frame_info.reg_save_ar_pfs; 367490075Sobrien grsave_prev = current_frame_info.reg_save_ar_pfs; 367590075Sobrien } 367690075Sobrien if (current_frame_info.reg_fp != 0 367790075Sobrien && (grsave_prev == 0 367890075Sobrien || current_frame_info.reg_fp == grsave_prev + 1)) 367990075Sobrien { 368090075Sobrien mask |= 2; 368190075Sobrien if (grsave_prev == 0) 368290075Sobrien grsave = HARD_FRAME_POINTER_REGNUM; 368390075Sobrien grsave_prev = current_frame_info.reg_fp; 368490075Sobrien } 368590075Sobrien if (current_frame_info.reg_save_pr != 0 368690075Sobrien && (grsave_prev == 0 368790075Sobrien || current_frame_info.reg_save_pr == grsave_prev + 1)) 368890075Sobrien { 368990075Sobrien mask |= 1; 369090075Sobrien if (grsave_prev == 0) 369190075Sobrien grsave = current_frame_info.reg_save_pr; 369290075Sobrien } 369390075Sobrien 3694132718Skan if (mask && TARGET_GNU_AS) 369590075Sobrien fprintf (file, "\t.prologue %d, %d\n", mask, 369690075Sobrien ia64_dbx_register_number (grsave)); 369790075Sobrien else 369890075Sobrien fputs ("\t.prologue\n", file); 369990075Sobrien 370090075Sobrien /* Emit a .spill directive, if necessary, to relocate the base of 370190075Sobrien the register spill area. */ 370290075Sobrien if (current_frame_info.spill_cfa_off != -16) 370390075Sobrien fprintf (file, "\t.spill %ld\n", 370490075Sobrien (long) (current_frame_info.spill_cfa_off 370590075Sobrien + current_frame_info.spill_size)); 370690075Sobrien} 370790075Sobrien 370890075Sobrien/* Emit the .body directive at the scheduled end of the prologue. */ 370990075Sobrien 371090075Sobrienstatic void 3711132718Skania64_output_function_end_prologue (FILE *file) 371290075Sobrien{ 371390075Sobrien if (!flag_unwind_tables && (!flag_exceptions || USING_SJLJ_EXCEPTIONS)) 371490075Sobrien return; 371590075Sobrien 371690075Sobrien fputs ("\t.body\n", file); 371790075Sobrien} 371890075Sobrien 371990075Sobrien/* Emit the function epilogue. */ 372090075Sobrien 372190075Sobrienstatic void 3722132718Skania64_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, 3723132718Skan HOST_WIDE_INT size ATTRIBUTE_UNUSED) 372490075Sobrien{ 372590075Sobrien int i; 372690075Sobrien 372790075Sobrien if (current_frame_info.reg_fp) 372890075Sobrien { 372990075Sobrien const char *tmp = reg_names[HARD_FRAME_POINTER_REGNUM]; 373090075Sobrien reg_names[HARD_FRAME_POINTER_REGNUM] 373190075Sobrien = reg_names[current_frame_info.reg_fp]; 373290075Sobrien reg_names[current_frame_info.reg_fp] = tmp; 373390075Sobrien } 373490075Sobrien if (! TARGET_REG_NAMES) 373590075Sobrien { 373690075Sobrien for (i = 0; i < current_frame_info.n_input_regs; i++) 373790075Sobrien reg_names[IN_REG (i)] = ia64_input_reg_names[i]; 373890075Sobrien for (i = 0; i < current_frame_info.n_local_regs; i++) 373990075Sobrien reg_names[LOC_REG (i)] = ia64_local_reg_names[i]; 374090075Sobrien for (i = 0; i < current_frame_info.n_output_regs; i++) 374190075Sobrien reg_names[OUT_REG (i)] = ia64_output_reg_names[i]; 374290075Sobrien } 374390075Sobrien 374490075Sobrien current_frame_info.initialized = 0; 374590075Sobrien} 374690075Sobrien 374790075Sobrienint 3748132718Skania64_dbx_register_number (int regno) 374990075Sobrien{ 375090075Sobrien /* In ia64_expand_prologue we quite literally renamed the frame pointer 375190075Sobrien from its home at loc79 to something inside the register frame. We 375290075Sobrien must perform the same renumbering here for the debug info. */ 375390075Sobrien if (current_frame_info.reg_fp) 375490075Sobrien { 375590075Sobrien if (regno == HARD_FRAME_POINTER_REGNUM) 375690075Sobrien regno = current_frame_info.reg_fp; 375790075Sobrien else if (regno == current_frame_info.reg_fp) 375890075Sobrien regno = HARD_FRAME_POINTER_REGNUM; 375990075Sobrien } 376090075Sobrien 376190075Sobrien if (IN_REGNO_P (regno)) 376290075Sobrien return 32 + regno - IN_REG (0); 376390075Sobrien else if (LOC_REGNO_P (regno)) 376490075Sobrien return 32 + current_frame_info.n_input_regs + regno - LOC_REG (0); 376590075Sobrien else if (OUT_REGNO_P (regno)) 376690075Sobrien return (32 + current_frame_info.n_input_regs 376790075Sobrien + current_frame_info.n_local_regs + regno - OUT_REG (0)); 376890075Sobrien else 376990075Sobrien return regno; 377090075Sobrien} 377190075Sobrien 377290075Sobrienvoid 3773132718Skania64_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain) 377490075Sobrien{ 377590075Sobrien rtx addr_reg, eight = GEN_INT (8); 377690075Sobrien 3777132718Skan /* The Intel assembler requires that the global __ia64_trampoline symbol 3778132718Skan be declared explicitly */ 3779132718Skan if (!TARGET_GNU_AS) 3780132718Skan { 3781132718Skan static bool declared_ia64_trampoline = false; 3782132718Skan 3783132718Skan if (!declared_ia64_trampoline) 3784132718Skan { 3785132718Skan declared_ia64_trampoline = true; 3786132718Skan (*targetm.asm_out.globalize_label) (asm_out_file, 3787132718Skan "__ia64_trampoline"); 3788132718Skan } 3789132718Skan } 3790132718Skan 3791169689Skan /* Make sure addresses are Pmode even if we are in ILP32 mode. */ 3792169689Skan addr = convert_memory_address (Pmode, addr); 3793169689Skan fnaddr = convert_memory_address (Pmode, fnaddr); 3794169689Skan static_chain = convert_memory_address (Pmode, static_chain); 3795169689Skan 379690075Sobrien /* Load up our iterator. */ 379790075Sobrien addr_reg = gen_reg_rtx (Pmode); 379890075Sobrien emit_move_insn (addr_reg, addr); 379990075Sobrien 380090075Sobrien /* The first two words are the fake descriptor: 380190075Sobrien __ia64_trampoline, ADDR+16. */ 380290075Sobrien emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), 380390075Sobrien gen_rtx_SYMBOL_REF (Pmode, "__ia64_trampoline")); 380490075Sobrien emit_insn (gen_adddi3 (addr_reg, addr_reg, eight)); 380590075Sobrien 380690075Sobrien emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), 380790075Sobrien copy_to_reg (plus_constant (addr, 16))); 380890075Sobrien emit_insn (gen_adddi3 (addr_reg, addr_reg, eight)); 380990075Sobrien 381090075Sobrien /* The third word is the target descriptor. */ 381190075Sobrien emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), fnaddr); 381290075Sobrien emit_insn (gen_adddi3 (addr_reg, addr_reg, eight)); 381390075Sobrien 381490075Sobrien /* The fourth word is the static chain. */ 381590075Sobrien emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), static_chain); 381690075Sobrien} 381790075Sobrien 381890075Sobrien/* Do any needed setup for a variadic function. CUM has not been updated 381990075Sobrien for the last named argument which has type TYPE and mode MODE. 382090075Sobrien 382190075Sobrien We generate the actual spill instructions during prologue generation. */ 382290075Sobrien 3823169689Skanstatic void 3824169689Skania64_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 3825169689Skan tree type, int * pretend_size, 3826132718Skan int second_time ATTRIBUTE_UNUSED) 382790075Sobrien{ 3828169689Skan CUMULATIVE_ARGS next_cum = *cum; 3829169689Skan 3830117395Skan /* Skip the current argument. */ 3831169689Skan ia64_function_arg_advance (&next_cum, mode, type, 1); 383290075Sobrien 3833169689Skan if (next_cum.words < MAX_ARGUMENT_SLOTS) 383490075Sobrien { 3835169689Skan int n = MAX_ARGUMENT_SLOTS - next_cum.words; 383690075Sobrien *pretend_size = n * UNITS_PER_WORD; 383790075Sobrien cfun->machine->n_varargs = n; 383890075Sobrien } 383990075Sobrien} 384090075Sobrien 384190075Sobrien/* Check whether TYPE is a homogeneous floating point aggregate. If 384290075Sobrien it is, return the mode of the floating point type that appears 384390075Sobrien in all leafs. If it is not, return VOIDmode. 384490075Sobrien 384590075Sobrien An aggregate is a homogeneous floating point aggregate is if all 384690075Sobrien fields/elements in it have the same floating point type (e.g, 3847169689Skan SFmode). 128-bit quad-precision floats are excluded. 384890075Sobrien 3849169689Skan Variable sized aggregates should never arrive here, since we should 3850169689Skan have already decided to pass them by reference. Top-level zero-sized 3851169689Skan aggregates are excluded because our parallels crash the middle-end. */ 3852169689Skan 385390075Sobrienstatic enum machine_mode 3854169689Skanhfa_element_mode (tree type, bool nested) 385590075Sobrien{ 385690075Sobrien enum machine_mode element_mode = VOIDmode; 385790075Sobrien enum machine_mode mode; 385890075Sobrien enum tree_code code = TREE_CODE (type); 385990075Sobrien int know_element_mode = 0; 386090075Sobrien tree t; 386190075Sobrien 3862169689Skan if (!nested && (!TYPE_SIZE (type) || integer_zerop (TYPE_SIZE (type)))) 3863169689Skan return VOIDmode; 3864169689Skan 386590075Sobrien switch (code) 386690075Sobrien { 386790075Sobrien case VOID_TYPE: case INTEGER_TYPE: case ENUMERAL_TYPE: 3868169689Skan case BOOLEAN_TYPE: case POINTER_TYPE: 386990075Sobrien case OFFSET_TYPE: case REFERENCE_TYPE: case METHOD_TYPE: 3870169689Skan case LANG_TYPE: case FUNCTION_TYPE: 387190075Sobrien return VOIDmode; 387290075Sobrien 387390075Sobrien /* Fortran complex types are supposed to be HFAs, so we need to handle 387490075Sobrien gcc's COMPLEX_TYPEs as HFAs. We need to exclude the integral complex 387590075Sobrien types though. */ 387690075Sobrien case COMPLEX_TYPE: 3877117395Skan if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT 3878132718Skan && TYPE_MODE (type) != TCmode) 3879132718Skan return GET_MODE_INNER (TYPE_MODE (type)); 388090075Sobrien else 388190075Sobrien return VOIDmode; 388290075Sobrien 388390075Sobrien case REAL_TYPE: 388490075Sobrien /* We want to return VOIDmode for raw REAL_TYPEs, but the actual 388590075Sobrien mode if this is contained within an aggregate. */ 3886132718Skan if (nested && TYPE_MODE (type) != TFmode) 388790075Sobrien return TYPE_MODE (type); 388890075Sobrien else 388990075Sobrien return VOIDmode; 389090075Sobrien 389190075Sobrien case ARRAY_TYPE: 389296263Sobrien return hfa_element_mode (TREE_TYPE (type), 1); 389390075Sobrien 389490075Sobrien case RECORD_TYPE: 389590075Sobrien case UNION_TYPE: 389690075Sobrien case QUAL_UNION_TYPE: 389790075Sobrien for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t)) 389890075Sobrien { 389990075Sobrien if (TREE_CODE (t) != FIELD_DECL) 390090075Sobrien continue; 390190075Sobrien 390290075Sobrien mode = hfa_element_mode (TREE_TYPE (t), 1); 390390075Sobrien if (know_element_mode) 390490075Sobrien { 390590075Sobrien if (mode != element_mode) 390690075Sobrien return VOIDmode; 390790075Sobrien } 390890075Sobrien else if (GET_MODE_CLASS (mode) != MODE_FLOAT) 390990075Sobrien return VOIDmode; 391090075Sobrien else 391190075Sobrien { 391290075Sobrien know_element_mode = 1; 391390075Sobrien element_mode = mode; 391490075Sobrien } 391590075Sobrien } 391690075Sobrien return element_mode; 391790075Sobrien 391890075Sobrien default: 391990075Sobrien /* If we reach here, we probably have some front-end specific type 392090075Sobrien that the backend doesn't know about. This can happen via the 392190075Sobrien aggregate_value_p call in init_function_start. All we can do is 392290075Sobrien ignore unknown tree types. */ 392390075Sobrien return VOIDmode; 392490075Sobrien } 392590075Sobrien 392690075Sobrien return VOIDmode; 392790075Sobrien} 392890075Sobrien 3929132718Skan/* Return the number of words required to hold a quantity of TYPE and MODE 3930132718Skan when passed as an argument. */ 3931132718Skanstatic int 3932132718Skania64_function_arg_words (tree type, enum machine_mode mode) 3933132718Skan{ 3934132718Skan int words; 3935132718Skan 3936132718Skan if (mode == BLKmode) 3937132718Skan words = int_size_in_bytes (type); 3938132718Skan else 3939132718Skan words = GET_MODE_SIZE (mode); 3940132718Skan 3941132718Skan return (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD; /* round up */ 3942132718Skan} 3943132718Skan 3944132718Skan/* Return the number of registers that should be skipped so the current 3945132718Skan argument (described by TYPE and WORDS) will be properly aligned. 3946132718Skan 3947132718Skan Integer and float arguments larger than 8 bytes start at the next 3948132718Skan even boundary. Aggregates larger than 8 bytes start at the next 3949132718Skan even boundary if the aggregate has 16 byte alignment. Note that 3950132718Skan in the 32-bit ABI, TImode and TFmode have only 8-byte alignment 3951132718Skan but are still to be aligned in registers. 3952132718Skan 3953132718Skan ??? The ABI does not specify how to handle aggregates with 3954132718Skan alignment from 9 to 15 bytes, or greater than 16. We handle them 3955132718Skan all as if they had 16 byte alignment. Such aggregates can occur 3956132718Skan only if gcc extensions are used. */ 3957132718Skanstatic int 3958132718Skania64_function_arg_offset (CUMULATIVE_ARGS *cum, tree type, int words) 3959132718Skan{ 3960132718Skan if ((cum->words & 1) == 0) 3961132718Skan return 0; 3962132718Skan 3963132718Skan if (type 3964132718Skan && TREE_CODE (type) != INTEGER_TYPE 3965132718Skan && TREE_CODE (type) != REAL_TYPE) 3966132718Skan return TYPE_ALIGN (type) > 8 * BITS_PER_UNIT; 3967132718Skan else 3968132718Skan return words > 1; 3969132718Skan} 3970132718Skan 397190075Sobrien/* Return rtx for register where argument is passed, or zero if it is passed 397290075Sobrien on the stack. */ 397390075Sobrien/* ??? 128-bit quad-precision floats are always passed in general 397490075Sobrien registers. */ 397590075Sobrien 397690075Sobrienrtx 3977132718Skania64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, 3978132718Skan int named, int incoming) 397990075Sobrien{ 398090075Sobrien int basereg = (incoming ? GR_ARG_FIRST : AR_ARG_FIRST); 3981132718Skan int words = ia64_function_arg_words (type, mode); 3982132718Skan int offset = ia64_function_arg_offset (cum, type, words); 398390075Sobrien enum machine_mode hfa_mode = VOIDmode; 398490075Sobrien 398590075Sobrien /* If all argument slots are used, then it must go on the stack. */ 398690075Sobrien if (cum->words + offset >= MAX_ARGUMENT_SLOTS) 398790075Sobrien return 0; 398890075Sobrien 398990075Sobrien /* Check for and handle homogeneous FP aggregates. */ 399090075Sobrien if (type) 399190075Sobrien hfa_mode = hfa_element_mode (type, 0); 399290075Sobrien 399390075Sobrien /* Unnamed prototyped hfas are passed as usual. Named prototyped hfas 399490075Sobrien and unprototyped hfas are passed specially. */ 399590075Sobrien if (hfa_mode != VOIDmode && (! cum->prototype || named)) 399690075Sobrien { 399790075Sobrien rtx loc[16]; 399890075Sobrien int i = 0; 399990075Sobrien int fp_regs = cum->fp_regs; 400090075Sobrien int int_regs = cum->words + offset; 400190075Sobrien int hfa_size = GET_MODE_SIZE (hfa_mode); 400290075Sobrien int byte_size; 400390075Sobrien int args_byte_size; 400490075Sobrien 400590075Sobrien /* If prototyped, pass it in FR regs then GR regs. 400690075Sobrien If not prototyped, pass it in both FR and GR regs. 400790075Sobrien 400890075Sobrien If this is an SFmode aggregate, then it is possible to run out of 400990075Sobrien FR regs while GR regs are still left. In that case, we pass the 401090075Sobrien remaining part in the GR regs. */ 401190075Sobrien 401290075Sobrien /* Fill the FP regs. We do this always. We stop if we reach the end 401390075Sobrien of the argument, the last FP register, or the last argument slot. */ 401490075Sobrien 401590075Sobrien byte_size = ((mode == BLKmode) 401690075Sobrien ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 401790075Sobrien args_byte_size = int_regs * UNITS_PER_WORD; 401890075Sobrien offset = 0; 401990075Sobrien for (; (offset < byte_size && fp_regs < MAX_ARGUMENT_SLOTS 402090075Sobrien && args_byte_size < (MAX_ARGUMENT_SLOTS * UNITS_PER_WORD)); i++) 402190075Sobrien { 402290075Sobrien loc[i] = gen_rtx_EXPR_LIST (VOIDmode, 402390075Sobrien gen_rtx_REG (hfa_mode, (FR_ARG_FIRST 402490075Sobrien + fp_regs)), 402590075Sobrien GEN_INT (offset)); 402690075Sobrien offset += hfa_size; 402790075Sobrien args_byte_size += hfa_size; 402890075Sobrien fp_regs++; 402990075Sobrien } 403090075Sobrien 403190075Sobrien /* If no prototype, then the whole thing must go in GR regs. */ 403290075Sobrien if (! cum->prototype) 403390075Sobrien offset = 0; 403490075Sobrien /* If this is an SFmode aggregate, then we might have some left over 403590075Sobrien that needs to go in GR regs. */ 403690075Sobrien else if (byte_size != offset) 403790075Sobrien int_regs += offset / UNITS_PER_WORD; 403890075Sobrien 403990075Sobrien /* Fill in the GR regs. We must use DImode here, not the hfa mode. */ 404090075Sobrien 404190075Sobrien for (; offset < byte_size && int_regs < MAX_ARGUMENT_SLOTS; i++) 404290075Sobrien { 404390075Sobrien enum machine_mode gr_mode = DImode; 4044132718Skan unsigned int gr_size; 404590075Sobrien 404690075Sobrien /* If we have an odd 4 byte hunk because we ran out of FR regs, 404790075Sobrien then this goes in a GR reg left adjusted/little endian, right 404890075Sobrien adjusted/big endian. */ 404990075Sobrien /* ??? Currently this is handled wrong, because 4-byte hunks are 405090075Sobrien always right adjusted/little endian. */ 405190075Sobrien if (offset & 0x4) 405290075Sobrien gr_mode = SImode; 405390075Sobrien /* If we have an even 4 byte hunk because the aggregate is a 405490075Sobrien multiple of 4 bytes in size, then this goes in a GR reg right 405590075Sobrien adjusted/little endian. */ 405690075Sobrien else if (byte_size - offset == 4) 405790075Sobrien gr_mode = SImode; 405890075Sobrien 405990075Sobrien loc[i] = gen_rtx_EXPR_LIST (VOIDmode, 406090075Sobrien gen_rtx_REG (gr_mode, (basereg 406190075Sobrien + int_regs)), 406290075Sobrien GEN_INT (offset)); 4063132718Skan 4064132718Skan gr_size = GET_MODE_SIZE (gr_mode); 4065132718Skan offset += gr_size; 4066132718Skan if (gr_size == UNITS_PER_WORD 4067132718Skan || (gr_size < UNITS_PER_WORD && offset % UNITS_PER_WORD == 0)) 4068132718Skan int_regs++; 4069132718Skan else if (gr_size > UNITS_PER_WORD) 4070132718Skan int_regs += gr_size / UNITS_PER_WORD; 407190075Sobrien } 4072169689Skan return gen_rtx_PARALLEL (mode, gen_rtvec_v (i, loc)); 407390075Sobrien } 407490075Sobrien 407590075Sobrien /* Integral and aggregates go in general registers. If we have run out of 407690075Sobrien FR registers, then FP values must also go in general registers. This can 407790075Sobrien happen when we have a SFmode HFA. */ 4078132718Skan else if (mode == TFmode || mode == TCmode 4079132718Skan || (! FLOAT_MODE_P (mode) || cum->fp_regs == MAX_ARGUMENT_SLOTS)) 4080117395Skan { 4081117395Skan int byte_size = ((mode == BLKmode) 4082117395Skan ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 4083117395Skan if (BYTES_BIG_ENDIAN 4084117395Skan && (mode == BLKmode || (type && AGGREGATE_TYPE_P (type))) 4085117395Skan && byte_size < UNITS_PER_WORD 4086117395Skan && byte_size > 0) 4087117395Skan { 4088117395Skan rtx gr_reg = gen_rtx_EXPR_LIST (VOIDmode, 4089117395Skan gen_rtx_REG (DImode, 4090117395Skan (basereg + cum->words 4091117395Skan + offset)), 4092117395Skan const0_rtx); 4093117395Skan return gen_rtx_PARALLEL (mode, gen_rtvec (1, gr_reg)); 4094117395Skan } 4095117395Skan else 4096117395Skan return gen_rtx_REG (mode, basereg + cum->words + offset); 409790075Sobrien 4098117395Skan } 4099117395Skan 410090075Sobrien /* If there is a prototype, then FP values go in a FR register when 4101132718Skan named, and in a GR register when unnamed. */ 410290075Sobrien else if (cum->prototype) 410390075Sobrien { 4104132718Skan if (named) 4105132718Skan return gen_rtx_REG (mode, FR_ARG_FIRST + cum->fp_regs); 4106132718Skan /* In big-endian mode, an anonymous SFmode value must be represented 4107132718Skan as (parallel:SF [(expr_list (reg:DI n) (const_int 0))]) to force 4108132718Skan the value into the high half of the general register. */ 4109132718Skan else if (BYTES_BIG_ENDIAN && mode == SFmode) 4110132718Skan return gen_rtx_PARALLEL (mode, 4111132718Skan gen_rtvec (1, 4112132718Skan gen_rtx_EXPR_LIST (VOIDmode, 4113132718Skan gen_rtx_REG (DImode, basereg + cum->words + offset), 4114132718Skan const0_rtx))); 4115132718Skan else 411690075Sobrien return gen_rtx_REG (mode, basereg + cum->words + offset); 411790075Sobrien } 411890075Sobrien /* If there is no prototype, then FP values go in both FR and GR 411990075Sobrien registers. */ 412090075Sobrien else 412190075Sobrien { 4122132718Skan /* See comment above. */ 4123132718Skan enum machine_mode inner_mode = 4124132718Skan (BYTES_BIG_ENDIAN && mode == SFmode) ? DImode : mode; 4125132718Skan 412690075Sobrien rtx fp_reg = gen_rtx_EXPR_LIST (VOIDmode, 412790075Sobrien gen_rtx_REG (mode, (FR_ARG_FIRST 412890075Sobrien + cum->fp_regs)), 412990075Sobrien const0_rtx); 413090075Sobrien rtx gr_reg = gen_rtx_EXPR_LIST (VOIDmode, 4131132718Skan gen_rtx_REG (inner_mode, 413290075Sobrien (basereg + cum->words 413390075Sobrien + offset)), 413490075Sobrien const0_rtx); 413590075Sobrien 413690075Sobrien return gen_rtx_PARALLEL (mode, gen_rtvec (2, fp_reg, gr_reg)); 413790075Sobrien } 413890075Sobrien} 413990075Sobrien 4140169689Skan/* Return number of bytes, at the beginning of the argument, that must be 414190075Sobrien put in registers. 0 is the argument is entirely in registers or entirely 414290075Sobrien in memory. */ 414390075Sobrien 4144169689Skanstatic int 4145169689Skania64_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, 4146169689Skan tree type, bool named ATTRIBUTE_UNUSED) 414790075Sobrien{ 4148132718Skan int words = ia64_function_arg_words (type, mode); 4149132718Skan int offset = ia64_function_arg_offset (cum, type, words); 415090075Sobrien 415190075Sobrien /* If all argument slots are used, then it must go on the stack. */ 415290075Sobrien if (cum->words + offset >= MAX_ARGUMENT_SLOTS) 415390075Sobrien return 0; 415490075Sobrien 415590075Sobrien /* It doesn't matter whether the argument goes in FR or GR regs. If 415690075Sobrien it fits within the 8 argument slots, then it goes entirely in 415790075Sobrien registers. If it extends past the last argument slot, then the rest 415890075Sobrien goes on the stack. */ 415990075Sobrien 416090075Sobrien if (words + cum->words + offset <= MAX_ARGUMENT_SLOTS) 416190075Sobrien return 0; 416290075Sobrien 4163169689Skan return (MAX_ARGUMENT_SLOTS - cum->words - offset) * UNITS_PER_WORD; 416490075Sobrien} 416590075Sobrien 416690075Sobrien/* Update CUM to point after this argument. This is patterned after 416790075Sobrien ia64_function_arg. */ 416890075Sobrien 416990075Sobrienvoid 4170132718Skania64_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, 4171132718Skan tree type, int named) 417290075Sobrien{ 4173132718Skan int words = ia64_function_arg_words (type, mode); 4174132718Skan int offset = ia64_function_arg_offset (cum, type, words); 417590075Sobrien enum machine_mode hfa_mode = VOIDmode; 417690075Sobrien 417790075Sobrien /* If all arg slots are already full, then there is nothing to do. */ 417890075Sobrien if (cum->words >= MAX_ARGUMENT_SLOTS) 417990075Sobrien return; 418090075Sobrien 418190075Sobrien cum->words += words + offset; 418290075Sobrien 418390075Sobrien /* Check for and handle homogeneous FP aggregates. */ 418490075Sobrien if (type) 418590075Sobrien hfa_mode = hfa_element_mode (type, 0); 418690075Sobrien 418790075Sobrien /* Unnamed prototyped hfas are passed as usual. Named prototyped hfas 418890075Sobrien and unprototyped hfas are passed specially. */ 418990075Sobrien if (hfa_mode != VOIDmode && (! cum->prototype || named)) 419090075Sobrien { 419190075Sobrien int fp_regs = cum->fp_regs; 419290075Sobrien /* This is the original value of cum->words + offset. */ 419390075Sobrien int int_regs = cum->words - words; 419490075Sobrien int hfa_size = GET_MODE_SIZE (hfa_mode); 419590075Sobrien int byte_size; 419690075Sobrien int args_byte_size; 419790075Sobrien 419890075Sobrien /* If prototyped, pass it in FR regs then GR regs. 419990075Sobrien If not prototyped, pass it in both FR and GR regs. 420090075Sobrien 420190075Sobrien If this is an SFmode aggregate, then it is possible to run out of 420290075Sobrien FR regs while GR regs are still left. In that case, we pass the 420390075Sobrien remaining part in the GR regs. */ 420490075Sobrien 420590075Sobrien /* Fill the FP regs. We do this always. We stop if we reach the end 420690075Sobrien of the argument, the last FP register, or the last argument slot. */ 420790075Sobrien 420890075Sobrien byte_size = ((mode == BLKmode) 420990075Sobrien ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); 421090075Sobrien args_byte_size = int_regs * UNITS_PER_WORD; 421190075Sobrien offset = 0; 421290075Sobrien for (; (offset < byte_size && fp_regs < MAX_ARGUMENT_SLOTS 421390075Sobrien && args_byte_size < (MAX_ARGUMENT_SLOTS * UNITS_PER_WORD));) 421490075Sobrien { 421590075Sobrien offset += hfa_size; 421690075Sobrien args_byte_size += hfa_size; 421790075Sobrien fp_regs++; 421890075Sobrien } 421990075Sobrien 422090075Sobrien cum->fp_regs = fp_regs; 422190075Sobrien } 422290075Sobrien 4223169689Skan /* Integral and aggregates go in general registers. So do TFmode FP values. 4224169689Skan If we have run out of FR registers, then other FP values must also go in 4225169689Skan general registers. This can happen when we have a SFmode HFA. */ 4226169689Skan else if (mode == TFmode || mode == TCmode 4227169689Skan || (! FLOAT_MODE_P (mode) || cum->fp_regs == MAX_ARGUMENT_SLOTS)) 422896263Sobrien cum->int_regs = cum->words; 422990075Sobrien 423090075Sobrien /* If there is a prototype, then FP values go in a FR register when 4231132718Skan named, and in a GR register when unnamed. */ 423290075Sobrien else if (cum->prototype) 423390075Sobrien { 423490075Sobrien if (! named) 423596263Sobrien cum->int_regs = cum->words; 423690075Sobrien else 423790075Sobrien /* ??? Complex types should not reach here. */ 423890075Sobrien cum->fp_regs += (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT ? 2 : 1); 423990075Sobrien } 424090075Sobrien /* If there is no prototype, then FP values go in both FR and GR 424190075Sobrien registers. */ 424290075Sobrien else 4243132718Skan { 424496263Sobrien /* ??? Complex types should not reach here. */ 424596263Sobrien cum->fp_regs += (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT ? 2 : 1); 424696263Sobrien cum->int_regs = cum->words; 424796263Sobrien } 424896263Sobrien} 424990075Sobrien 4250169689Skan/* Arguments with alignment larger than 8 bytes start at the next even 4251169689Skan boundary. On ILP32 HPUX, TFmode arguments start on next even boundary 4252169689Skan even though their normal alignment is 8 bytes. See ia64_function_arg. */ 425396263Sobrien 425496263Sobrienint 4255169689Skania64_function_arg_boundary (enum machine_mode mode, tree type) 425696263Sobrien{ 4257169689Skan 4258169689Skan if (mode == TFmode && TARGET_HPUX && TARGET_ILP32) 4259169689Skan return PARM_BOUNDARY * 2; 4260169689Skan 4261169689Skan if (type) 4262169689Skan { 4263169689Skan if (TYPE_ALIGN (type) > PARM_BOUNDARY) 4264169689Skan return PARM_BOUNDARY * 2; 4265169689Skan else 4266169689Skan return PARM_BOUNDARY; 4267169689Skan } 4268169689Skan 4269169689Skan if (GET_MODE_BITSIZE (mode) > PARM_BOUNDARY) 4270169689Skan return PARM_BOUNDARY * 2; 4271169689Skan else 4272169689Skan return PARM_BOUNDARY; 427390075Sobrien} 4274132718Skan 4275132718Skan/* True if it is OK to do sibling call optimization for the specified 4276132718Skan call expression EXP. DECL will be the called function, or NULL if 4277132718Skan this is an indirect call. */ 4278132718Skanstatic bool 4279132718Skania64_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) 4280132718Skan{ 4281146895Skan /* We can't perform a sibcall if the current function has the syscall_linkage 4282146895Skan attribute. */ 4283146895Skan if (lookup_attribute ("syscall_linkage", 4284146895Skan TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) 4285146895Skan return false; 4286146895Skan 4287132718Skan /* We must always return with our current GP. This means we can 4288132718Skan only sibcall to functions defined in the current module. */ 4289132718Skan return decl && (*targetm.binds_local_p) (decl); 4290132718Skan} 429190075Sobrien 429290075Sobrien 429390075Sobrien/* Implement va_arg. */ 429490075Sobrien 4295169689Skanstatic tree 4296169689Skania64_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) 429790075Sobrien{ 429896263Sobrien /* Variable sized types are passed by reference. */ 4299169689Skan if (pass_by_reference (NULL, TYPE_MODE (type), type, false)) 430096263Sobrien { 4301169689Skan tree ptrtype = build_pointer_type (type); 4302169689Skan tree addr = std_gimplify_va_arg_expr (valist, ptrtype, pre_p, post_p); 4303169689Skan return build_va_arg_indirect_ref (addr); 430496263Sobrien } 430596263Sobrien 4306132718Skan /* Aggregate arguments with alignment larger than 8 bytes start at 4307132718Skan the next even boundary. Integer and floating point arguments 4308132718Skan do so if they are larger than 8 bytes, whether or not they are 4309132718Skan also aligned larger than 8 bytes. */ 4310132718Skan if ((TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == INTEGER_TYPE) 4311132718Skan ? int_size_in_bytes (type) > 8 : TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) 431290075Sobrien { 4313169689Skan tree t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist, 4314169689Skan build_int_cst (NULL_TREE, 2 * UNITS_PER_WORD - 1)); 4315169689Skan t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t, 4316169689Skan build_int_cst (NULL_TREE, -2 * UNITS_PER_WORD)); 4317169689Skan t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t); 4318169689Skan gimplify_and_add (t, pre_p); 431990075Sobrien } 432090075Sobrien 4321169689Skan return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); 432290075Sobrien} 432390075Sobrien 432490075Sobrien/* Return 1 if function return value returned in memory. Return 0 if it is 432590075Sobrien in a register. */ 432690075Sobrien 4327169689Skanstatic bool 4328169689Skania64_return_in_memory (tree valtype, tree fntype ATTRIBUTE_UNUSED) 432990075Sobrien{ 433090075Sobrien enum machine_mode mode; 433190075Sobrien enum machine_mode hfa_mode; 433290075Sobrien HOST_WIDE_INT byte_size; 433390075Sobrien 433490075Sobrien mode = TYPE_MODE (valtype); 433590075Sobrien byte_size = GET_MODE_SIZE (mode); 433690075Sobrien if (mode == BLKmode) 433790075Sobrien { 433890075Sobrien byte_size = int_size_in_bytes (valtype); 433990075Sobrien if (byte_size < 0) 4340169689Skan return true; 434190075Sobrien } 434290075Sobrien 434390075Sobrien /* Hfa's with up to 8 elements are returned in the FP argument registers. */ 434490075Sobrien 434590075Sobrien hfa_mode = hfa_element_mode (valtype, 0); 434690075Sobrien if (hfa_mode != VOIDmode) 434790075Sobrien { 434890075Sobrien int hfa_size = GET_MODE_SIZE (hfa_mode); 434990075Sobrien 435090075Sobrien if (byte_size / hfa_size > MAX_ARGUMENT_SLOTS) 4351169689Skan return true; 435290075Sobrien else 4353169689Skan return false; 435490075Sobrien } 435590075Sobrien else if (byte_size > UNITS_PER_WORD * MAX_INT_RETURN_SLOTS) 4356169689Skan return true; 435790075Sobrien else 4358169689Skan return false; 435990075Sobrien} 436090075Sobrien 436190075Sobrien/* Return rtx for register that holds the function return value. */ 436290075Sobrien 436390075Sobrienrtx 4364132718Skania64_function_value (tree valtype, tree func ATTRIBUTE_UNUSED) 436590075Sobrien{ 436690075Sobrien enum machine_mode mode; 436790075Sobrien enum machine_mode hfa_mode; 436890075Sobrien 436990075Sobrien mode = TYPE_MODE (valtype); 437090075Sobrien hfa_mode = hfa_element_mode (valtype, 0); 437190075Sobrien 437290075Sobrien if (hfa_mode != VOIDmode) 437390075Sobrien { 437490075Sobrien rtx loc[8]; 437590075Sobrien int i; 437690075Sobrien int hfa_size; 437790075Sobrien int byte_size; 437890075Sobrien int offset; 437990075Sobrien 438090075Sobrien hfa_size = GET_MODE_SIZE (hfa_mode); 438190075Sobrien byte_size = ((mode == BLKmode) 438290075Sobrien ? int_size_in_bytes (valtype) : GET_MODE_SIZE (mode)); 438390075Sobrien offset = 0; 438490075Sobrien for (i = 0; offset < byte_size; i++) 438590075Sobrien { 438690075Sobrien loc[i] = gen_rtx_EXPR_LIST (VOIDmode, 438790075Sobrien gen_rtx_REG (hfa_mode, FR_ARG_FIRST + i), 438890075Sobrien GEN_INT (offset)); 438990075Sobrien offset += hfa_size; 439090075Sobrien } 4391169689Skan return gen_rtx_PARALLEL (mode, gen_rtvec_v (i, loc)); 439290075Sobrien } 4393132718Skan else if (FLOAT_TYPE_P (valtype) && mode != TFmode && mode != TCmode) 439490075Sobrien return gen_rtx_REG (mode, FR_ARG_FIRST); 439590075Sobrien else 4396117395Skan { 4397169689Skan bool need_parallel = false; 4398169689Skan 4399169689Skan /* In big-endian mode, we need to manage the layout of aggregates 4400169689Skan in the registers so that we get the bits properly aligned in 4401169689Skan the highpart of the registers. */ 4402117395Skan if (BYTES_BIG_ENDIAN 4403117395Skan && (mode == BLKmode || (valtype && AGGREGATE_TYPE_P (valtype)))) 4404169689Skan need_parallel = true; 4405169689Skan 4406169689Skan /* Something like struct S { long double x; char a[0] } is not an 4407169689Skan HFA structure, and therefore doesn't go in fp registers. But 4408169689Skan the middle-end will give it XFmode anyway, and XFmode values 4409169689Skan don't normally fit in integer registers. So we need to smuggle 4410169689Skan the value inside a parallel. */ 4411169689Skan else if (mode == XFmode || mode == XCmode || mode == RFmode) 4412169689Skan need_parallel = true; 4413169689Skan 4414169689Skan if (need_parallel) 4415117395Skan { 4416117395Skan rtx loc[8]; 4417117395Skan int offset; 4418117395Skan int bytesize; 4419117395Skan int i; 4420117395Skan 4421117395Skan offset = 0; 4422117395Skan bytesize = int_size_in_bytes (valtype); 4423169689Skan /* An empty PARALLEL is invalid here, but the return value 4424169689Skan doesn't matter for empty structs. */ 4425169689Skan if (bytesize == 0) 4426169689Skan return gen_rtx_REG (mode, GR_RET_FIRST); 4427117395Skan for (i = 0; offset < bytesize; i++) 4428117395Skan { 4429117395Skan loc[i] = gen_rtx_EXPR_LIST (VOIDmode, 4430117395Skan gen_rtx_REG (DImode, 4431117395Skan GR_RET_FIRST + i), 4432117395Skan GEN_INT (offset)); 4433117395Skan offset += UNITS_PER_WORD; 4434117395Skan } 4435117395Skan return gen_rtx_PARALLEL (mode, gen_rtvec_v (i, loc)); 4436117395Skan } 4437169689Skan 4438169689Skan return gen_rtx_REG (mode, GR_RET_FIRST); 4439117395Skan } 444090075Sobrien} 444190075Sobrien 4442169689Skan/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. 4443132718Skan We need to emit DTP-relative relocations. */ 4444132718Skan 4445169689Skanstatic void 4446132718Skania64_output_dwarf_dtprel (FILE *file, int size, rtx x) 4447132718Skan{ 4448169689Skan gcc_assert (size == 4 || size == 8); 4449169689Skan if (size == 4) 4450169689Skan fputs ("\tdata4.ua\t@dtprel(", file); 4451169689Skan else 4452169689Skan fputs ("\tdata8.ua\t@dtprel(", file); 4453132718Skan output_addr_const (file, x); 4454132718Skan fputs (")", file); 4455132718Skan} 4456132718Skan 445790075Sobrien/* Print a memory address as an operand to reference that memory location. */ 445890075Sobrien 445990075Sobrien/* ??? Do we need this? It gets used only for 'a' operands. We could perhaps 446090075Sobrien also call this from ia64_print_operand for memory addresses. */ 446190075Sobrien 446290075Sobrienvoid 4463132718Skania64_print_operand_address (FILE * stream ATTRIBUTE_UNUSED, 4464132718Skan rtx address ATTRIBUTE_UNUSED) 446590075Sobrien{ 446690075Sobrien} 446790075Sobrien 446890075Sobrien/* Print an operand to an assembler instruction. 446990075Sobrien C Swap and print a comparison operator. 447090075Sobrien D Print an FP comparison operator. 447190075Sobrien E Print 32 - constant, for SImode shifts as extract. 447290075Sobrien e Print 64 - constant, for DImode rotates. 447390075Sobrien F A floating point constant 0.0 emitted as f0, or 1.0 emitted as f1, or 447490075Sobrien a floating point register emitted normally. 447590075Sobrien I Invert a predicate register by adding 1. 447690075Sobrien J Select the proper predicate register for a condition. 447790075Sobrien j Select the inverse predicate register for a condition. 447890075Sobrien O Append .acq for volatile load. 447990075Sobrien P Postincrement of a MEM. 448090075Sobrien Q Append .rel for volatile store. 448190075Sobrien S Shift amount for shladd instruction. 448290075Sobrien T Print an 8-bit sign extended number (K) as a 32-bit unsigned number 448390075Sobrien for Intel assembler. 448490075Sobrien U Print an 8-bit sign extended number (K) as a 64-bit unsigned number 448590075Sobrien for Intel assembler. 4486169689Skan X A pair of floating point registers. 448790075Sobrien r Print register name, or constant 0 as r0. HP compatibility for 4488169689Skan Linux kernel. 4489169689Skan v Print vector constant value as an 8-byte integer value. */ 4490169689Skan 449190075Sobrienvoid 4492132718Skania64_print_operand (FILE * file, rtx x, int code) 449390075Sobrien{ 449490075Sobrien const char *str; 449590075Sobrien 449690075Sobrien switch (code) 449790075Sobrien { 449890075Sobrien case 0: 449990075Sobrien /* Handled below. */ 450090075Sobrien break; 450190075Sobrien 450290075Sobrien case 'C': 450390075Sobrien { 450490075Sobrien enum rtx_code c = swap_condition (GET_CODE (x)); 450590075Sobrien fputs (GET_RTX_NAME (c), file); 450690075Sobrien return; 450790075Sobrien } 450890075Sobrien 450990075Sobrien case 'D': 451090075Sobrien switch (GET_CODE (x)) 451190075Sobrien { 451290075Sobrien case NE: 451390075Sobrien str = "neq"; 451490075Sobrien break; 451590075Sobrien case UNORDERED: 451690075Sobrien str = "unord"; 451790075Sobrien break; 451890075Sobrien case ORDERED: 451990075Sobrien str = "ord"; 452090075Sobrien break; 452190075Sobrien default: 452290075Sobrien str = GET_RTX_NAME (GET_CODE (x)); 452390075Sobrien break; 452490075Sobrien } 452590075Sobrien fputs (str, file); 452690075Sobrien return; 452790075Sobrien 452890075Sobrien case 'E': 452990075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, 32 - INTVAL (x)); 453090075Sobrien return; 453190075Sobrien 453290075Sobrien case 'e': 453390075Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, 64 - INTVAL (x)); 453490075Sobrien return; 453590075Sobrien 453690075Sobrien case 'F': 453790075Sobrien if (x == CONST0_RTX (GET_MODE (x))) 453890075Sobrien str = reg_names [FR_REG (0)]; 453990075Sobrien else if (x == CONST1_RTX (GET_MODE (x))) 454090075Sobrien str = reg_names [FR_REG (1)]; 454190075Sobrien else 4542169689Skan { 4543169689Skan gcc_assert (GET_CODE (x) == REG); 4544169689Skan str = reg_names [REGNO (x)]; 4545169689Skan } 454690075Sobrien fputs (str, file); 454790075Sobrien return; 454890075Sobrien 454990075Sobrien case 'I': 455090075Sobrien fputs (reg_names [REGNO (x) + 1], file); 455190075Sobrien return; 455290075Sobrien 455390075Sobrien case 'J': 455490075Sobrien case 'j': 455590075Sobrien { 455690075Sobrien unsigned int regno = REGNO (XEXP (x, 0)); 455790075Sobrien if (GET_CODE (x) == EQ) 455890075Sobrien regno += 1; 455990075Sobrien if (code == 'j') 456090075Sobrien regno ^= 1; 456190075Sobrien fputs (reg_names [regno], file); 456290075Sobrien } 456390075Sobrien return; 456490075Sobrien 456590075Sobrien case 'O': 456690075Sobrien if (MEM_VOLATILE_P (x)) 456790075Sobrien fputs(".acq", file); 456890075Sobrien return; 456990075Sobrien 457090075Sobrien case 'P': 457190075Sobrien { 457290075Sobrien HOST_WIDE_INT value; 457390075Sobrien 457490075Sobrien switch (GET_CODE (XEXP (x, 0))) 457590075Sobrien { 457690075Sobrien default: 457790075Sobrien return; 457890075Sobrien 457990075Sobrien case POST_MODIFY: 458090075Sobrien x = XEXP (XEXP (XEXP (x, 0), 1), 1); 458190075Sobrien if (GET_CODE (x) == CONST_INT) 458290075Sobrien value = INTVAL (x); 4583169689Skan else 458490075Sobrien { 4585169689Skan gcc_assert (GET_CODE (x) == REG); 458690075Sobrien fprintf (file, ", %s", reg_names[REGNO (x)]); 458790075Sobrien return; 458890075Sobrien } 458990075Sobrien break; 459090075Sobrien 459190075Sobrien case POST_INC: 459290075Sobrien value = GET_MODE_SIZE (GET_MODE (x)); 459390075Sobrien break; 459490075Sobrien 459590075Sobrien case POST_DEC: 459690075Sobrien value = - (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (x)); 459790075Sobrien break; 459890075Sobrien } 459990075Sobrien 4600132718Skan fprintf (file, ", " HOST_WIDE_INT_PRINT_DEC, value); 460190075Sobrien return; 460290075Sobrien } 460390075Sobrien 460490075Sobrien case 'Q': 460590075Sobrien if (MEM_VOLATILE_P (x)) 460690075Sobrien fputs(".rel", file); 460790075Sobrien return; 460890075Sobrien 460990075Sobrien case 'S': 461090075Sobrien fprintf (file, "%d", exact_log2 (INTVAL (x))); 461190075Sobrien return; 461290075Sobrien 461390075Sobrien case 'T': 461490075Sobrien if (! TARGET_GNU_AS && GET_CODE (x) == CONST_INT) 461590075Sobrien { 461690075Sobrien fprintf (file, "0x%x", (int) INTVAL (x) & 0xffffffff); 461790075Sobrien return; 461890075Sobrien } 461990075Sobrien break; 462090075Sobrien 462190075Sobrien case 'U': 462290075Sobrien if (! TARGET_GNU_AS && GET_CODE (x) == CONST_INT) 462390075Sobrien { 462490075Sobrien const char *prefix = "0x"; 462590075Sobrien if (INTVAL (x) & 0x80000000) 462690075Sobrien { 462790075Sobrien fprintf (file, "0xffffffff"); 462890075Sobrien prefix = ""; 462990075Sobrien } 463090075Sobrien fprintf (file, "%s%x", prefix, (int) INTVAL (x) & 0xffffffff); 463190075Sobrien return; 463290075Sobrien } 463390075Sobrien break; 463490075Sobrien 4635169689Skan case 'X': 4636169689Skan { 4637169689Skan unsigned int regno = REGNO (x); 4638169689Skan fprintf (file, "%s, %s", reg_names [regno], reg_names [regno + 1]); 4639169689Skan } 4640169689Skan return; 4641169689Skan 464290075Sobrien case 'r': 464390075Sobrien /* If this operand is the constant zero, write it as register zero. 464490075Sobrien Any register, zero, or CONST_INT value is OK here. */ 464590075Sobrien if (GET_CODE (x) == REG) 464690075Sobrien fputs (reg_names[REGNO (x)], file); 464790075Sobrien else if (x == CONST0_RTX (GET_MODE (x))) 464890075Sobrien fputs ("r0", file); 464990075Sobrien else if (GET_CODE (x) == CONST_INT) 465090075Sobrien output_addr_const (file, x); 465190075Sobrien else 465290075Sobrien output_operand_lossage ("invalid %%r value"); 465390075Sobrien return; 465490075Sobrien 4655169689Skan case 'v': 4656169689Skan gcc_assert (GET_CODE (x) == CONST_VECTOR); 4657169689Skan x = simplify_subreg (DImode, x, GET_MODE (x), 0); 4658169689Skan break; 4659169689Skan 466090075Sobrien case '+': 466190075Sobrien { 466290075Sobrien const char *which; 4663132718Skan 466490075Sobrien /* For conditional branches, returns or calls, substitute 466590075Sobrien sptk, dptk, dpnt, or spnt for %s. */ 466690075Sobrien x = find_reg_note (current_output_insn, REG_BR_PROB, 0); 466790075Sobrien if (x) 466890075Sobrien { 466990075Sobrien int pred_val = INTVAL (XEXP (x, 0)); 467090075Sobrien 467190075Sobrien /* Guess top and bottom 10% statically predicted. */ 4672169689Skan if (pred_val < REG_BR_PROB_BASE / 50 4673169689Skan && br_prob_note_reliable_p (x)) 467490075Sobrien which = ".spnt"; 467590075Sobrien else if (pred_val < REG_BR_PROB_BASE / 2) 467690075Sobrien which = ".dpnt"; 4677169689Skan else if (pred_val < REG_BR_PROB_BASE / 100 * 98 4678169689Skan || !br_prob_note_reliable_p (x)) 467990075Sobrien which = ".dptk"; 468090075Sobrien else 468190075Sobrien which = ".sptk"; 468290075Sobrien } 468390075Sobrien else if (GET_CODE (current_output_insn) == CALL_INSN) 468490075Sobrien which = ".sptk"; 468590075Sobrien else 468690075Sobrien which = ".dptk"; 468790075Sobrien 468890075Sobrien fputs (which, file); 468990075Sobrien return; 469090075Sobrien } 469190075Sobrien 469290075Sobrien case ',': 469390075Sobrien x = current_insn_predicate; 469490075Sobrien if (x) 469590075Sobrien { 469690075Sobrien unsigned int regno = REGNO (XEXP (x, 0)); 469790075Sobrien if (GET_CODE (x) == EQ) 469890075Sobrien regno += 1; 469990075Sobrien fprintf (file, "(%s) ", reg_names [regno]); 470090075Sobrien } 470190075Sobrien return; 470290075Sobrien 470390075Sobrien default: 470490075Sobrien output_operand_lossage ("ia64_print_operand: unknown code"); 470590075Sobrien return; 470690075Sobrien } 470790075Sobrien 470890075Sobrien switch (GET_CODE (x)) 470990075Sobrien { 471090075Sobrien /* This happens for the spill/restore instructions. */ 471190075Sobrien case POST_INC: 471290075Sobrien case POST_DEC: 471390075Sobrien case POST_MODIFY: 471490075Sobrien x = XEXP (x, 0); 471590075Sobrien /* ... fall through ... */ 471690075Sobrien 471790075Sobrien case REG: 471890075Sobrien fputs (reg_names [REGNO (x)], file); 471990075Sobrien break; 472090075Sobrien 472190075Sobrien case MEM: 472290075Sobrien { 472390075Sobrien rtx addr = XEXP (x, 0); 4724169689Skan if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC) 472590075Sobrien addr = XEXP (addr, 0); 472690075Sobrien fprintf (file, "[%s]", reg_names [REGNO (addr)]); 472790075Sobrien break; 472890075Sobrien } 472990075Sobrien 473090075Sobrien default: 473190075Sobrien output_addr_const (file, x); 473290075Sobrien break; 473390075Sobrien } 473490075Sobrien 473590075Sobrien return; 473690075Sobrien} 473790075Sobrien 4738132718Skan/* Compute a (partial) cost for rtx X. Return true if the complete 4739132718Skan cost has been computed, and false if subexpressions should be 4740132718Skan scanned. In either case, *TOTAL contains the cost result. */ 4741132718Skan/* ??? This is incomplete. */ 4742132718Skan 4743132718Skanstatic bool 4744132718Skania64_rtx_costs (rtx x, int code, int outer_code, int *total) 4745132718Skan{ 4746132718Skan switch (code) 4747132718Skan { 4748132718Skan case CONST_INT: 4749132718Skan switch (outer_code) 4750132718Skan { 4751132718Skan case SET: 4752132718Skan *total = CONST_OK_FOR_J (INTVAL (x)) ? 0 : COSTS_N_INSNS (1); 4753132718Skan return true; 4754132718Skan case PLUS: 4755132718Skan if (CONST_OK_FOR_I (INTVAL (x))) 4756132718Skan *total = 0; 4757132718Skan else if (CONST_OK_FOR_J (INTVAL (x))) 4758132718Skan *total = 1; 4759132718Skan else 4760132718Skan *total = COSTS_N_INSNS (1); 4761132718Skan return true; 4762132718Skan default: 4763132718Skan if (CONST_OK_FOR_K (INTVAL (x)) || CONST_OK_FOR_L (INTVAL (x))) 4764132718Skan *total = 0; 4765132718Skan else 4766132718Skan *total = COSTS_N_INSNS (1); 4767132718Skan return true; 4768132718Skan } 4769132718Skan 4770132718Skan case CONST_DOUBLE: 4771132718Skan *total = COSTS_N_INSNS (1); 4772132718Skan return true; 4773132718Skan 4774132718Skan case CONST: 4775132718Skan case SYMBOL_REF: 4776132718Skan case LABEL_REF: 4777132718Skan *total = COSTS_N_INSNS (3); 4778132718Skan return true; 4779132718Skan 4780132718Skan case MULT: 4781132718Skan /* For multiplies wider than HImode, we have to go to the FPU, 4782132718Skan which normally involves copies. Plus there's the latency 4783132718Skan of the multiply itself, and the latency of the instructions to 4784132718Skan transfer integer regs to FP regs. */ 4785132718Skan /* ??? Check for FP mode. */ 4786132718Skan if (GET_MODE_SIZE (GET_MODE (x)) > 2) 4787132718Skan *total = COSTS_N_INSNS (10); 4788132718Skan else 4789132718Skan *total = COSTS_N_INSNS (2); 4790132718Skan return true; 4791132718Skan 4792132718Skan case PLUS: 4793132718Skan case MINUS: 4794132718Skan case ASHIFT: 4795132718Skan case ASHIFTRT: 4796132718Skan case LSHIFTRT: 4797132718Skan *total = COSTS_N_INSNS (1); 4798132718Skan return true; 4799132718Skan 4800132718Skan case DIV: 4801132718Skan case UDIV: 4802132718Skan case MOD: 4803132718Skan case UMOD: 4804132718Skan /* We make divide expensive, so that divide-by-constant will be 4805132718Skan optimized to a multiply. */ 4806132718Skan *total = COSTS_N_INSNS (60); 4807132718Skan return true; 4808132718Skan 4809132718Skan default: 4810132718Skan return false; 4811132718Skan } 4812132718Skan} 4813132718Skan 4814132718Skan/* Calculate the cost of moving data from a register in class FROM to 481590075Sobrien one in class TO, using MODE. */ 481690075Sobrien 481790075Sobrienint 4818132718Skania64_register_move_cost (enum machine_mode mode, enum reg_class from, 4819132718Skan enum reg_class to) 482090075Sobrien{ 482190075Sobrien /* ADDL_REGS is the same as GR_REGS for movement purposes. */ 482290075Sobrien if (to == ADDL_REGS) 482390075Sobrien to = GR_REGS; 482490075Sobrien if (from == ADDL_REGS) 482590075Sobrien from = GR_REGS; 482690075Sobrien 482790075Sobrien /* All costs are symmetric, so reduce cases by putting the 482890075Sobrien lower number class as the destination. */ 482990075Sobrien if (from < to) 483090075Sobrien { 483190075Sobrien enum reg_class tmp = to; 483290075Sobrien to = from, from = tmp; 483390075Sobrien } 483490075Sobrien 4835132718Skan /* Moving from FR<->GR in XFmode must be more expensive than 2, 483690075Sobrien so that we get secondary memory reloads. Between FR_REGS, 483790075Sobrien we have to make this at least as expensive as MEMORY_MOVE_COST 483890075Sobrien to avoid spectacularly poor register class preferencing. */ 4839169689Skan if (mode == XFmode || mode == RFmode) 484090075Sobrien { 484190075Sobrien if (to != GR_REGS || from != GR_REGS) 484290075Sobrien return MEMORY_MOVE_COST (mode, to, 0); 484390075Sobrien else 484490075Sobrien return 3; 484590075Sobrien } 484690075Sobrien 484790075Sobrien switch (to) 484890075Sobrien { 484990075Sobrien case PR_REGS: 485090075Sobrien /* Moving between PR registers takes two insns. */ 485190075Sobrien if (from == PR_REGS) 485290075Sobrien return 3; 485390075Sobrien /* Moving between PR and anything but GR is impossible. */ 485490075Sobrien if (from != GR_REGS) 485590075Sobrien return MEMORY_MOVE_COST (mode, to, 0); 485690075Sobrien break; 485790075Sobrien 485890075Sobrien case BR_REGS: 485990075Sobrien /* Moving between BR and anything but GR is impossible. */ 486090075Sobrien if (from != GR_REGS && from != GR_AND_BR_REGS) 486190075Sobrien return MEMORY_MOVE_COST (mode, to, 0); 486290075Sobrien break; 486390075Sobrien 486490075Sobrien case AR_I_REGS: 486590075Sobrien case AR_M_REGS: 486690075Sobrien /* Moving between AR and anything but GR is impossible. */ 486790075Sobrien if (from != GR_REGS) 486890075Sobrien return MEMORY_MOVE_COST (mode, to, 0); 486990075Sobrien break; 487090075Sobrien 487190075Sobrien case GR_REGS: 487290075Sobrien case FR_REGS: 4873169689Skan case FP_REGS: 487490075Sobrien case GR_AND_FR_REGS: 487590075Sobrien case GR_AND_BR_REGS: 487690075Sobrien case ALL_REGS: 487790075Sobrien break; 487890075Sobrien 487990075Sobrien default: 4880169689Skan gcc_unreachable (); 488190075Sobrien } 488290075Sobrien 488390075Sobrien return 2; 488490075Sobrien} 488590075Sobrien 4886169689Skan/* Implement PREFERRED_RELOAD_CLASS. Place additional restrictions on CLASS 4887169689Skan to use when copying X into that class. */ 4888169689Skan 4889169689Skanenum reg_class 4890169689Skania64_preferred_reload_class (rtx x, enum reg_class class) 4891169689Skan{ 4892169689Skan switch (class) 4893169689Skan { 4894169689Skan case FR_REGS: 4895169689Skan case FP_REGS: 4896169689Skan /* Don't allow volatile mem reloads into floating point registers. 4897169689Skan This is defined to force reload to choose the r/m case instead 4898169689Skan of the f/f case when reloading (set (reg fX) (mem/v)). */ 4899169689Skan if (MEM_P (x) && MEM_VOLATILE_P (x)) 4900169689Skan return NO_REGS; 4901169689Skan 4902169689Skan /* Force all unrecognized constants into the constant pool. */ 4903169689Skan if (CONSTANT_P (x)) 4904169689Skan return NO_REGS; 4905169689Skan break; 4906169689Skan 4907169689Skan case AR_M_REGS: 4908169689Skan case AR_I_REGS: 4909169689Skan if (!OBJECT_P (x)) 4910169689Skan return NO_REGS; 4911169689Skan break; 4912169689Skan 4913169689Skan default: 4914169689Skan break; 4915169689Skan } 4916169689Skan 4917169689Skan return class; 4918169689Skan} 4919169689Skan 492090075Sobrien/* This function returns the register class required for a secondary 492190075Sobrien register when copying between one of the registers in CLASS, and X, 492290075Sobrien using MODE. A return value of NO_REGS means that no secondary register 492390075Sobrien is required. */ 492490075Sobrien 492590075Sobrienenum reg_class 4926132718Skania64_secondary_reload_class (enum reg_class class, 4927132718Skan enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) 492890075Sobrien{ 492990075Sobrien int regno = -1; 493090075Sobrien 493190075Sobrien if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG) 493290075Sobrien regno = true_regnum (x); 493390075Sobrien 493490075Sobrien switch (class) 493590075Sobrien { 493690075Sobrien case BR_REGS: 493790075Sobrien case AR_M_REGS: 493890075Sobrien case AR_I_REGS: 493990075Sobrien /* ??? BR<->BR register copies can happen due to a bad gcse/cse/global 494090075Sobrien interaction. We end up with two pseudos with overlapping lifetimes 494190075Sobrien both of which are equiv to the same constant, and both which need 494290075Sobrien to be in BR_REGS. This seems to be a cse bug. cse_basic_block_end 494390075Sobrien changes depending on the path length, which means the qty_first_reg 494490075Sobrien check in make_regs_eqv can give different answers at different times. 494590075Sobrien At some point I'll probably need a reload_indi pattern to handle 494690075Sobrien this. 494790075Sobrien 494890075Sobrien We can also get GR_AND_FR_REGS to BR_REGS/AR_REGS copies, where we 494990075Sobrien wound up with a FP register from GR_AND_FR_REGS. Extend that to all 495090075Sobrien non-general registers for good measure. */ 495190075Sobrien if (regno >= 0 && ! GENERAL_REGNO_P (regno)) 495290075Sobrien return GR_REGS; 495390075Sobrien 495490075Sobrien /* This is needed if a pseudo used as a call_operand gets spilled to a 495590075Sobrien stack slot. */ 495690075Sobrien if (GET_CODE (x) == MEM) 495790075Sobrien return GR_REGS; 495890075Sobrien break; 495990075Sobrien 496090075Sobrien case FR_REGS: 4961169689Skan case FP_REGS: 4962132718Skan /* Need to go through general registers to get to other class regs. */ 496390075Sobrien if (regno >= 0 && ! (FR_REGNO_P (regno) || GENERAL_REGNO_P (regno))) 496490075Sobrien return GR_REGS; 4965132718Skan 496690075Sobrien /* This can happen when a paradoxical subreg is an operand to the 496790075Sobrien muldi3 pattern. */ 496890075Sobrien /* ??? This shouldn't be necessary after instruction scheduling is 496990075Sobrien enabled, because paradoxical subregs are not accepted by 497090075Sobrien register_operand when INSN_SCHEDULING is defined. Or alternatively, 497190075Sobrien stop the paradoxical subreg stupidity in the *_operand functions 497290075Sobrien in recog.c. */ 497390075Sobrien if (GET_CODE (x) == MEM 497490075Sobrien && (GET_MODE (x) == SImode || GET_MODE (x) == HImode 497590075Sobrien || GET_MODE (x) == QImode)) 497690075Sobrien return GR_REGS; 497790075Sobrien 497890075Sobrien /* This can happen because of the ior/and/etc patterns that accept FP 497990075Sobrien registers as operands. If the third operand is a constant, then it 498090075Sobrien needs to be reloaded into a FP register. */ 498190075Sobrien if (GET_CODE (x) == CONST_INT) 498290075Sobrien return GR_REGS; 498390075Sobrien 498490075Sobrien /* This can happen because of register elimination in a muldi3 insn. 498590075Sobrien E.g. `26107 * (unsigned long)&u'. */ 498690075Sobrien if (GET_CODE (x) == PLUS) 498790075Sobrien return GR_REGS; 498890075Sobrien break; 498990075Sobrien 499090075Sobrien case PR_REGS: 499190075Sobrien /* ??? This happens if we cse/gcse a BImode value across a call, 499290075Sobrien and the function has a nonlocal goto. This is because global 499390075Sobrien does not allocate call crossing pseudos to hard registers when 499490075Sobrien current_function_has_nonlocal_goto is true. This is relatively 499590075Sobrien common for C++ programs that use exceptions. To reproduce, 499690075Sobrien return NO_REGS and compile libstdc++. */ 499790075Sobrien if (GET_CODE (x) == MEM) 499890075Sobrien return GR_REGS; 499990075Sobrien 500090075Sobrien /* This can happen when we take a BImode subreg of a DImode value, 500190075Sobrien and that DImode value winds up in some non-GR register. */ 500290075Sobrien if (regno >= 0 && ! GENERAL_REGNO_P (regno) && ! PR_REGNO_P (regno)) 500390075Sobrien return GR_REGS; 500490075Sobrien break; 500590075Sobrien 500690075Sobrien default: 500790075Sobrien break; 500890075Sobrien } 500990075Sobrien 501090075Sobrien return NO_REGS; 501190075Sobrien} 5012132718Skan 501390075Sobrien 501490075Sobrien/* Parse the -mfixed-range= option string. */ 501590075Sobrien 501690075Sobrienstatic void 5017132718Skanfix_range (const char *const_str) 501890075Sobrien{ 501990075Sobrien int i, first, last; 502090075Sobrien char *str, *dash, *comma; 502190075Sobrien 502290075Sobrien /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and 502390075Sobrien REG2 are either register names or register numbers. The effect 502490075Sobrien of this option is to mark the registers in the range from REG1 to 502590075Sobrien REG2 as ``fixed'' so they won't be used by the compiler. This is 502690075Sobrien used, e.g., to ensure that kernel mode code doesn't use f32-f127. */ 502790075Sobrien 502890075Sobrien i = strlen (const_str); 502990075Sobrien str = (char *) alloca (i + 1); 503090075Sobrien memcpy (str, const_str, i + 1); 503190075Sobrien 503290075Sobrien while (1) 503390075Sobrien { 503490075Sobrien dash = strchr (str, '-'); 503590075Sobrien if (!dash) 503690075Sobrien { 5037169689Skan warning (0, "value of -mfixed-range must have form REG1-REG2"); 503890075Sobrien return; 503990075Sobrien } 504090075Sobrien *dash = '\0'; 504190075Sobrien 504290075Sobrien comma = strchr (dash + 1, ','); 504390075Sobrien if (comma) 504490075Sobrien *comma = '\0'; 504590075Sobrien 504690075Sobrien first = decode_reg_name (str); 504790075Sobrien if (first < 0) 504890075Sobrien { 5049169689Skan warning (0, "unknown register name: %s", str); 505090075Sobrien return; 505190075Sobrien } 505290075Sobrien 505390075Sobrien last = decode_reg_name (dash + 1); 505490075Sobrien if (last < 0) 505590075Sobrien { 5056169689Skan warning (0, "unknown register name: %s", dash + 1); 505790075Sobrien return; 505890075Sobrien } 505990075Sobrien 506090075Sobrien *dash = '-'; 506190075Sobrien 506290075Sobrien if (first > last) 506390075Sobrien { 5064169689Skan warning (0, "%s-%s is an empty range", str, dash + 1); 506590075Sobrien return; 506690075Sobrien } 506790075Sobrien 506890075Sobrien for (i = first; i <= last; ++i) 506990075Sobrien fixed_regs[i] = call_used_regs[i] = 1; 507090075Sobrien 507190075Sobrien if (!comma) 507290075Sobrien break; 507390075Sobrien 507490075Sobrien *comma = ','; 507590075Sobrien str = comma + 1; 507690075Sobrien } 507790075Sobrien} 507890075Sobrien 5079169689Skan/* Implement TARGET_HANDLE_OPTION. */ 508090075Sobrien 5081169689Skanstatic bool 5082169689Skania64_handle_option (size_t code, const char *arg, int value) 508390075Sobrien{ 5084169689Skan switch (code) 5085132718Skan { 5086169689Skan case OPT_mfixed_range_: 5087169689Skan fix_range (arg); 5088169689Skan return true; 5089132718Skan 5090169689Skan case OPT_mtls_size_: 5091169689Skan if (value != 14 && value != 22 && value != 64) 5092169689Skan error ("bad value %<%s%> for -mtls-size= switch", arg); 5093169689Skan return true; 5094132718Skan 5095169689Skan case OPT_mtune_: 5096169689Skan { 5097169689Skan static struct pta 5098169689Skan { 5099169689Skan const char *name; /* processor name or nickname. */ 5100169689Skan enum processor_type processor; 5101169689Skan } 5102169689Skan const processor_alias_table[] = 5103169689Skan { 5104169689Skan {"itanium", PROCESSOR_ITANIUM}, 5105169689Skan {"itanium1", PROCESSOR_ITANIUM}, 5106169689Skan {"merced", PROCESSOR_ITANIUM}, 5107169689Skan {"itanium2", PROCESSOR_ITANIUM2}, 5108169689Skan {"mckinley", PROCESSOR_ITANIUM2}, 5109169689Skan }; 5110169689Skan int const pta_size = ARRAY_SIZE (processor_alias_table); 5111169689Skan int i; 511290075Sobrien 5113169689Skan for (i = 0; i < pta_size; i++) 5114169689Skan if (!strcmp (arg, processor_alias_table[i].name)) 5115169689Skan { 5116169689Skan ia64_tune = processor_alias_table[i].processor; 5117169689Skan break; 5118169689Skan } 5119169689Skan if (i == pta_size) 5120169689Skan error ("bad value %<%s%> for -mtune= switch", arg); 5121169689Skan return true; 5122169689Skan } 512390075Sobrien 5124169689Skan default: 5125169689Skan return true; 5126117395Skan } 5127169689Skan} 5128117395Skan 5129169689Skan/* Implement OVERRIDE_OPTIONS. */ 5130132718Skan 5131169689Skanvoid 5132169689Skania64_override_options (void) 5133169689Skan{ 5134169689Skan if (TARGET_AUTO_PIC) 5135169689Skan target_flags |= MASK_CONST_GP; 5136132718Skan 5137169689Skan if (TARGET_INLINE_SQRT == INL_MIN_LAT) 5138117395Skan { 5139169689Skan warning (0, "not yet implemented: latency-optimized inline square root"); 5140169689Skan TARGET_INLINE_SQRT = INL_MAX_THR; 5141117395Skan } 5142117395Skan 514390075Sobrien ia64_flag_schedule_insns2 = flag_schedule_insns_after_reload; 514490075Sobrien flag_schedule_insns_after_reload = 0; 514590075Sobrien 514690075Sobrien ia64_section_threshold = g_switch_set ? g_switch_value : IA64_DEFAULT_GVALUE; 514790075Sobrien 514890075Sobrien init_machine_status = ia64_init_machine_status; 514990075Sobrien} 5150169689Skan 5151169689Skanstatic struct machine_function * 5152169689Skania64_init_machine_status (void) 5153169689Skan{ 5154169689Skan return ggc_alloc_cleared (sizeof (struct machine_function)); 5155169689Skan} 515690075Sobrien 5157132718Skanstatic enum attr_itanium_class ia64_safe_itanium_class (rtx); 5158132718Skanstatic enum attr_type ia64_safe_type (rtx); 515990075Sobrien 516090075Sobrienstatic enum attr_itanium_class 5161132718Skania64_safe_itanium_class (rtx insn) 516290075Sobrien{ 516390075Sobrien if (recog_memoized (insn) >= 0) 516490075Sobrien return get_attr_itanium_class (insn); 516590075Sobrien else 516690075Sobrien return ITANIUM_CLASS_UNKNOWN; 516790075Sobrien} 516890075Sobrien 516990075Sobrienstatic enum attr_type 5170132718Skania64_safe_type (rtx insn) 517190075Sobrien{ 517290075Sobrien if (recog_memoized (insn) >= 0) 517390075Sobrien return get_attr_type (insn); 517490075Sobrien else 517590075Sobrien return TYPE_UNKNOWN; 517690075Sobrien} 517790075Sobrien 517890075Sobrien/* The following collection of routines emit instruction group stop bits as 517990075Sobrien necessary to avoid dependencies. */ 518090075Sobrien 518190075Sobrien/* Need to track some additional registers as far as serialization is 518290075Sobrien concerned so we can properly handle br.call and br.ret. We could 518390075Sobrien make these registers visible to gcc, but since these registers are 518490075Sobrien never explicitly used in gcc generated code, it seems wasteful to 518590075Sobrien do so (plus it would make the call and return patterns needlessly 518690075Sobrien complex). */ 518790075Sobrien#define REG_RP (BR_REG (0)) 518890075Sobrien#define REG_AR_CFM (FIRST_PSEUDO_REGISTER + 1) 518990075Sobrien/* This is used for volatile asms which may require a stop bit immediately 519090075Sobrien before and after them. */ 519190075Sobrien#define REG_VOLATILE (FIRST_PSEUDO_REGISTER + 2) 519290075Sobrien#define AR_UNAT_BIT_0 (FIRST_PSEUDO_REGISTER + 3) 519390075Sobrien#define NUM_REGS (AR_UNAT_BIT_0 + 64) 519490075Sobrien 519590075Sobrien/* For each register, we keep track of how it has been written in the 519690075Sobrien current instruction group. 519790075Sobrien 519890075Sobrien If a register is written unconditionally (no qualifying predicate), 519990075Sobrien WRITE_COUNT is set to 2 and FIRST_PRED is ignored. 520090075Sobrien 520190075Sobrien If a register is written if its qualifying predicate P is true, we 520290075Sobrien set WRITE_COUNT to 1 and FIRST_PRED to P. Later on, the same register 520390075Sobrien may be written again by the complement of P (P^1) and when this happens, 520490075Sobrien WRITE_COUNT gets set to 2. 520590075Sobrien 520690075Sobrien The result of this is that whenever an insn attempts to write a register 520790075Sobrien whose WRITE_COUNT is two, we need to issue an insn group barrier first. 520890075Sobrien 520990075Sobrien If a predicate register is written by a floating-point insn, we set 521090075Sobrien WRITTEN_BY_FP to true. 521190075Sobrien 521290075Sobrien If a predicate register is written by an AND.ORCM we set WRITTEN_BY_AND 521390075Sobrien to true; if it was written by an OR.ANDCM we set WRITTEN_BY_OR to true. */ 521490075Sobrien 521590075Sobrienstruct reg_write_state 521690075Sobrien{ 521790075Sobrien unsigned int write_count : 2; 521890075Sobrien unsigned int first_pred : 16; 521990075Sobrien unsigned int written_by_fp : 1; 522090075Sobrien unsigned int written_by_and : 1; 522190075Sobrien unsigned int written_by_or : 1; 522290075Sobrien}; 522390075Sobrien 522490075Sobrien/* Cumulative info for the current instruction group. */ 522590075Sobrienstruct reg_write_state rws_sum[NUM_REGS]; 522690075Sobrien/* Info for the current instruction. This gets copied to rws_sum after a 522790075Sobrien stop bit is emitted. */ 522890075Sobrienstruct reg_write_state rws_insn[NUM_REGS]; 522990075Sobrien 523090075Sobrien/* Indicates whether this is the first instruction after a stop bit, 5231169689Skan in which case we don't need another stop bit. Without this, 5232169689Skan ia64_variable_issue will die when scheduling an alloc. */ 523390075Sobrienstatic int first_instruction; 523490075Sobrien 523590075Sobrien/* Misc flags needed to compute RAW/WAW dependencies while we are traversing 523690075Sobrien RTL for one instruction. */ 523790075Sobrienstruct reg_flags 523890075Sobrien{ 523990075Sobrien unsigned int is_write : 1; /* Is register being written? */ 524090075Sobrien unsigned int is_fp : 1; /* Is register used as part of an fp op? */ 524190075Sobrien unsigned int is_branch : 1; /* Is register used as part of a branch? */ 524290075Sobrien unsigned int is_and : 1; /* Is register used as part of and.orcm? */ 524390075Sobrien unsigned int is_or : 1; /* Is register used as part of or.andcm? */ 524490075Sobrien unsigned int is_sibcall : 1; /* Is this a sibling or normal call? */ 524590075Sobrien}; 524690075Sobrien 5247132718Skanstatic void rws_update (struct reg_write_state *, int, struct reg_flags, int); 5248132718Skanstatic int rws_access_regno (int, struct reg_flags, int); 5249132718Skanstatic int rws_access_reg (rtx, struct reg_flags, int); 5250169689Skanstatic void update_set_flags (rtx, struct reg_flags *); 5251169689Skanstatic int set_src_needs_barrier (rtx, struct reg_flags, int); 5252132718Skanstatic int rtx_needs_barrier (rtx, struct reg_flags, int); 5253132718Skanstatic void init_insn_group_barriers (void); 5254169689Skanstatic int group_barrier_needed (rtx); 5255169689Skanstatic int safe_group_barrier_needed (rtx); 525690075Sobrien 525790075Sobrien/* Update *RWS for REGNO, which is being written by the current instruction, 525890075Sobrien with predicate PRED, and associated register flags in FLAGS. */ 525990075Sobrien 526090075Sobrienstatic void 5261132718Skanrws_update (struct reg_write_state *rws, int regno, struct reg_flags flags, int pred) 526290075Sobrien{ 526390075Sobrien if (pred) 526490075Sobrien rws[regno].write_count++; 526590075Sobrien else 526690075Sobrien rws[regno].write_count = 2; 526790075Sobrien rws[regno].written_by_fp |= flags.is_fp; 526890075Sobrien /* ??? Not tracking and/or across differing predicates. */ 526990075Sobrien rws[regno].written_by_and = flags.is_and; 527090075Sobrien rws[regno].written_by_or = flags.is_or; 527190075Sobrien rws[regno].first_pred = pred; 527290075Sobrien} 527390075Sobrien 527490075Sobrien/* Handle an access to register REGNO of type FLAGS using predicate register 527590075Sobrien PRED. Update rws_insn and rws_sum arrays. Return 1 if this access creates 527690075Sobrien a dependency with an earlier instruction in the same group. */ 527790075Sobrien 527890075Sobrienstatic int 5279132718Skanrws_access_regno (int regno, struct reg_flags flags, int pred) 528090075Sobrien{ 528190075Sobrien int need_barrier = 0; 528290075Sobrien 5283169689Skan gcc_assert (regno < NUM_REGS); 528490075Sobrien 528590075Sobrien if (! PR_REGNO_P (regno)) 528690075Sobrien flags.is_and = flags.is_or = 0; 528790075Sobrien 528890075Sobrien if (flags.is_write) 528990075Sobrien { 529090075Sobrien int write_count; 529190075Sobrien 529290075Sobrien /* One insn writes same reg multiple times? */ 5293169689Skan gcc_assert (!rws_insn[regno].write_count); 529490075Sobrien 529590075Sobrien /* Update info for current instruction. */ 529690075Sobrien rws_update (rws_insn, regno, flags, pred); 529790075Sobrien write_count = rws_sum[regno].write_count; 529890075Sobrien 529990075Sobrien switch (write_count) 530090075Sobrien { 530190075Sobrien case 0: 530290075Sobrien /* The register has not been written yet. */ 530390075Sobrien rws_update (rws_sum, regno, flags, pred); 530490075Sobrien break; 530590075Sobrien 530690075Sobrien case 1: 530790075Sobrien /* The register has been written via a predicate. If this is 530890075Sobrien not a complementary predicate, then we need a barrier. */ 530990075Sobrien /* ??? This assumes that P and P+1 are always complementary 531090075Sobrien predicates for P even. */ 531190075Sobrien if (flags.is_and && rws_sum[regno].written_by_and) 5312132718Skan ; 531390075Sobrien else if (flags.is_or && rws_sum[regno].written_by_or) 531490075Sobrien ; 531590075Sobrien else if ((rws_sum[regno].first_pred ^ 1) != pred) 531690075Sobrien need_barrier = 1; 531790075Sobrien rws_update (rws_sum, regno, flags, pred); 531890075Sobrien break; 531990075Sobrien 532090075Sobrien case 2: 532190075Sobrien /* The register has been unconditionally written already. We 532290075Sobrien need a barrier. */ 532390075Sobrien if (flags.is_and && rws_sum[regno].written_by_and) 532490075Sobrien ; 532590075Sobrien else if (flags.is_or && rws_sum[regno].written_by_or) 532690075Sobrien ; 532790075Sobrien else 532890075Sobrien need_barrier = 1; 532990075Sobrien rws_sum[regno].written_by_and = flags.is_and; 533090075Sobrien rws_sum[regno].written_by_or = flags.is_or; 533190075Sobrien break; 533290075Sobrien 533390075Sobrien default: 5334169689Skan gcc_unreachable (); 533590075Sobrien } 533690075Sobrien } 533790075Sobrien else 533890075Sobrien { 533990075Sobrien if (flags.is_branch) 534090075Sobrien { 534190075Sobrien /* Branches have several RAW exceptions that allow to avoid 534290075Sobrien barriers. */ 534390075Sobrien 534490075Sobrien if (REGNO_REG_CLASS (regno) == BR_REGS || regno == AR_PFS_REGNUM) 534590075Sobrien /* RAW dependencies on branch regs are permissible as long 534690075Sobrien as the writer is a non-branch instruction. Since we 534790075Sobrien never generate code that uses a branch register written 534890075Sobrien by a branch instruction, handling this case is 534990075Sobrien easy. */ 535090075Sobrien return 0; 535190075Sobrien 535290075Sobrien if (REGNO_REG_CLASS (regno) == PR_REGS 535390075Sobrien && ! rws_sum[regno].written_by_fp) 535490075Sobrien /* The predicates of a branch are available within the 535590075Sobrien same insn group as long as the predicate was written by 535690075Sobrien something other than a floating-point instruction. */ 535790075Sobrien return 0; 535890075Sobrien } 535990075Sobrien 536090075Sobrien if (flags.is_and && rws_sum[regno].written_by_and) 536190075Sobrien return 0; 536290075Sobrien if (flags.is_or && rws_sum[regno].written_by_or) 536390075Sobrien return 0; 536490075Sobrien 536590075Sobrien switch (rws_sum[regno].write_count) 536690075Sobrien { 536790075Sobrien case 0: 536890075Sobrien /* The register has not been written yet. */ 536990075Sobrien break; 537090075Sobrien 537190075Sobrien case 1: 537290075Sobrien /* The register has been written via a predicate. If this is 537390075Sobrien not a complementary predicate, then we need a barrier. */ 537490075Sobrien /* ??? This assumes that P and P+1 are always complementary 537590075Sobrien predicates for P even. */ 537690075Sobrien if ((rws_sum[regno].first_pred ^ 1) != pred) 537790075Sobrien need_barrier = 1; 537890075Sobrien break; 537990075Sobrien 538090075Sobrien case 2: 538190075Sobrien /* The register has been unconditionally written already. We 538290075Sobrien need a barrier. */ 538390075Sobrien need_barrier = 1; 538490075Sobrien break; 538590075Sobrien 538690075Sobrien default: 5387169689Skan gcc_unreachable (); 538890075Sobrien } 538990075Sobrien } 539090075Sobrien 539190075Sobrien return need_barrier; 539290075Sobrien} 539390075Sobrien 539490075Sobrienstatic int 5395132718Skanrws_access_reg (rtx reg, struct reg_flags flags, int pred) 539690075Sobrien{ 539790075Sobrien int regno = REGNO (reg); 539890075Sobrien int n = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)); 539990075Sobrien 540090075Sobrien if (n == 1) 540190075Sobrien return rws_access_regno (regno, flags, pred); 540290075Sobrien else 540390075Sobrien { 540490075Sobrien int need_barrier = 0; 540590075Sobrien while (--n >= 0) 540690075Sobrien need_barrier |= rws_access_regno (regno + n, flags, pred); 540790075Sobrien return need_barrier; 540890075Sobrien } 540990075Sobrien} 541090075Sobrien 541190075Sobrien/* Examine X, which is a SET rtx, and update the flags, the predicate, and 541290075Sobrien the condition, stored in *PFLAGS, *PPRED and *PCOND. */ 541390075Sobrien 541490075Sobrienstatic void 5415169689Skanupdate_set_flags (rtx x, struct reg_flags *pflags) 541690075Sobrien{ 541790075Sobrien rtx src = SET_SRC (x); 541890075Sobrien 541990075Sobrien switch (GET_CODE (src)) 542090075Sobrien { 542190075Sobrien case CALL: 542290075Sobrien return; 542390075Sobrien 542490075Sobrien case IF_THEN_ELSE: 5425169689Skan /* There are four cases here: 5426169689Skan (1) The destination is (pc), in which case this is a branch, 5427169689Skan nothing here applies. 5428169689Skan (2) The destination is ar.lc, in which case this is a 5429169689Skan doloop_end_internal, 5430169689Skan (3) The destination is an fp register, in which case this is 5431169689Skan an fselect instruction. 5432169689Skan (4) The condition has (unspec [(reg)] UNSPEC_LDC), in which case 5433169689Skan this is a check load. 5434169689Skan In all cases, nothing we do in this function applies. */ 5435169689Skan return; 543690075Sobrien 543790075Sobrien default: 5438169689Skan if (COMPARISON_P (src) 5439169689Skan && SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (src, 0)))) 544090075Sobrien /* Set pflags->is_fp to 1 so that we know we're dealing 544190075Sobrien with a floating point comparison when processing the 544290075Sobrien destination of the SET. */ 544390075Sobrien pflags->is_fp = 1; 544490075Sobrien 544590075Sobrien /* Discover if this is a parallel comparison. We only handle 544690075Sobrien and.orcm and or.andcm at present, since we must retain a 544790075Sobrien strict inverse on the predicate pair. */ 544890075Sobrien else if (GET_CODE (src) == AND) 544990075Sobrien pflags->is_and = 1; 545090075Sobrien else if (GET_CODE (src) == IOR) 545190075Sobrien pflags->is_or = 1; 545290075Sobrien 545390075Sobrien break; 545490075Sobrien } 545590075Sobrien} 545690075Sobrien 545790075Sobrien/* Subroutine of rtx_needs_barrier; this function determines whether the 545890075Sobrien source of a given SET rtx found in X needs a barrier. FLAGS and PRED 545990075Sobrien are as in rtx_needs_barrier. COND is an rtx that holds the condition 546090075Sobrien for this insn. */ 5461132718Skan 546290075Sobrienstatic int 5463169689Skanset_src_needs_barrier (rtx x, struct reg_flags flags, int pred) 546490075Sobrien{ 546590075Sobrien int need_barrier = 0; 546690075Sobrien rtx dst; 546790075Sobrien rtx src = SET_SRC (x); 546890075Sobrien 546990075Sobrien if (GET_CODE (src) == CALL) 547090075Sobrien /* We don't need to worry about the result registers that 547190075Sobrien get written by subroutine call. */ 547290075Sobrien return rtx_needs_barrier (src, flags, pred); 547390075Sobrien else if (SET_DEST (x) == pc_rtx) 547490075Sobrien { 547590075Sobrien /* X is a conditional branch. */ 547690075Sobrien /* ??? This seems redundant, as the caller sets this bit for 547790075Sobrien all JUMP_INSNs. */ 5478169689Skan if (!ia64_spec_check_src_p (src)) 5479169689Skan flags.is_branch = 1; 548090075Sobrien return rtx_needs_barrier (src, flags, pred); 548190075Sobrien } 548290075Sobrien 5483169689Skan if (ia64_spec_check_src_p (src)) 5484169689Skan /* Avoid checking one register twice (in condition 5485169689Skan and in 'then' section) for ldc pattern. */ 5486169689Skan { 5487169689Skan gcc_assert (REG_P (XEXP (src, 2))); 5488169689Skan need_barrier = rtx_needs_barrier (XEXP (src, 2), flags, pred); 5489169689Skan 5490169689Skan /* We process MEM below. */ 5491169689Skan src = XEXP (src, 1); 5492169689Skan } 549390075Sobrien 5494169689Skan need_barrier |= rtx_needs_barrier (src, flags, pred); 549590075Sobrien 549690075Sobrien dst = SET_DEST (x); 549790075Sobrien if (GET_CODE (dst) == ZERO_EXTRACT) 549890075Sobrien { 549990075Sobrien need_barrier |= rtx_needs_barrier (XEXP (dst, 1), flags, pred); 550090075Sobrien need_barrier |= rtx_needs_barrier (XEXP (dst, 2), flags, pred); 550190075Sobrien } 550290075Sobrien return need_barrier; 550390075Sobrien} 550490075Sobrien 5505132718Skan/* Handle an access to rtx X of type FLAGS using predicate register 5506132718Skan PRED. Return 1 if this access creates a dependency with an earlier 5507132718Skan instruction in the same group. */ 550890075Sobrien 550990075Sobrienstatic int 5510132718Skanrtx_needs_barrier (rtx x, struct reg_flags flags, int pred) 551190075Sobrien{ 551290075Sobrien int i, j; 551390075Sobrien int is_complemented = 0; 551490075Sobrien int need_barrier = 0; 551590075Sobrien const char *format_ptr; 551690075Sobrien struct reg_flags new_flags; 5517169689Skan rtx cond; 551890075Sobrien 551990075Sobrien if (! x) 552090075Sobrien return 0; 552190075Sobrien 552290075Sobrien new_flags = flags; 552390075Sobrien 552490075Sobrien switch (GET_CODE (x)) 552590075Sobrien { 5526132718Skan case SET: 5527169689Skan update_set_flags (x, &new_flags); 5528169689Skan need_barrier = set_src_needs_barrier (x, new_flags, pred); 552990075Sobrien if (GET_CODE (SET_SRC (x)) != CALL) 553090075Sobrien { 553190075Sobrien new_flags.is_write = 1; 553290075Sobrien need_barrier |= rtx_needs_barrier (SET_DEST (x), new_flags, pred); 553390075Sobrien } 553490075Sobrien break; 553590075Sobrien 553690075Sobrien case CALL: 553790075Sobrien new_flags.is_write = 0; 553890075Sobrien need_barrier |= rws_access_regno (AR_EC_REGNUM, new_flags, pred); 553990075Sobrien 554090075Sobrien /* Avoid multiple register writes, in case this is a pattern with 5541169689Skan multiple CALL rtx. This avoids a failure in rws_access_reg. */ 554290075Sobrien if (! flags.is_sibcall && ! rws_insn[REG_AR_CFM].write_count) 554390075Sobrien { 554490075Sobrien new_flags.is_write = 1; 554590075Sobrien need_barrier |= rws_access_regno (REG_RP, new_flags, pred); 554690075Sobrien need_barrier |= rws_access_regno (AR_PFS_REGNUM, new_flags, pred); 554790075Sobrien need_barrier |= rws_access_regno (REG_AR_CFM, new_flags, pred); 554890075Sobrien } 554990075Sobrien break; 555090075Sobrien 555190075Sobrien case COND_EXEC: 555290075Sobrien /* X is a predicated instruction. */ 555390075Sobrien 555490075Sobrien cond = COND_EXEC_TEST (x); 5555169689Skan gcc_assert (!pred); 555690075Sobrien need_barrier = rtx_needs_barrier (cond, flags, 0); 555790075Sobrien 555890075Sobrien if (GET_CODE (cond) == EQ) 555990075Sobrien is_complemented = 1; 556090075Sobrien cond = XEXP (cond, 0); 5561169689Skan gcc_assert (GET_CODE (cond) == REG 5562169689Skan && REGNO_REG_CLASS (REGNO (cond)) == PR_REGS); 556390075Sobrien pred = REGNO (cond); 556490075Sobrien if (is_complemented) 556590075Sobrien ++pred; 556690075Sobrien 556790075Sobrien need_barrier |= rtx_needs_barrier (COND_EXEC_CODE (x), flags, pred); 556890075Sobrien return need_barrier; 556990075Sobrien 557090075Sobrien case CLOBBER: 557190075Sobrien case USE: 557290075Sobrien /* Clobber & use are for earlier compiler-phases only. */ 557390075Sobrien break; 557490075Sobrien 557590075Sobrien case ASM_OPERANDS: 557690075Sobrien case ASM_INPUT: 557790075Sobrien /* We always emit stop bits for traditional asms. We emit stop bits 557890075Sobrien for volatile extended asms if TARGET_VOL_ASM_STOP is true. */ 557990075Sobrien if (GET_CODE (x) != ASM_OPERANDS 558090075Sobrien || (MEM_VOLATILE_P (x) && TARGET_VOL_ASM_STOP)) 558190075Sobrien { 558290075Sobrien /* Avoid writing the register multiple times if we have multiple 5583169689Skan asm outputs. This avoids a failure in rws_access_reg. */ 558490075Sobrien if (! rws_insn[REG_VOLATILE].write_count) 558590075Sobrien { 558690075Sobrien new_flags.is_write = 1; 558790075Sobrien rws_access_regno (REG_VOLATILE, new_flags, pred); 558890075Sobrien } 558990075Sobrien return 1; 559090075Sobrien } 559190075Sobrien 559290075Sobrien /* For all ASM_OPERANDS, we must traverse the vector of input operands. 5593169689Skan We cannot just fall through here since then we would be confused 559490075Sobrien by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate 559590075Sobrien traditional asms unlike their normal usage. */ 559690075Sobrien 559790075Sobrien for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; --i) 559890075Sobrien if (rtx_needs_barrier (ASM_OPERANDS_INPUT (x, i), flags, pred)) 559990075Sobrien need_barrier = 1; 560090075Sobrien break; 560190075Sobrien 560290075Sobrien case PARALLEL: 560390075Sobrien for (i = XVECLEN (x, 0) - 1; i >= 0; --i) 560490075Sobrien { 560590075Sobrien rtx pat = XVECEXP (x, 0, i); 5606169689Skan switch (GET_CODE (pat)) 560790075Sobrien { 5608169689Skan case SET: 5609169689Skan update_set_flags (pat, &new_flags); 5610169689Skan need_barrier |= set_src_needs_barrier (pat, new_flags, pred); 5611169689Skan break; 5612169689Skan 5613169689Skan case USE: 5614169689Skan case CALL: 5615169689Skan case ASM_OPERANDS: 5616169689Skan need_barrier |= rtx_needs_barrier (pat, flags, pred); 5617169689Skan break; 5618169689Skan 5619169689Skan case CLOBBER: 5620169689Skan case RETURN: 5621169689Skan break; 5622169689Skan 5623169689Skan default: 5624169689Skan gcc_unreachable (); 562590075Sobrien } 562690075Sobrien } 562790075Sobrien for (i = XVECLEN (x, 0) - 1; i >= 0; --i) 562890075Sobrien { 562990075Sobrien rtx pat = XVECEXP (x, 0, i); 563090075Sobrien if (GET_CODE (pat) == SET) 563190075Sobrien { 563290075Sobrien if (GET_CODE (SET_SRC (pat)) != CALL) 563390075Sobrien { 563490075Sobrien new_flags.is_write = 1; 563590075Sobrien need_barrier |= rtx_needs_barrier (SET_DEST (pat), new_flags, 563690075Sobrien pred); 563790075Sobrien } 563890075Sobrien } 563990075Sobrien else if (GET_CODE (pat) == CLOBBER || GET_CODE (pat) == RETURN) 564090075Sobrien need_barrier |= rtx_needs_barrier (pat, flags, pred); 564190075Sobrien } 564290075Sobrien break; 564390075Sobrien 564490075Sobrien case SUBREG: 5645169689Skan need_barrier |= rtx_needs_barrier (SUBREG_REG (x), flags, pred); 5646169689Skan break; 564790075Sobrien case REG: 564890075Sobrien if (REGNO (x) == AR_UNAT_REGNUM) 564990075Sobrien { 565090075Sobrien for (i = 0; i < 64; ++i) 565190075Sobrien need_barrier |= rws_access_regno (AR_UNAT_BIT_0 + i, flags, pred); 565290075Sobrien } 565390075Sobrien else 565490075Sobrien need_barrier = rws_access_reg (x, flags, pred); 565590075Sobrien break; 565690075Sobrien 565790075Sobrien case MEM: 565890075Sobrien /* Find the regs used in memory address computation. */ 565990075Sobrien new_flags.is_write = 0; 566090075Sobrien need_barrier = rtx_needs_barrier (XEXP (x, 0), new_flags, pred); 566190075Sobrien break; 566290075Sobrien 5663169689Skan case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: 566490075Sobrien case SYMBOL_REF: case LABEL_REF: case CONST: 566590075Sobrien break; 566690075Sobrien 566790075Sobrien /* Operators with side-effects. */ 566890075Sobrien case POST_INC: case POST_DEC: 5669169689Skan gcc_assert (GET_CODE (XEXP (x, 0)) == REG); 567090075Sobrien 567190075Sobrien new_flags.is_write = 0; 567290075Sobrien need_barrier = rws_access_reg (XEXP (x, 0), new_flags, pred); 567390075Sobrien new_flags.is_write = 1; 567490075Sobrien need_barrier |= rws_access_reg (XEXP (x, 0), new_flags, pred); 567590075Sobrien break; 567690075Sobrien 567790075Sobrien case POST_MODIFY: 5678169689Skan gcc_assert (GET_CODE (XEXP (x, 0)) == REG); 567990075Sobrien 568090075Sobrien new_flags.is_write = 0; 568190075Sobrien need_barrier = rws_access_reg (XEXP (x, 0), new_flags, pred); 568290075Sobrien need_barrier |= rtx_needs_barrier (XEXP (x, 1), new_flags, pred); 568390075Sobrien new_flags.is_write = 1; 568490075Sobrien need_barrier |= rws_access_reg (XEXP (x, 0), new_flags, pred); 568590075Sobrien break; 568690075Sobrien 568790075Sobrien /* Handle common unary and binary ops for efficiency. */ 568890075Sobrien case COMPARE: case PLUS: case MINUS: case MULT: case DIV: 568990075Sobrien case MOD: case UDIV: case UMOD: case AND: case IOR: 569090075Sobrien case XOR: case ASHIFT: case ROTATE: case ASHIFTRT: case LSHIFTRT: 569190075Sobrien case ROTATERT: case SMIN: case SMAX: case UMIN: case UMAX: 569290075Sobrien case NE: case EQ: case GE: case GT: case LE: 569390075Sobrien case LT: case GEU: case GTU: case LEU: case LTU: 569490075Sobrien need_barrier = rtx_needs_barrier (XEXP (x, 0), new_flags, pred); 569590075Sobrien need_barrier |= rtx_needs_barrier (XEXP (x, 1), new_flags, pred); 569690075Sobrien break; 569790075Sobrien 569890075Sobrien case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: 569990075Sobrien case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT: 570090075Sobrien case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: case ABS: 5701132718Skan case SQRT: case FFS: case POPCOUNT: 570290075Sobrien need_barrier = rtx_needs_barrier (XEXP (x, 0), flags, pred); 570390075Sobrien break; 570490075Sobrien 5705169689Skan case VEC_SELECT: 5706169689Skan /* VEC_SELECT's second argument is a PARALLEL with integers that 5707169689Skan describe the elements selected. On ia64, those integers are 5708169689Skan always constants. Avoid walking the PARALLEL so that we don't 5709169689Skan get confused with "normal" parallels and then die. */ 5710169689Skan need_barrier = rtx_needs_barrier (XEXP (x, 0), flags, pred); 5711169689Skan break; 5712169689Skan 571390075Sobrien case UNSPEC: 571490075Sobrien switch (XINT (x, 1)) 571590075Sobrien { 5716117395Skan case UNSPEC_LTOFF_DTPMOD: 5717117395Skan case UNSPEC_LTOFF_DTPREL: 5718117395Skan case UNSPEC_DTPREL: 5719117395Skan case UNSPEC_LTOFF_TPREL: 5720117395Skan case UNSPEC_TPREL: 5721117395Skan case UNSPEC_PRED_REL_MUTEX: 5722117395Skan case UNSPEC_PIC_CALL: 5723117395Skan case UNSPEC_MF: 5724117395Skan case UNSPEC_FETCHADD_ACQ: 5725117395Skan case UNSPEC_BSP_VALUE: 5726117395Skan case UNSPEC_FLUSHRS: 5727117395Skan case UNSPEC_BUNDLE_SELECTOR: 5728117395Skan break; 5729117395Skan 5730117395Skan case UNSPEC_GR_SPILL: 5731117395Skan case UNSPEC_GR_RESTORE: 573290075Sobrien { 573390075Sobrien HOST_WIDE_INT offset = INTVAL (XVECEXP (x, 0, 1)); 573490075Sobrien HOST_WIDE_INT bit = (offset >> 3) & 63; 573590075Sobrien 573690075Sobrien need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred); 5737169689Skan new_flags.is_write = (XINT (x, 1) == UNSPEC_GR_SPILL); 573890075Sobrien need_barrier |= rws_access_regno (AR_UNAT_BIT_0 + bit, 573990075Sobrien new_flags, pred); 574090075Sobrien break; 574190075Sobrien } 5742132718Skan 5743117395Skan case UNSPEC_FR_SPILL: 5744117395Skan case UNSPEC_FR_RESTORE: 5745132718Skan case UNSPEC_GETF_EXP: 5746132718Skan case UNSPEC_SETF_EXP: 5747117395Skan case UNSPEC_ADDP4: 5748132718Skan case UNSPEC_FR_SQRT_RECIP_APPROX: 5749169689Skan case UNSPEC_LDA: 5750169689Skan case UNSPEC_LDS: 5751169689Skan case UNSPEC_LDSA: 5752169689Skan case UNSPEC_CHKACLR: 5753169689Skan case UNSPEC_CHKS: 575490075Sobrien need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred); 575590075Sobrien break; 575690075Sobrien 5757117395Skan case UNSPEC_FR_RECIP_APPROX: 5758169689Skan case UNSPEC_SHRP: 5759169689Skan case UNSPEC_COPYSIGN: 576090075Sobrien need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred); 576190075Sobrien need_barrier |= rtx_needs_barrier (XVECEXP (x, 0, 1), flags, pred); 576290075Sobrien break; 576390075Sobrien 5764117395Skan case UNSPEC_CMPXCHG_ACQ: 576590075Sobrien need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 1), flags, pred); 576690075Sobrien need_barrier |= rtx_needs_barrier (XVECEXP (x, 0, 2), flags, pred); 576790075Sobrien break; 576890075Sobrien 576990075Sobrien default: 5770169689Skan gcc_unreachable (); 577190075Sobrien } 577290075Sobrien break; 577390075Sobrien 577490075Sobrien case UNSPEC_VOLATILE: 577590075Sobrien switch (XINT (x, 1)) 577690075Sobrien { 5777117395Skan case UNSPECV_ALLOC: 577890075Sobrien /* Alloc must always be the first instruction of a group. 577990075Sobrien We force this by always returning true. */ 578090075Sobrien /* ??? We might get better scheduling if we explicitly check for 578190075Sobrien input/local/output register dependencies, and modify the 578290075Sobrien scheduler so that alloc is always reordered to the start of 578390075Sobrien the current group. We could then eliminate all of the 578490075Sobrien first_instruction code. */ 578590075Sobrien rws_access_regno (AR_PFS_REGNUM, flags, pred); 578690075Sobrien 578790075Sobrien new_flags.is_write = 1; 578890075Sobrien rws_access_regno (REG_AR_CFM, new_flags, pred); 578990075Sobrien return 1; 579090075Sobrien 5791117395Skan case UNSPECV_SET_BSP: 579290075Sobrien need_barrier = 1; 579390075Sobrien break; 579490075Sobrien 5795117395Skan case UNSPECV_BLOCKAGE: 5796117395Skan case UNSPECV_INSN_GROUP_BARRIER: 5797117395Skan case UNSPECV_BREAK: 5798117395Skan case UNSPECV_PSAC_ALL: 5799117395Skan case UNSPECV_PSAC_NORMAL: 580090075Sobrien return 0; 580190075Sobrien 580290075Sobrien default: 5803169689Skan gcc_unreachable (); 580490075Sobrien } 580590075Sobrien break; 580690075Sobrien 580790075Sobrien case RETURN: 580890075Sobrien new_flags.is_write = 0; 580990075Sobrien need_barrier = rws_access_regno (REG_RP, flags, pred); 581090075Sobrien need_barrier |= rws_access_regno (AR_PFS_REGNUM, flags, pred); 581190075Sobrien 581290075Sobrien new_flags.is_write = 1; 581390075Sobrien need_barrier |= rws_access_regno (AR_EC_REGNUM, new_flags, pred); 581490075Sobrien need_barrier |= rws_access_regno (REG_AR_CFM, new_flags, pred); 581590075Sobrien break; 581690075Sobrien 581790075Sobrien default: 581890075Sobrien format_ptr = GET_RTX_FORMAT (GET_CODE (x)); 581990075Sobrien for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) 582090075Sobrien switch (format_ptr[i]) 582190075Sobrien { 582290075Sobrien case '0': /* unused field */ 582390075Sobrien case 'i': /* integer */ 582490075Sobrien case 'n': /* note */ 582590075Sobrien case 'w': /* wide integer */ 582690075Sobrien case 's': /* pointer to string */ 582790075Sobrien case 'S': /* optional pointer to string */ 582890075Sobrien break; 582990075Sobrien 583090075Sobrien case 'e': 583190075Sobrien if (rtx_needs_barrier (XEXP (x, i), flags, pred)) 583290075Sobrien need_barrier = 1; 583390075Sobrien break; 583490075Sobrien 583590075Sobrien case 'E': 583690075Sobrien for (j = XVECLEN (x, i) - 1; j >= 0; --j) 583790075Sobrien if (rtx_needs_barrier (XVECEXP (x, i, j), flags, pred)) 583890075Sobrien need_barrier = 1; 583990075Sobrien break; 584090075Sobrien 584190075Sobrien default: 5842169689Skan gcc_unreachable (); 584390075Sobrien } 584490075Sobrien break; 584590075Sobrien } 584690075Sobrien return need_barrier; 584790075Sobrien} 584890075Sobrien 5849169689Skan/* Clear out the state for group_barrier_needed at the start of a 585090075Sobrien sequence of insns. */ 585190075Sobrien 585290075Sobrienstatic void 5853132718Skaninit_insn_group_barriers (void) 585490075Sobrien{ 585590075Sobrien memset (rws_sum, 0, sizeof (rws_sum)); 585690075Sobrien first_instruction = 1; 585790075Sobrien} 585890075Sobrien 5859169689Skan/* Given the current state, determine whether a group barrier (a stop bit) is 5860169689Skan necessary before INSN. Return nonzero if so. This modifies the state to 5861169689Skan include the effects of INSN as a side-effect. */ 586290075Sobrien 586390075Sobrienstatic int 5864169689Skangroup_barrier_needed (rtx insn) 586590075Sobrien{ 586690075Sobrien rtx pat; 586790075Sobrien int need_barrier = 0; 586890075Sobrien struct reg_flags flags; 586990075Sobrien 587090075Sobrien memset (&flags, 0, sizeof (flags)); 587190075Sobrien switch (GET_CODE (insn)) 587290075Sobrien { 587390075Sobrien case NOTE: 587490075Sobrien break; 587590075Sobrien 587690075Sobrien case BARRIER: 587790075Sobrien /* A barrier doesn't imply an instruction group boundary. */ 587890075Sobrien break; 587990075Sobrien 588090075Sobrien case CODE_LABEL: 588190075Sobrien memset (rws_insn, 0, sizeof (rws_insn)); 588290075Sobrien return 1; 588390075Sobrien 588490075Sobrien case CALL_INSN: 588590075Sobrien flags.is_branch = 1; 588690075Sobrien flags.is_sibcall = SIBLING_CALL_P (insn); 588790075Sobrien memset (rws_insn, 0, sizeof (rws_insn)); 588890075Sobrien 588990075Sobrien /* Don't bundle a call following another call. */ 589090075Sobrien if ((pat = prev_active_insn (insn)) 589190075Sobrien && GET_CODE (pat) == CALL_INSN) 589290075Sobrien { 589390075Sobrien need_barrier = 1; 589490075Sobrien break; 589590075Sobrien } 589690075Sobrien 589790075Sobrien need_barrier = rtx_needs_barrier (PATTERN (insn), flags, 0); 589890075Sobrien break; 589990075Sobrien 590090075Sobrien case JUMP_INSN: 5901169689Skan if (!ia64_spec_check_p (insn)) 5902169689Skan flags.is_branch = 1; 590390075Sobrien 590490075Sobrien /* Don't bundle a jump following a call. */ 590590075Sobrien if ((pat = prev_active_insn (insn)) 590690075Sobrien && GET_CODE (pat) == CALL_INSN) 590790075Sobrien { 590890075Sobrien need_barrier = 1; 590990075Sobrien break; 591090075Sobrien } 591190075Sobrien /* FALLTHRU */ 591290075Sobrien 591390075Sobrien case INSN: 591490075Sobrien if (GET_CODE (PATTERN (insn)) == USE 591590075Sobrien || GET_CODE (PATTERN (insn)) == CLOBBER) 591690075Sobrien /* Don't care about USE and CLOBBER "insns"---those are used to 591790075Sobrien indicate to the optimizer that it shouldn't get rid of 591890075Sobrien certain operations. */ 591990075Sobrien break; 592090075Sobrien 592190075Sobrien pat = PATTERN (insn); 592290075Sobrien 592390075Sobrien /* Ug. Hack hacks hacked elsewhere. */ 592490075Sobrien switch (recog_memoized (insn)) 592590075Sobrien { 592690075Sobrien /* We play dependency tricks with the epilogue in order 592790075Sobrien to get proper schedules. Undo this for dv analysis. */ 592890075Sobrien case CODE_FOR_epilogue_deallocate_stack: 592996263Sobrien case CODE_FOR_prologue_allocate_stack: 593090075Sobrien pat = XVECEXP (pat, 0, 0); 593190075Sobrien break; 593290075Sobrien 593390075Sobrien /* The pattern we use for br.cloop confuses the code above. 593490075Sobrien The second element of the vector is representative. */ 593590075Sobrien case CODE_FOR_doloop_end_internal: 593690075Sobrien pat = XVECEXP (pat, 0, 1); 593790075Sobrien break; 593890075Sobrien 593990075Sobrien /* Doesn't generate code. */ 594090075Sobrien case CODE_FOR_pred_rel_mutex: 594190075Sobrien case CODE_FOR_prologue_use: 594290075Sobrien return 0; 594390075Sobrien 594490075Sobrien default: 594590075Sobrien break; 594690075Sobrien } 594790075Sobrien 594890075Sobrien memset (rws_insn, 0, sizeof (rws_insn)); 594990075Sobrien need_barrier = rtx_needs_barrier (pat, flags, 0); 595090075Sobrien 595190075Sobrien /* Check to see if the previous instruction was a volatile 595290075Sobrien asm. */ 595390075Sobrien if (! need_barrier) 595490075Sobrien need_barrier = rws_access_regno (REG_VOLATILE, flags, 0); 595590075Sobrien break; 595690075Sobrien 595790075Sobrien default: 5958169689Skan gcc_unreachable (); 595990075Sobrien } 596090075Sobrien 5961132718Skan if (first_instruction && INSN_P (insn) 5962132718Skan && ia64_safe_itanium_class (insn) != ITANIUM_CLASS_IGNORE 5963132718Skan && GET_CODE (PATTERN (insn)) != USE 5964132718Skan && GET_CODE (PATTERN (insn)) != CLOBBER) 596590075Sobrien { 596690075Sobrien need_barrier = 0; 596790075Sobrien first_instruction = 0; 596890075Sobrien } 596990075Sobrien 597090075Sobrien return need_barrier; 597190075Sobrien} 597290075Sobrien 5973169689Skan/* Like group_barrier_needed, but do not clobber the current state. */ 597490075Sobrien 597590075Sobrienstatic int 5976169689Skansafe_group_barrier_needed (rtx insn) 597790075Sobrien{ 597890075Sobrien struct reg_write_state rws_saved[NUM_REGS]; 597990075Sobrien int saved_first_instruction; 598090075Sobrien int t; 598190075Sobrien 598290075Sobrien memcpy (rws_saved, rws_sum, NUM_REGS * sizeof *rws_saved); 598390075Sobrien saved_first_instruction = first_instruction; 598490075Sobrien 5985169689Skan t = group_barrier_needed (insn); 598690075Sobrien 598790075Sobrien memcpy (rws_sum, rws_saved, NUM_REGS * sizeof *rws_saved); 598890075Sobrien first_instruction = saved_first_instruction; 598990075Sobrien 599090075Sobrien return t; 599190075Sobrien} 599290075Sobrien 5993132718Skan/* Scan the current function and insert stop bits as necessary to 5994132718Skan eliminate dependencies. This function assumes that a final 5995132718Skan instruction scheduling pass has been run which has already 5996132718Skan inserted most of the necessary stop bits. This function only 5997132718Skan inserts new ones at basic block boundaries, since these are 5998132718Skan invisible to the scheduler. */ 599990075Sobrien 600090075Sobrienstatic void 6001132718Skanemit_insn_group_barriers (FILE *dump) 600290075Sobrien{ 600390075Sobrien rtx insn; 600490075Sobrien rtx last_label = 0; 600590075Sobrien int insns_since_last_label = 0; 600690075Sobrien 600790075Sobrien init_insn_group_barriers (); 600890075Sobrien 6009132718Skan for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 601090075Sobrien { 601190075Sobrien if (GET_CODE (insn) == CODE_LABEL) 601290075Sobrien { 601390075Sobrien if (insns_since_last_label) 601490075Sobrien last_label = insn; 601590075Sobrien insns_since_last_label = 0; 601690075Sobrien } 601790075Sobrien else if (GET_CODE (insn) == NOTE 601890075Sobrien && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK) 601990075Sobrien { 602090075Sobrien if (insns_since_last_label) 602190075Sobrien last_label = insn; 602290075Sobrien insns_since_last_label = 0; 602390075Sobrien } 602490075Sobrien else if (GET_CODE (insn) == INSN 602590075Sobrien && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE 6026117395Skan && XINT (PATTERN (insn), 1) == UNSPECV_INSN_GROUP_BARRIER) 602790075Sobrien { 602890075Sobrien init_insn_group_barriers (); 602990075Sobrien last_label = 0; 603090075Sobrien } 603190075Sobrien else if (INSN_P (insn)) 603290075Sobrien { 603390075Sobrien insns_since_last_label = 1; 603490075Sobrien 6035169689Skan if (group_barrier_needed (insn)) 603690075Sobrien { 603790075Sobrien if (last_label) 603890075Sobrien { 603990075Sobrien if (dump) 604090075Sobrien fprintf (dump, "Emitting stop before label %d\n", 604190075Sobrien INSN_UID (last_label)); 604290075Sobrien emit_insn_before (gen_insn_group_barrier (GEN_INT (3)), last_label); 604390075Sobrien insn = last_label; 604490075Sobrien 604590075Sobrien init_insn_group_barriers (); 604690075Sobrien last_label = 0; 604790075Sobrien } 604890075Sobrien } 604990075Sobrien } 605090075Sobrien } 605190075Sobrien} 605290075Sobrien 605390075Sobrien/* Like emit_insn_group_barriers, but run if no final scheduling pass was run. 605490075Sobrien This function has to emit all necessary group barriers. */ 605590075Sobrien 605690075Sobrienstatic void 6057132718Skanemit_all_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED) 605890075Sobrien{ 605990075Sobrien rtx insn; 606090075Sobrien 606190075Sobrien init_insn_group_barriers (); 606290075Sobrien 6063132718Skan for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 606490075Sobrien { 606590075Sobrien if (GET_CODE (insn) == BARRIER) 606690075Sobrien { 606790075Sobrien rtx last = prev_active_insn (insn); 606890075Sobrien 606990075Sobrien if (! last) 607090075Sobrien continue; 607190075Sobrien if (GET_CODE (last) == JUMP_INSN 607290075Sobrien && GET_CODE (PATTERN (last)) == ADDR_DIFF_VEC) 607390075Sobrien last = prev_active_insn (last); 607490075Sobrien if (recog_memoized (last) != CODE_FOR_insn_group_barrier) 607590075Sobrien emit_insn_after (gen_insn_group_barrier (GEN_INT (3)), last); 607690075Sobrien 607790075Sobrien init_insn_group_barriers (); 607890075Sobrien } 607990075Sobrien else if (INSN_P (insn)) 608090075Sobrien { 608190075Sobrien if (recog_memoized (insn) == CODE_FOR_insn_group_barrier) 608290075Sobrien init_insn_group_barriers (); 6083169689Skan else if (group_barrier_needed (insn)) 608490075Sobrien { 608590075Sobrien emit_insn_before (gen_insn_group_barrier (GEN_INT (3)), insn); 608690075Sobrien init_insn_group_barriers (); 6087169689Skan group_barrier_needed (insn); 608890075Sobrien } 608990075Sobrien } 609090075Sobrien } 609190075Sobrien} 6092132718Skan 609390075Sobrien 609490075Sobrien 609590075Sobrien/* Instruction scheduling support. */ 609690075Sobrien 609790075Sobrien#define NR_BUNDLES 10 609890075Sobrien 6099132718Skan/* A list of names of all available bundles. */ 610090075Sobrien 6101132718Skanstatic const char *bundle_name [NR_BUNDLES] = 610290075Sobrien{ 6103132718Skan ".mii", 6104132718Skan ".mmi", 6105132718Skan ".mfi", 6106132718Skan ".mmf", 610790075Sobrien#if NR_BUNDLES == 10 6108132718Skan ".bbb", 6109132718Skan ".mbb", 611090075Sobrien#endif 6111132718Skan ".mib", 6112132718Skan ".mmb", 6113132718Skan ".mfb", 6114132718Skan ".mlx" 611590075Sobrien}; 611690075Sobrien 6117132718Skan/* Nonzero if we should insert stop bits into the schedule. */ 611890075Sobrien 6119132718Skanint ia64_final_schedule = 0; 612090075Sobrien 6121169689Skan/* Codes of the corresponding queried units: */ 612290075Sobrien 6123132718Skanstatic int _0mii_, _0mmi_, _0mfi_, _0mmf_; 6124132718Skanstatic int _0bbb_, _0mbb_, _0mib_, _0mmb_, _0mfb_, _0mlx_; 612590075Sobrien 6126132718Skanstatic int _1mii_, _1mmi_, _1mfi_, _1mmf_; 6127132718Skanstatic int _1bbb_, _1mbb_, _1mib_, _1mmb_, _1mfb_, _1mlx_; 612890075Sobrien 6129132718Skanstatic int pos_1, pos_2, pos_3, pos_4, pos_5, pos_6; 613090075Sobrien 6131132718Skan/* The following variable value is an insn group barrier. */ 613290075Sobrien 6133132718Skanstatic rtx dfa_stop_insn; 613490075Sobrien 6135132718Skan/* The following variable value is the last issued insn. */ 613690075Sobrien 6137132718Skanstatic rtx last_scheduled_insn; 613890075Sobrien 6139132718Skan/* The following variable value is size of the DFA state. */ 614090075Sobrien 6141132718Skanstatic size_t dfa_state_size; 614290075Sobrien 6143132718Skan/* The following variable value is pointer to a DFA state used as 6144132718Skan temporary variable. */ 614590075Sobrien 6146132718Skanstatic state_t temp_dfa_state = NULL; 614790075Sobrien 6148132718Skan/* The following variable value is DFA state after issuing the last 6149132718Skan insn. */ 6150132718Skan 6151132718Skanstatic state_t prev_cycle_state = NULL; 6152132718Skan 6153132718Skan/* The following array element values are TRUE if the corresponding 6154132718Skan insn requires to add stop bits before it. */ 6155132718Skan 6156169689Skanstatic char *stops_p = NULL; 6157132718Skan 6158169689Skan/* The following array element values are ZERO for non-speculative 6159169689Skan instructions and hold corresponding speculation check number for 6160169689Skan speculative instructions. */ 6161169689Skanstatic int *spec_check_no = NULL; 6162169689Skan 6163169689Skan/* Size of spec_check_no array. */ 6164169689Skanstatic int max_uid = 0; 6165169689Skan 6166132718Skan/* The following variable is used to set up the mentioned above array. */ 6167132718Skan 6168132718Skanstatic int stop_before_p = 0; 6169132718Skan 6170132718Skan/* The following variable value is length of the arrays `clocks' and 6171132718Skan `add_cycles'. */ 6172132718Skan 6173132718Skanstatic int clocks_length; 6174132718Skan 6175132718Skan/* The following array element values are cycles on which the 6176132718Skan corresponding insn will be issued. The array is used only for 6177132718Skan Itanium1. */ 6178132718Skan 6179132718Skanstatic int *clocks; 6180132718Skan 6181132718Skan/* The following array element values are numbers of cycles should be 6182132718Skan added to improve insn scheduling for MM_insns for Itanium1. */ 6183132718Skan 6184132718Skanstatic int *add_cycles; 6185132718Skan 6186169689Skan/* The following variable value is number of data speculations in progress. */ 6187169689Skanstatic int pending_data_specs = 0; 6188169689Skan 6189132718Skanstatic rtx ia64_single_set (rtx); 6190132718Skanstatic void ia64_emit_insn_before (rtx, rtx); 6191132718Skan 6192132718Skan/* Map a bundle number to its pseudo-op. */ 6193132718Skan 6194132718Skanconst char * 6195132718Skanget_bundle_name (int b) 6196132718Skan{ 6197132718Skan return bundle_name[b]; 619890075Sobrien} 619990075Sobrien 6200132718Skan 620190075Sobrien/* Return the maximum number of instructions a cpu can issue. */ 620290075Sobrien 620390075Sobrienstatic int 6204132718Skania64_issue_rate (void) 620590075Sobrien{ 620690075Sobrien return 6; 620790075Sobrien} 620890075Sobrien 620990075Sobrien/* Helper function - like single_set, but look inside COND_EXEC. */ 621090075Sobrien 621190075Sobrienstatic rtx 6212132718Skania64_single_set (rtx insn) 621390075Sobrien{ 621490075Sobrien rtx x = PATTERN (insn), ret; 621590075Sobrien if (GET_CODE (x) == COND_EXEC) 621690075Sobrien x = COND_EXEC_CODE (x); 621790075Sobrien if (GET_CODE (x) == SET) 621890075Sobrien return x; 621996263Sobrien 622096263Sobrien /* Special case here prologue_allocate_stack and epilogue_deallocate_stack. 622196263Sobrien Although they are not classical single set, the second set is there just 622296263Sobrien to protect it from moving past FP-relative stack accesses. */ 622396263Sobrien switch (recog_memoized (insn)) 622490075Sobrien { 622596263Sobrien case CODE_FOR_prologue_allocate_stack: 622696263Sobrien case CODE_FOR_epilogue_deallocate_stack: 622796263Sobrien ret = XVECEXP (x, 0, 0); 622896263Sobrien break; 622996263Sobrien 623096263Sobrien default: 623196263Sobrien ret = single_set_2 (insn, x); 623296263Sobrien break; 623390075Sobrien } 623496263Sobrien 623590075Sobrien return ret; 623690075Sobrien} 623790075Sobrien 6238169689Skan/* Adjust the cost of a scheduling dependency. 6239169689Skan Return the new cost of a dependency of type DEP_TYPE or INSN on DEP_INSN. 6240169689Skan COST is the current cost. */ 624190075Sobrien 624290075Sobrienstatic int 6243169689Skania64_adjust_cost_2 (rtx insn, int dep_type1, rtx dep_insn, int cost) 624490075Sobrien{ 6245169689Skan enum reg_note dep_type = (enum reg_note) dep_type1; 624690075Sobrien enum attr_itanium_class dep_class; 624790075Sobrien enum attr_itanium_class insn_class; 624890075Sobrien 6249169689Skan if (dep_type != REG_DEP_OUTPUT) 6250132718Skan return cost; 625190075Sobrien 6252132718Skan insn_class = ia64_safe_itanium_class (insn); 6253132718Skan dep_class = ia64_safe_itanium_class (dep_insn); 6254132718Skan if (dep_class == ITANIUM_CLASS_ST || dep_class == ITANIUM_CLASS_STF 6255132718Skan || insn_class == ITANIUM_CLASS_ST || insn_class == ITANIUM_CLASS_STF) 625690075Sobrien return 0; 625790075Sobrien 6258132718Skan return cost; 6259132718Skan} 626090075Sobrien 6261132718Skan/* Like emit_insn_before, but skip cycle_display notes. 6262132718Skan ??? When cycle display notes are implemented, update this. */ 626390075Sobrien 6264132718Skanstatic void 6265132718Skania64_emit_insn_before (rtx insn, rtx before) 6266132718Skan{ 6267132718Skan emit_insn_before (insn, before); 6268132718Skan} 626990075Sobrien 6270132718Skan/* The following function marks insns who produce addresses for load 6271132718Skan and store insns. Such insns will be placed into M slots because it 6272132718Skan decrease latency time for Itanium1 (see function 6273132718Skan `ia64_produce_address_p' and the DFA descriptions). */ 6274132718Skan 6275132718Skanstatic void 6276132718Skania64_dependencies_evaluation_hook (rtx head, rtx tail) 6277132718Skan{ 6278132718Skan rtx insn, link, next, next_tail; 6279132718Skan 6280169689Skan /* Before reload, which_alternative is not set, which means that 6281169689Skan ia64_safe_itanium_class will produce wrong results for (at least) 6282169689Skan move instructions. */ 6283169689Skan if (!reload_completed) 6284169689Skan return; 6285169689Skan 6286132718Skan next_tail = NEXT_INSN (tail); 6287132718Skan for (insn = head; insn != next_tail; insn = NEXT_INSN (insn)) 6288132718Skan if (INSN_P (insn)) 6289132718Skan insn->call = 0; 6290132718Skan for (insn = head; insn != next_tail; insn = NEXT_INSN (insn)) 6291132718Skan if (INSN_P (insn) 6292132718Skan && ia64_safe_itanium_class (insn) == ITANIUM_CLASS_IALU) 6293132718Skan { 6294132718Skan for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1)) 6295132718Skan { 6296169689Skan enum attr_itanium_class c; 6297169689Skan 6298169689Skan if (REG_NOTE_KIND (link) != REG_DEP_TRUE) 6299169689Skan continue; 6300132718Skan next = XEXP (link, 0); 6301169689Skan c = ia64_safe_itanium_class (next); 6302169689Skan if ((c == ITANIUM_CLASS_ST 6303169689Skan || c == ITANIUM_CLASS_STF) 6304132718Skan && ia64_st_address_bypass_p (insn, next)) 6305132718Skan break; 6306169689Skan else if ((c == ITANIUM_CLASS_LD 6307169689Skan || c == ITANIUM_CLASS_FLD 6308169689Skan || c == ITANIUM_CLASS_FLDP) 6309132718Skan && ia64_ld_address_bypass_p (insn, next)) 6310132718Skan break; 6311132718Skan } 6312132718Skan insn->call = link != 0; 6313132718Skan } 6314132718Skan} 6315132718Skan 6316132718Skan/* We're beginning a new block. Initialize data structures as necessary. */ 6317132718Skan 6318132718Skanstatic void 6319132718Skania64_sched_init (FILE *dump ATTRIBUTE_UNUSED, 6320132718Skan int sched_verbose ATTRIBUTE_UNUSED, 6321132718Skan int max_ready ATTRIBUTE_UNUSED) 6322132718Skan{ 6323132718Skan#ifdef ENABLE_CHECKING 6324132718Skan rtx insn; 6325132718Skan 6326132718Skan if (reload_completed) 6327132718Skan for (insn = NEXT_INSN (current_sched_info->prev_head); 6328132718Skan insn != current_sched_info->next_tail; 6329132718Skan insn = NEXT_INSN (insn)) 6330169689Skan gcc_assert (!SCHED_GROUP_P (insn)); 6331132718Skan#endif 6332132718Skan last_scheduled_insn = NULL_RTX; 6333132718Skan init_insn_group_barriers (); 6334132718Skan} 6335132718Skan 6336169689Skan/* We're beginning a scheduling pass. Check assertion. */ 6337169689Skan 6338169689Skanstatic void 6339169689Skania64_sched_init_global (FILE *dump ATTRIBUTE_UNUSED, 6340169689Skan int sched_verbose ATTRIBUTE_UNUSED, 6341169689Skan int max_ready ATTRIBUTE_UNUSED) 6342169689Skan{ 6343169689Skan gcc_assert (!pending_data_specs); 6344169689Skan} 6345169689Skan 6346169689Skan/* Scheduling pass is now finished. Free/reset static variable. */ 6347169689Skanstatic void 6348169689Skania64_sched_finish_global (FILE *dump ATTRIBUTE_UNUSED, 6349169689Skan int sched_verbose ATTRIBUTE_UNUSED) 6350169689Skan{ 6351169689Skan free (spec_check_no); 6352169689Skan spec_check_no = 0; 6353169689Skan max_uid = 0; 6354169689Skan} 6355169689Skan 6356132718Skan/* We are about to being issuing insns for this clock cycle. 6357132718Skan Override the default sort algorithm to better slot instructions. */ 6358132718Skan 6359132718Skanstatic int 6360132718Skania64_dfa_sched_reorder (FILE *dump, int sched_verbose, rtx *ready, 6361132718Skan int *pn_ready, int clock_var ATTRIBUTE_UNUSED, 6362132718Skan int reorder_type) 6363132718Skan{ 6364132718Skan int n_asms; 6365132718Skan int n_ready = *pn_ready; 6366132718Skan rtx *e_ready = ready + n_ready; 6367132718Skan rtx *insnp; 6368132718Skan 6369132718Skan if (sched_verbose) 6370132718Skan fprintf (dump, "// ia64_dfa_sched_reorder (type %d):\n", reorder_type); 6371132718Skan 6372132718Skan if (reorder_type == 0) 637390075Sobrien { 6374132718Skan /* First, move all USEs, CLOBBERs and other crud out of the way. */ 6375132718Skan n_asms = 0; 6376132718Skan for (insnp = ready; insnp < e_ready; insnp++) 6377132718Skan if (insnp < e_ready) 6378132718Skan { 6379132718Skan rtx insn = *insnp; 6380132718Skan enum attr_type t = ia64_safe_type (insn); 6381132718Skan if (t == TYPE_UNKNOWN) 6382132718Skan { 6383132718Skan if (GET_CODE (PATTERN (insn)) == ASM_INPUT 6384132718Skan || asm_noperands (PATTERN (insn)) >= 0) 6385132718Skan { 6386132718Skan rtx lowest = ready[n_asms]; 6387132718Skan ready[n_asms] = insn; 6388132718Skan *insnp = lowest; 6389132718Skan n_asms++; 6390132718Skan } 6391132718Skan else 6392132718Skan { 6393132718Skan rtx highest = ready[n_ready - 1]; 6394132718Skan ready[n_ready - 1] = insn; 6395132718Skan *insnp = highest; 6396132718Skan return 1; 6397132718Skan } 6398132718Skan } 6399132718Skan } 640090075Sobrien 6401132718Skan if (n_asms < n_ready) 640290075Sobrien { 6403132718Skan /* Some normal insns to process. Skip the asms. */ 6404132718Skan ready += n_asms; 6405132718Skan n_ready -= n_asms; 640690075Sobrien } 6407132718Skan else if (n_ready > 0) 6408132718Skan return 1; 640990075Sobrien } 641090075Sobrien 6411132718Skan if (ia64_final_schedule) 6412132718Skan { 6413132718Skan int deleted = 0; 6414132718Skan int nr_need_stop = 0; 641590075Sobrien 6416132718Skan for (insnp = ready; insnp < e_ready; insnp++) 6417169689Skan if (safe_group_barrier_needed (*insnp)) 6418132718Skan nr_need_stop++; 641990075Sobrien 6420132718Skan if (reorder_type == 1 && n_ready == nr_need_stop) 6421132718Skan return 0; 6422132718Skan if (reorder_type == 0) 6423132718Skan return 1; 6424132718Skan insnp = e_ready; 6425132718Skan /* Move down everything that needs a stop bit, preserving 6426132718Skan relative order. */ 6427132718Skan while (insnp-- > ready + deleted) 6428132718Skan while (insnp >= ready + deleted) 6429132718Skan { 6430132718Skan rtx insn = *insnp; 6431169689Skan if (! safe_group_barrier_needed (insn)) 6432132718Skan break; 6433132718Skan memmove (ready + 1, ready, (insnp - ready) * sizeof (rtx)); 6434132718Skan *ready = insn; 6435132718Skan deleted++; 6436132718Skan } 6437132718Skan n_ready -= deleted; 6438132718Skan ready += deleted; 643990075Sobrien } 644096263Sobrien 6441132718Skan return 1; 6442132718Skan} 644396263Sobrien 6444132718Skan/* We are about to being issuing insns for this clock cycle. Override 6445132718Skan the default sort algorithm to better slot instructions. */ 644696263Sobrien 6447132718Skanstatic int 6448132718Skania64_sched_reorder (FILE *dump, int sched_verbose, rtx *ready, int *pn_ready, 6449132718Skan int clock_var) 6450132718Skan{ 6451132718Skan return ia64_dfa_sched_reorder (dump, sched_verbose, ready, 6452132718Skan pn_ready, clock_var, 0); 6453132718Skan} 645496263Sobrien 6455132718Skan/* Like ia64_sched_reorder, but called after issuing each insn. 6456132718Skan Override the default sort algorithm to better slot instructions. */ 645790075Sobrien 6458132718Skanstatic int 6459132718Skania64_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED, 6460132718Skan int sched_verbose ATTRIBUTE_UNUSED, rtx *ready, 6461132718Skan int *pn_ready, int clock_var) 6462132718Skan{ 6463132718Skan if (ia64_tune == PROCESSOR_ITANIUM && reload_completed && last_scheduled_insn) 6464132718Skan clocks [INSN_UID (last_scheduled_insn)] = clock_var; 6465132718Skan return ia64_dfa_sched_reorder (dump, sched_verbose, ready, pn_ready, 6466132718Skan clock_var, 1); 646790075Sobrien} 646890075Sobrien 6469132718Skan/* We are about to issue INSN. Return the number of insns left on the 6470132718Skan ready queue that can be issued this cycle. */ 6471132718Skan 6472132718Skanstatic int 6473132718Skania64_variable_issue (FILE *dump ATTRIBUTE_UNUSED, 6474132718Skan int sched_verbose ATTRIBUTE_UNUSED, 6475132718Skan rtx insn ATTRIBUTE_UNUSED, 6476132718Skan int can_issue_more ATTRIBUTE_UNUSED) 647790075Sobrien{ 6478169689Skan if (current_sched_info->flags & DO_SPECULATION) 6479169689Skan /* Modulo scheduling does not extend h_i_d when emitting 6480169689Skan new instructions. Deal with it. */ 6481169689Skan { 6482169689Skan if (DONE_SPEC (insn) & BEGIN_DATA) 6483169689Skan pending_data_specs++; 6484169689Skan if (CHECK_SPEC (insn) & BEGIN_DATA) 6485169689Skan pending_data_specs--; 6486169689Skan } 6487169689Skan 6488132718Skan last_scheduled_insn = insn; 6489132718Skan memcpy (prev_cycle_state, curr_state, dfa_state_size); 6490132718Skan if (reload_completed) 6491132718Skan { 6492169689Skan int needed = group_barrier_needed (insn); 6493169689Skan 6494169689Skan gcc_assert (!needed); 6495132718Skan if (GET_CODE (insn) == CALL_INSN) 6496132718Skan init_insn_group_barriers (); 6497132718Skan stops_p [INSN_UID (insn)] = stop_before_p; 6498132718Skan stop_before_p = 0; 6499132718Skan } 6500132718Skan return 1; 6501132718Skan} 650290075Sobrien 6503132718Skan/* We are choosing insn from the ready queue. Return nonzero if INSN 6504132718Skan can be chosen. */ 650590075Sobrien 6506132718Skanstatic int 6507132718Skania64_first_cycle_multipass_dfa_lookahead_guard (rtx insn) 6508132718Skan{ 6509169689Skan gcc_assert (insn && INSN_P (insn)); 6510169689Skan return ((!reload_completed 6511169689Skan || !safe_group_barrier_needed (insn)) 6512169689Skan && ia64_first_cycle_multipass_dfa_lookahead_guard_spec (insn)); 6513132718Skan} 651490075Sobrien 6515169689Skan/* We are choosing insn from the ready queue. Return nonzero if INSN 6516169689Skan can be chosen. */ 6517169689Skan 6518169689Skanstatic bool 6519169689Skania64_first_cycle_multipass_dfa_lookahead_guard_spec (rtx insn) 6520169689Skan{ 6521169689Skan gcc_assert (insn && INSN_P (insn)); 6522169689Skan /* Size of ALAT is 32. As far as we perform conservative data speculation, 6523169689Skan we keep ALAT half-empty. */ 6524169689Skan return (pending_data_specs < 16 6525169689Skan || !(TODO_SPEC (insn) & BEGIN_DATA)); 6526169689Skan} 6527169689Skan 6528132718Skan/* The following variable value is pseudo-insn used by the DFA insn 6529132718Skan scheduler to change the DFA state when the simulated clock is 6530132718Skan increased. */ 6531132718Skan 6532132718Skanstatic rtx dfa_pre_cycle_insn; 6533132718Skan 6534169689Skan/* We are about to being issuing INSN. Return nonzero if we cannot 6535132718Skan issue it on given cycle CLOCK and return zero if we should not sort 6536132718Skan the ready queue on the next clock start. */ 6537132718Skan 653890075Sobrienstatic int 6539132718Skania64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock, 6540132718Skan int clock, int *sort_p) 654190075Sobrien{ 6542132718Skan int setup_clocks_p = FALSE; 654390075Sobrien 6544169689Skan gcc_assert (insn && INSN_P (insn)); 6545169689Skan if ((reload_completed && safe_group_barrier_needed (insn)) 6546132718Skan || (last_scheduled_insn 6547132718Skan && (GET_CODE (last_scheduled_insn) == CALL_INSN 6548132718Skan || GET_CODE (PATTERN (last_scheduled_insn)) == ASM_INPUT 6549132718Skan || asm_noperands (PATTERN (last_scheduled_insn)) >= 0))) 655090075Sobrien { 6551132718Skan init_insn_group_barriers (); 6552132718Skan if (verbose && dump) 6553132718Skan fprintf (dump, "// Stop should be before %d%s\n", INSN_UID (insn), 6554132718Skan last_clock == clock ? " + cycle advance" : ""); 6555132718Skan stop_before_p = 1; 6556132718Skan if (last_clock == clock) 655790075Sobrien { 6558132718Skan state_transition (curr_state, dfa_stop_insn); 6559132718Skan if (TARGET_EARLY_STOP_BITS) 6560132718Skan *sort_p = (last_scheduled_insn == NULL_RTX 6561132718Skan || GET_CODE (last_scheduled_insn) != CALL_INSN); 6562132718Skan else 6563132718Skan *sort_p = 0; 6564132718Skan return 1; 656590075Sobrien } 6566132718Skan else if (reload_completed) 6567132718Skan setup_clocks_p = TRUE; 6568132718Skan if (GET_CODE (PATTERN (last_scheduled_insn)) == ASM_INPUT 6569132718Skan || asm_noperands (PATTERN (last_scheduled_insn)) >= 0) 6570132718Skan state_reset (curr_state); 6571132718Skan else 657290075Sobrien { 6573132718Skan memcpy (curr_state, prev_cycle_state, dfa_state_size); 6574132718Skan state_transition (curr_state, dfa_stop_insn); 6575132718Skan state_transition (curr_state, dfa_pre_cycle_insn); 6576132718Skan state_transition (curr_state, NULL); 657790075Sobrien } 657890075Sobrien } 6579132718Skan else if (reload_completed) 6580132718Skan setup_clocks_p = TRUE; 6581132718Skan if (setup_clocks_p && ia64_tune == PROCESSOR_ITANIUM 6582132718Skan && GET_CODE (PATTERN (insn)) != ASM_INPUT 6583132718Skan && asm_noperands (PATTERN (insn)) < 0) 6584132718Skan { 6585132718Skan enum attr_itanium_class c = ia64_safe_itanium_class (insn); 658690075Sobrien 6587132718Skan if (c != ITANIUM_CLASS_MMMUL && c != ITANIUM_CLASS_MMSHF) 6588132718Skan { 6589132718Skan rtx link; 6590132718Skan int d = -1; 6591132718Skan 6592132718Skan for (link = LOG_LINKS (insn); link; link = XEXP (link, 1)) 6593132718Skan if (REG_NOTE_KIND (link) == 0) 6594132718Skan { 6595132718Skan enum attr_itanium_class dep_class; 6596132718Skan rtx dep_insn = XEXP (link, 0); 6597132718Skan 6598132718Skan dep_class = ia64_safe_itanium_class (dep_insn); 6599132718Skan if ((dep_class == ITANIUM_CLASS_MMMUL 6600132718Skan || dep_class == ITANIUM_CLASS_MMSHF) 6601132718Skan && last_clock - clocks [INSN_UID (dep_insn)] < 4 6602132718Skan && (d < 0 6603132718Skan || last_clock - clocks [INSN_UID (dep_insn)] < d)) 6604132718Skan d = last_clock - clocks [INSN_UID (dep_insn)]; 6605132718Skan } 6606132718Skan if (d >= 0) 6607132718Skan add_cycles [INSN_UID (insn)] = 3 - d; 6608132718Skan } 6609132718Skan } 661090075Sobrien return 0; 661190075Sobrien} 661290075Sobrien 6613169689Skan/* Implement targetm.sched.h_i_d_extended hook. 6614169689Skan Extend internal data structures. */ 6615169689Skanstatic void 6616169689Skania64_h_i_d_extended (void) 6617169689Skan{ 6618169689Skan if (current_sched_info->flags & DO_SPECULATION) 6619169689Skan { 6620169689Skan int new_max_uid = get_max_uid () + 1; 6621169689Skan 6622169689Skan spec_check_no = xrecalloc (spec_check_no, new_max_uid, 6623169689Skan max_uid, sizeof (*spec_check_no)); 6624169689Skan max_uid = new_max_uid; 6625169689Skan } 6626169689Skan 6627169689Skan if (stops_p != NULL) 6628169689Skan { 6629169689Skan int new_clocks_length = get_max_uid () + 1; 6630169689Skan 6631169689Skan stops_p = xrecalloc (stops_p, new_clocks_length, clocks_length, 1); 6632169689Skan 6633169689Skan if (ia64_tune == PROCESSOR_ITANIUM) 6634169689Skan { 6635169689Skan clocks = xrecalloc (clocks, new_clocks_length, clocks_length, 6636169689Skan sizeof (int)); 6637169689Skan add_cycles = xrecalloc (add_cycles, new_clocks_length, clocks_length, 6638169689Skan sizeof (int)); 6639169689Skan } 6640169689Skan 6641169689Skan clocks_length = new_clocks_length; 6642169689Skan } 6643169689Skan} 6644169689Skan 6645169689Skan/* Constants that help mapping 'enum machine_mode' to int. */ 6646169689Skanenum SPEC_MODES 6647169689Skan { 6648169689Skan SPEC_MODE_INVALID = -1, 6649169689Skan SPEC_MODE_FIRST = 0, 6650169689Skan SPEC_MODE_FOR_EXTEND_FIRST = 1, 6651169689Skan SPEC_MODE_FOR_EXTEND_LAST = 3, 6652169689Skan SPEC_MODE_LAST = 8 6653169689Skan }; 6654169689Skan 6655169689Skan/* Return index of the MODE. */ 6656169689Skanstatic int 6657169689Skania64_mode_to_int (enum machine_mode mode) 6658169689Skan{ 6659169689Skan switch (mode) 6660169689Skan { 6661169689Skan case BImode: return 0; /* SPEC_MODE_FIRST */ 6662169689Skan case QImode: return 1; /* SPEC_MODE_FOR_EXTEND_FIRST */ 6663169689Skan case HImode: return 2; 6664169689Skan case SImode: return 3; /* SPEC_MODE_FOR_EXTEND_LAST */ 6665169689Skan case DImode: return 4; 6666169689Skan case SFmode: return 5; 6667169689Skan case DFmode: return 6; 6668169689Skan case XFmode: return 7; 6669169689Skan case TImode: 6670169689Skan /* ??? This mode needs testing. Bypasses for ldfp8 instruction are not 6671169689Skan mentioned in itanium[12].md. Predicate fp_register_operand also 6672169689Skan needs to be defined. Bottom line: better disable for now. */ 6673169689Skan return SPEC_MODE_INVALID; 6674169689Skan default: return SPEC_MODE_INVALID; 6675169689Skan } 6676169689Skan} 6677169689Skan 6678169689Skan/* Provide information about speculation capabilities. */ 6679169689Skanstatic void 6680169689Skania64_set_sched_flags (spec_info_t spec_info) 6681169689Skan{ 6682169689Skan unsigned int *flags = &(current_sched_info->flags); 6683169689Skan 6684169689Skan if (*flags & SCHED_RGN 6685169689Skan || *flags & SCHED_EBB) 6686169689Skan { 6687169689Skan int mask = 0; 6688169689Skan 6689169689Skan if ((mflag_sched_br_data_spec && !reload_completed && optimize > 0) 6690169689Skan || (mflag_sched_ar_data_spec && reload_completed)) 6691169689Skan { 6692169689Skan mask |= BEGIN_DATA; 6693169689Skan 6694169689Skan if ((mflag_sched_br_in_data_spec && !reload_completed) 6695169689Skan || (mflag_sched_ar_in_data_spec && reload_completed)) 6696169689Skan mask |= BE_IN_DATA; 6697169689Skan } 6698169689Skan 6699169689Skan if (mflag_sched_control_spec) 6700169689Skan { 6701169689Skan mask |= BEGIN_CONTROL; 6702169689Skan 6703169689Skan if (mflag_sched_in_control_spec) 6704169689Skan mask |= BE_IN_CONTROL; 6705169689Skan } 6706169689Skan 6707169689Skan gcc_assert (*flags & USE_GLAT); 6708169689Skan 6709169689Skan if (mask) 6710169689Skan { 6711169689Skan *flags |= USE_DEPS_LIST | DETACH_LIFE_INFO | DO_SPECULATION; 6712169689Skan 6713169689Skan spec_info->mask = mask; 6714169689Skan spec_info->flags = 0; 6715169689Skan 6716169689Skan if ((mask & DATA_SPEC) && mflag_sched_prefer_non_data_spec_insns) 6717169689Skan spec_info->flags |= PREFER_NON_DATA_SPEC; 6718169689Skan 6719169689Skan if ((mask & CONTROL_SPEC) 6720169689Skan && mflag_sched_prefer_non_control_spec_insns) 6721169689Skan spec_info->flags |= PREFER_NON_CONTROL_SPEC; 6722169689Skan 6723169689Skan if (mflag_sched_spec_verbose) 6724169689Skan { 6725169689Skan if (sched_verbose >= 1) 6726169689Skan spec_info->dump = sched_dump; 6727169689Skan else 6728169689Skan spec_info->dump = stderr; 6729169689Skan } 6730169689Skan else 6731169689Skan spec_info->dump = 0; 6732169689Skan 6733169689Skan if (mflag_sched_count_spec_in_critical_path) 6734169689Skan spec_info->flags |= COUNT_SPEC_IN_CRITICAL_PATH; 6735169689Skan } 6736169689Skan } 6737169689Skan} 6738169689Skan 6739169689Skan/* Implement targetm.sched.speculate_insn hook. 6740169689Skan Check if the INSN can be TS speculative. 6741169689Skan If 'no' - return -1. 6742169689Skan If 'yes' - generate speculative pattern in the NEW_PAT and return 1. 6743169689Skan If current pattern of the INSN already provides TS speculation, return 0. */ 6744169689Skanstatic int 6745169689Skania64_speculate_insn (rtx insn, ds_t ts, rtx *new_pat) 6746169689Skan{ 6747169689Skan rtx pat, reg, mem, mem_reg; 6748169689Skan int mode_no, gen_p = 1; 6749169689Skan bool extend_p; 6750169689Skan 6751169689Skan gcc_assert (!(ts & ~BEGIN_SPEC) && ts); 6752169689Skan 6753169689Skan pat = PATTERN (insn); 6754169689Skan 6755169689Skan if (GET_CODE (pat) == COND_EXEC) 6756169689Skan pat = COND_EXEC_CODE (pat); 6757169689Skan 6758169689Skan /* This should be a SET ... */ 6759169689Skan if (GET_CODE (pat) != SET) 6760169689Skan return -1; 6761169689Skan 6762169689Skan reg = SET_DEST (pat); 6763169689Skan /* ... to the general/fp register ... */ 6764169689Skan if (!REG_P (reg) || !(GR_REGNO_P (REGNO (reg)) || FP_REGNO_P (REGNO (reg)))) 6765169689Skan return -1; 6766169689Skan 6767169689Skan /* ... from the mem ... */ 6768169689Skan mem = SET_SRC (pat); 6769169689Skan 6770169689Skan /* ... that can, possibly, be a zero_extend ... */ 6771169689Skan if (GET_CODE (mem) == ZERO_EXTEND) 6772169689Skan { 6773169689Skan mem = XEXP (mem, 0); 6774169689Skan extend_p = true; 6775169689Skan } 6776169689Skan else 6777169689Skan extend_p = false; 6778169689Skan 6779169689Skan /* ... or a speculative load. */ 6780169689Skan if (GET_CODE (mem) == UNSPEC) 6781169689Skan { 6782169689Skan int code; 6783169689Skan 6784169689Skan code = XINT (mem, 1); 6785169689Skan if (code != UNSPEC_LDA && code != UNSPEC_LDS && code != UNSPEC_LDSA) 6786169689Skan return -1; 6787169689Skan 6788169689Skan if ((code == UNSPEC_LDA && !(ts & BEGIN_CONTROL)) 6789169689Skan || (code == UNSPEC_LDS && !(ts & BEGIN_DATA)) 6790169689Skan || code == UNSPEC_LDSA) 6791169689Skan gen_p = 0; 6792169689Skan 6793169689Skan mem = XVECEXP (mem, 0, 0); 6794169689Skan gcc_assert (MEM_P (mem)); 6795169689Skan } 6796169689Skan 6797169689Skan /* Source should be a mem ... */ 6798169689Skan if (!MEM_P (mem)) 6799169689Skan return -1; 6800169689Skan 6801169689Skan /* ... addressed by a register. */ 6802169689Skan mem_reg = XEXP (mem, 0); 6803169689Skan if (!REG_P (mem_reg)) 6804169689Skan return -1; 6805169689Skan 6806169689Skan /* We should use MEM's mode since REG's mode in presence of ZERO_EXTEND 6807169689Skan will always be DImode. */ 6808169689Skan mode_no = ia64_mode_to_int (GET_MODE (mem)); 6809169689Skan 6810169689Skan if (mode_no == SPEC_MODE_INVALID 6811169689Skan || (extend_p 6812169689Skan && !(SPEC_MODE_FOR_EXTEND_FIRST <= mode_no 6813169689Skan && mode_no <= SPEC_MODE_FOR_EXTEND_LAST))) 6814169689Skan return -1; 6815169689Skan 6816169689Skan extract_insn_cached (insn); 6817169689Skan gcc_assert (reg == recog_data.operand[0] && mem == recog_data.operand[1]); 6818169689Skan 6819169689Skan *new_pat = ia64_gen_spec_insn (insn, ts, mode_no, gen_p != 0, extend_p); 6820169689Skan 6821169689Skan return gen_p; 6822169689Skan} 6823169689Skan 6824169689Skanenum 6825169689Skan { 6826169689Skan /* Offset to reach ZERO_EXTEND patterns. */ 6827169689Skan SPEC_GEN_EXTEND_OFFSET = SPEC_MODE_LAST - SPEC_MODE_FOR_EXTEND_FIRST + 1, 6828169689Skan /* Number of patterns for each speculation mode. */ 6829169689Skan SPEC_N = (SPEC_MODE_LAST 6830169689Skan + SPEC_MODE_FOR_EXTEND_LAST - SPEC_MODE_FOR_EXTEND_FIRST + 2) 6831169689Skan }; 6832169689Skan 6833169689Skanenum SPEC_GEN_LD_MAP 6834169689Skan { 6835169689Skan /* Offset to ld.a patterns. */ 6836169689Skan SPEC_GEN_A = 0 * SPEC_N, 6837169689Skan /* Offset to ld.s patterns. */ 6838169689Skan SPEC_GEN_S = 1 * SPEC_N, 6839169689Skan /* Offset to ld.sa patterns. */ 6840169689Skan SPEC_GEN_SA = 2 * SPEC_N, 6841169689Skan /* Offset to ld.sa patterns. For this patterns corresponding ld.c will 6842169689Skan mutate to chk.s. */ 6843169689Skan SPEC_GEN_SA_FOR_S = 3 * SPEC_N 6844169689Skan }; 6845169689Skan 6846169689Skan/* These offsets are used to get (4 * SPEC_N). */ 6847169689Skanenum SPEC_GEN_CHECK_OFFSET 6848169689Skan { 6849169689Skan SPEC_GEN_CHKA_FOR_A_OFFSET = 4 * SPEC_N - SPEC_GEN_A, 6850169689Skan SPEC_GEN_CHKA_FOR_SA_OFFSET = 4 * SPEC_N - SPEC_GEN_SA 6851169689Skan }; 6852169689Skan 6853169689Skan/* If GEN_P is true, calculate the index of needed speculation check and return 6854169689Skan speculative pattern for INSN with speculative mode TS, machine mode 6855169689Skan MODE_NO and with ZERO_EXTEND (if EXTEND_P is true). 6856169689Skan If GEN_P is false, just calculate the index of needed speculation check. */ 6857169689Skanstatic rtx 6858169689Skania64_gen_spec_insn (rtx insn, ds_t ts, int mode_no, bool gen_p, bool extend_p) 6859169689Skan{ 6860169689Skan rtx pat, new_pat; 6861169689Skan int load_no; 6862169689Skan int shift = 0; 6863169689Skan 6864169689Skan static rtx (* const gen_load[]) (rtx, rtx) = { 6865169689Skan gen_movbi_advanced, 6866169689Skan gen_movqi_advanced, 6867169689Skan gen_movhi_advanced, 6868169689Skan gen_movsi_advanced, 6869169689Skan gen_movdi_advanced, 6870169689Skan gen_movsf_advanced, 6871169689Skan gen_movdf_advanced, 6872169689Skan gen_movxf_advanced, 6873169689Skan gen_movti_advanced, 6874169689Skan gen_zero_extendqidi2_advanced, 6875169689Skan gen_zero_extendhidi2_advanced, 6876169689Skan gen_zero_extendsidi2_advanced, 6877169689Skan 6878169689Skan gen_movbi_speculative, 6879169689Skan gen_movqi_speculative, 6880169689Skan gen_movhi_speculative, 6881169689Skan gen_movsi_speculative, 6882169689Skan gen_movdi_speculative, 6883169689Skan gen_movsf_speculative, 6884169689Skan gen_movdf_speculative, 6885169689Skan gen_movxf_speculative, 6886169689Skan gen_movti_speculative, 6887169689Skan gen_zero_extendqidi2_speculative, 6888169689Skan gen_zero_extendhidi2_speculative, 6889169689Skan gen_zero_extendsidi2_speculative, 6890169689Skan 6891169689Skan gen_movbi_speculative_advanced, 6892169689Skan gen_movqi_speculative_advanced, 6893169689Skan gen_movhi_speculative_advanced, 6894169689Skan gen_movsi_speculative_advanced, 6895169689Skan gen_movdi_speculative_advanced, 6896169689Skan gen_movsf_speculative_advanced, 6897169689Skan gen_movdf_speculative_advanced, 6898169689Skan gen_movxf_speculative_advanced, 6899169689Skan gen_movti_speculative_advanced, 6900169689Skan gen_zero_extendqidi2_speculative_advanced, 6901169689Skan gen_zero_extendhidi2_speculative_advanced, 6902169689Skan gen_zero_extendsidi2_speculative_advanced, 6903169689Skan 6904169689Skan gen_movbi_speculative_advanced, 6905169689Skan gen_movqi_speculative_advanced, 6906169689Skan gen_movhi_speculative_advanced, 6907169689Skan gen_movsi_speculative_advanced, 6908169689Skan gen_movdi_speculative_advanced, 6909169689Skan gen_movsf_speculative_advanced, 6910169689Skan gen_movdf_speculative_advanced, 6911169689Skan gen_movxf_speculative_advanced, 6912169689Skan gen_movti_speculative_advanced, 6913169689Skan gen_zero_extendqidi2_speculative_advanced, 6914169689Skan gen_zero_extendhidi2_speculative_advanced, 6915169689Skan gen_zero_extendsidi2_speculative_advanced 6916169689Skan }; 6917169689Skan 6918169689Skan load_no = extend_p ? mode_no + SPEC_GEN_EXTEND_OFFSET : mode_no; 6919169689Skan 6920169689Skan if (ts & BEGIN_DATA) 6921169689Skan { 6922169689Skan /* We don't need recovery because even if this is ld.sa 6923169689Skan ALAT entry will be allocated only if NAT bit is set to zero. 6924169689Skan So it is enough to use ld.c here. */ 6925169689Skan 6926169689Skan if (ts & BEGIN_CONTROL) 6927169689Skan { 6928169689Skan load_no += SPEC_GEN_SA; 6929169689Skan 6930169689Skan if (!mflag_sched_ldc) 6931169689Skan shift = SPEC_GEN_CHKA_FOR_SA_OFFSET; 6932169689Skan } 6933169689Skan else 6934169689Skan { 6935169689Skan load_no += SPEC_GEN_A; 6936169689Skan 6937169689Skan if (!mflag_sched_ldc) 6938169689Skan shift = SPEC_GEN_CHKA_FOR_A_OFFSET; 6939169689Skan } 6940169689Skan } 6941169689Skan else if (ts & BEGIN_CONTROL) 6942169689Skan { 6943169689Skan /* ld.sa can be used instead of ld.s to avoid basic block splitting. */ 6944169689Skan if (!mflag_control_ldc) 6945169689Skan load_no += SPEC_GEN_S; 6946169689Skan else 6947169689Skan { 6948169689Skan gcc_assert (mflag_sched_ldc); 6949169689Skan load_no += SPEC_GEN_SA_FOR_S; 6950169689Skan } 6951169689Skan } 6952169689Skan else 6953169689Skan gcc_unreachable (); 6954169689Skan 6955169689Skan /* Set the desired check index. We add '1', because zero element in this 6956169689Skan array means, that instruction with such uid is non-speculative. */ 6957169689Skan spec_check_no[INSN_UID (insn)] = load_no + shift + 1; 6958169689Skan 6959169689Skan if (!gen_p) 6960169689Skan return 0; 6961169689Skan 6962169689Skan new_pat = gen_load[load_no] (copy_rtx (recog_data.operand[0]), 6963169689Skan copy_rtx (recog_data.operand[1])); 6964169689Skan 6965169689Skan pat = PATTERN (insn); 6966169689Skan if (GET_CODE (pat) == COND_EXEC) 6967169689Skan new_pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx 6968169689Skan (COND_EXEC_TEST (pat)), new_pat); 6969169689Skan 6970169689Skan return new_pat; 6971169689Skan} 6972169689Skan 6973169689Skan/* Offset to branchy checks. */ 6974169689Skanenum { SPEC_GEN_CHECK_MUTATION_OFFSET = 5 * SPEC_N }; 6975169689Skan 6976169689Skan/* Return nonzero, if INSN needs branchy recovery check. */ 6977169689Skanstatic bool 6978169689Skania64_needs_block_p (rtx insn) 6979169689Skan{ 6980169689Skan int check_no; 6981169689Skan 6982169689Skan check_no = spec_check_no[INSN_UID(insn)] - 1; 6983169689Skan gcc_assert (0 <= check_no && check_no < SPEC_GEN_CHECK_MUTATION_OFFSET); 6984169689Skan 6985169689Skan return ((SPEC_GEN_S <= check_no && check_no < SPEC_GEN_S + SPEC_N) 6986169689Skan || (4 * SPEC_N <= check_no && check_no < 4 * SPEC_N + SPEC_N)); 6987169689Skan} 6988169689Skan 6989169689Skan/* Generate (or regenerate, if (MUTATE_P)) recovery check for INSN. 6990169689Skan If (LABEL != 0 || MUTATE_P), generate branchy recovery check. 6991169689Skan Otherwise, generate a simple check. */ 6992169689Skanstatic rtx 6993169689Skania64_gen_check (rtx insn, rtx label, bool mutate_p) 6994169689Skan{ 6995169689Skan rtx op1, pat, check_pat; 6996169689Skan 6997169689Skan static rtx (* const gen_check[]) (rtx, rtx) = { 6998169689Skan gen_movbi_clr, 6999169689Skan gen_movqi_clr, 7000169689Skan gen_movhi_clr, 7001169689Skan gen_movsi_clr, 7002169689Skan gen_movdi_clr, 7003169689Skan gen_movsf_clr, 7004169689Skan gen_movdf_clr, 7005169689Skan gen_movxf_clr, 7006169689Skan gen_movti_clr, 7007169689Skan gen_zero_extendqidi2_clr, 7008169689Skan gen_zero_extendhidi2_clr, 7009169689Skan gen_zero_extendsidi2_clr, 7010169689Skan 7011169689Skan gen_speculation_check_bi, 7012169689Skan gen_speculation_check_qi, 7013169689Skan gen_speculation_check_hi, 7014169689Skan gen_speculation_check_si, 7015169689Skan gen_speculation_check_di, 7016169689Skan gen_speculation_check_sf, 7017169689Skan gen_speculation_check_df, 7018169689Skan gen_speculation_check_xf, 7019169689Skan gen_speculation_check_ti, 7020169689Skan gen_speculation_check_di, 7021169689Skan gen_speculation_check_di, 7022169689Skan gen_speculation_check_di, 7023169689Skan 7024169689Skan gen_movbi_clr, 7025169689Skan gen_movqi_clr, 7026169689Skan gen_movhi_clr, 7027169689Skan gen_movsi_clr, 7028169689Skan gen_movdi_clr, 7029169689Skan gen_movsf_clr, 7030169689Skan gen_movdf_clr, 7031169689Skan gen_movxf_clr, 7032169689Skan gen_movti_clr, 7033169689Skan gen_zero_extendqidi2_clr, 7034169689Skan gen_zero_extendhidi2_clr, 7035169689Skan gen_zero_extendsidi2_clr, 7036169689Skan 7037169689Skan gen_movbi_clr, 7038169689Skan gen_movqi_clr, 7039169689Skan gen_movhi_clr, 7040169689Skan gen_movsi_clr, 7041169689Skan gen_movdi_clr, 7042169689Skan gen_movsf_clr, 7043169689Skan gen_movdf_clr, 7044169689Skan gen_movxf_clr, 7045169689Skan gen_movti_clr, 7046169689Skan gen_zero_extendqidi2_clr, 7047169689Skan gen_zero_extendhidi2_clr, 7048169689Skan gen_zero_extendsidi2_clr, 7049169689Skan 7050169689Skan gen_advanced_load_check_clr_bi, 7051169689Skan gen_advanced_load_check_clr_qi, 7052169689Skan gen_advanced_load_check_clr_hi, 7053169689Skan gen_advanced_load_check_clr_si, 7054169689Skan gen_advanced_load_check_clr_di, 7055169689Skan gen_advanced_load_check_clr_sf, 7056169689Skan gen_advanced_load_check_clr_df, 7057169689Skan gen_advanced_load_check_clr_xf, 7058169689Skan gen_advanced_load_check_clr_ti, 7059169689Skan gen_advanced_load_check_clr_di, 7060169689Skan gen_advanced_load_check_clr_di, 7061169689Skan gen_advanced_load_check_clr_di, 7062169689Skan 7063169689Skan /* Following checks are generated during mutation. */ 7064169689Skan gen_advanced_load_check_clr_bi, 7065169689Skan gen_advanced_load_check_clr_qi, 7066169689Skan gen_advanced_load_check_clr_hi, 7067169689Skan gen_advanced_load_check_clr_si, 7068169689Skan gen_advanced_load_check_clr_di, 7069169689Skan gen_advanced_load_check_clr_sf, 7070169689Skan gen_advanced_load_check_clr_df, 7071169689Skan gen_advanced_load_check_clr_xf, 7072169689Skan gen_advanced_load_check_clr_ti, 7073169689Skan gen_advanced_load_check_clr_di, 7074169689Skan gen_advanced_load_check_clr_di, 7075169689Skan gen_advanced_load_check_clr_di, 7076169689Skan 7077169689Skan 0,0,0,0,0,0,0,0,0,0,0,0, 7078169689Skan 7079169689Skan gen_advanced_load_check_clr_bi, 7080169689Skan gen_advanced_load_check_clr_qi, 7081169689Skan gen_advanced_load_check_clr_hi, 7082169689Skan gen_advanced_load_check_clr_si, 7083169689Skan gen_advanced_load_check_clr_di, 7084169689Skan gen_advanced_load_check_clr_sf, 7085169689Skan gen_advanced_load_check_clr_df, 7086169689Skan gen_advanced_load_check_clr_xf, 7087169689Skan gen_advanced_load_check_clr_ti, 7088169689Skan gen_advanced_load_check_clr_di, 7089169689Skan gen_advanced_load_check_clr_di, 7090169689Skan gen_advanced_load_check_clr_di, 7091169689Skan 7092169689Skan gen_speculation_check_bi, 7093169689Skan gen_speculation_check_qi, 7094169689Skan gen_speculation_check_hi, 7095169689Skan gen_speculation_check_si, 7096169689Skan gen_speculation_check_di, 7097169689Skan gen_speculation_check_sf, 7098169689Skan gen_speculation_check_df, 7099169689Skan gen_speculation_check_xf, 7100169689Skan gen_speculation_check_ti, 7101169689Skan gen_speculation_check_di, 7102169689Skan gen_speculation_check_di, 7103169689Skan gen_speculation_check_di 7104169689Skan }; 7105169689Skan 7106169689Skan extract_insn_cached (insn); 7107169689Skan 7108169689Skan if (label) 7109169689Skan { 7110169689Skan gcc_assert (mutate_p || ia64_needs_block_p (insn)); 7111169689Skan op1 = label; 7112169689Skan } 7113169689Skan else 7114169689Skan { 7115169689Skan gcc_assert (!mutate_p && !ia64_needs_block_p (insn)); 7116169689Skan op1 = copy_rtx (recog_data.operand[1]); 7117169689Skan } 7118169689Skan 7119169689Skan if (mutate_p) 7120169689Skan /* INSN is ld.c. 7121169689Skan Find the speculation check number by searching for original 7122169689Skan speculative load in the RESOLVED_DEPS list of INSN. 7123169689Skan As long as patterns are unique for each instruction, this can be 7124169689Skan accomplished by matching ORIG_PAT fields. */ 7125169689Skan { 7126169689Skan rtx link; 7127169689Skan int check_no = 0; 7128169689Skan rtx orig_pat = ORIG_PAT (insn); 7129169689Skan 7130169689Skan for (link = RESOLVED_DEPS (insn); link; link = XEXP (link, 1)) 7131169689Skan { 7132169689Skan rtx x = XEXP (link, 0); 7133169689Skan 7134169689Skan if (ORIG_PAT (x) == orig_pat) 7135169689Skan check_no = spec_check_no[INSN_UID (x)]; 7136169689Skan } 7137169689Skan gcc_assert (check_no); 7138169689Skan 7139169689Skan spec_check_no[INSN_UID (insn)] = (check_no 7140169689Skan + SPEC_GEN_CHECK_MUTATION_OFFSET); 7141169689Skan } 7142169689Skan 7143169689Skan check_pat = (gen_check[spec_check_no[INSN_UID (insn)] - 1] 7144169689Skan (copy_rtx (recog_data.operand[0]), op1)); 7145169689Skan 7146169689Skan pat = PATTERN (insn); 7147169689Skan if (GET_CODE (pat) == COND_EXEC) 7148169689Skan check_pat = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (COND_EXEC_TEST (pat)), 7149169689Skan check_pat); 7150169689Skan 7151169689Skan return check_pat; 7152169689Skan} 7153169689Skan 7154169689Skan/* Return nonzero, if X is branchy recovery check. */ 7155169689Skanstatic int 7156169689Skania64_spec_check_p (rtx x) 7157169689Skan{ 7158169689Skan x = PATTERN (x); 7159169689Skan if (GET_CODE (x) == COND_EXEC) 7160169689Skan x = COND_EXEC_CODE (x); 7161169689Skan if (GET_CODE (x) == SET) 7162169689Skan return ia64_spec_check_src_p (SET_SRC (x)); 7163169689Skan return 0; 7164169689Skan} 7165169689Skan 7166169689Skan/* Return nonzero, if SRC belongs to recovery check. */ 7167169689Skanstatic int 7168169689Skania64_spec_check_src_p (rtx src) 7169169689Skan{ 7170169689Skan if (GET_CODE (src) == IF_THEN_ELSE) 7171169689Skan { 7172169689Skan rtx t; 7173169689Skan 7174169689Skan t = XEXP (src, 0); 7175169689Skan if (GET_CODE (t) == NE) 7176169689Skan { 7177169689Skan t = XEXP (t, 0); 7178169689Skan 7179169689Skan if (GET_CODE (t) == UNSPEC) 7180169689Skan { 7181169689Skan int code; 7182169689Skan 7183169689Skan code = XINT (t, 1); 7184169689Skan 7185169689Skan if (code == UNSPEC_CHKACLR 7186169689Skan || code == UNSPEC_CHKS 7187169689Skan || code == UNSPEC_LDCCLR) 7188169689Skan { 7189169689Skan gcc_assert (code != 0); 7190169689Skan return code; 7191169689Skan } 7192169689Skan } 7193169689Skan } 7194169689Skan } 7195169689Skan return 0; 7196169689Skan} 7197132718Skan 719890075Sobrien 7199132718Skan/* The following page contains abstract data `bundle states' which are 7200132718Skan used for bundling insns (inserting nops and template generation). */ 720190075Sobrien 7202132718Skan/* The following describes state of insn bundling. */ 720390075Sobrien 7204132718Skanstruct bundle_state 720590075Sobrien{ 7206132718Skan /* Unique bundle state number to identify them in the debugging 7207132718Skan output */ 7208132718Skan int unique_num; 7209132718Skan rtx insn; /* corresponding insn, NULL for the 1st and the last state */ 7210132718Skan /* number nops before and after the insn */ 7211132718Skan short before_nops_num, after_nops_num; 7212132718Skan int insn_num; /* insn number (0 - for initial state, 1 - for the 1st 7213132718Skan insn */ 7214132718Skan int cost; /* cost of the state in cycles */ 7215132718Skan int accumulated_insns_num; /* number of all previous insns including 7216132718Skan nops. L is considered as 2 insns */ 7217132718Skan int branch_deviation; /* deviation of previous branches from 3rd slots */ 7218132718Skan struct bundle_state *next; /* next state with the same insn_num */ 7219132718Skan struct bundle_state *originator; /* originator (previous insn state) */ 7220132718Skan /* All bundle states are in the following chain. */ 7221132718Skan struct bundle_state *allocated_states_chain; 7222132718Skan /* The DFA State after issuing the insn and the nops. */ 7223132718Skan state_t dfa_state; 7224132718Skan}; 722590075Sobrien 7226132718Skan/* The following is map insn number to the corresponding bundle state. */ 722790075Sobrien 7228132718Skanstatic struct bundle_state **index_to_bundle_states; 722990075Sobrien 7230132718Skan/* The unique number of next bundle state. */ 723190075Sobrien 7232132718Skanstatic int bundle_states_num; 723390075Sobrien 7234132718Skan/* All allocated bundle states are in the following chain. */ 723590075Sobrien 7236132718Skanstatic struct bundle_state *allocated_bundle_states_chain; 723790075Sobrien 7238132718Skan/* All allocated but not used bundle states are in the following 7239132718Skan chain. */ 724090075Sobrien 7241132718Skanstatic struct bundle_state *free_bundle_state_chain; 724290075Sobrien 724390075Sobrien 7244132718Skan/* The following function returns a free bundle state. */ 724596263Sobrien 7246132718Skanstatic struct bundle_state * 7247132718Skanget_free_bundle_state (void) 7248132718Skan{ 7249132718Skan struct bundle_state *result; 725096263Sobrien 7251132718Skan if (free_bundle_state_chain != NULL) 7252132718Skan { 7253132718Skan result = free_bundle_state_chain; 7254132718Skan free_bundle_state_chain = result->next; 725590075Sobrien } 7256132718Skan else 725790075Sobrien { 7258132718Skan result = xmalloc (sizeof (struct bundle_state)); 7259132718Skan result->dfa_state = xmalloc (dfa_state_size); 7260132718Skan result->allocated_states_chain = allocated_bundle_states_chain; 7261132718Skan allocated_bundle_states_chain = result; 726290075Sobrien } 7263132718Skan result->unique_num = bundle_states_num++; 7264132718Skan return result; 726590075Sobrien 726690075Sobrien} 726790075Sobrien 7268132718Skan/* The following function frees given bundle state. */ 726990075Sobrien 727090075Sobrienstatic void 7271132718Skanfree_bundle_state (struct bundle_state *state) 727290075Sobrien{ 7273132718Skan state->next = free_bundle_state_chain; 7274132718Skan free_bundle_state_chain = state; 727590075Sobrien} 727690075Sobrien 7277132718Skan/* Start work with abstract data `bundle states'. */ 7278132718Skan 727990075Sobrienstatic void 7280132718Skaninitiate_bundle_states (void) 728190075Sobrien{ 7282132718Skan bundle_states_num = 0; 7283132718Skan free_bundle_state_chain = NULL; 7284132718Skan allocated_bundle_states_chain = NULL; 728590075Sobrien} 728690075Sobrien 7287132718Skan/* Finish work with abstract data `bundle states'. */ 728890075Sobrien 728990075Sobrienstatic void 7290132718Skanfinish_bundle_states (void) 729190075Sobrien{ 7292132718Skan struct bundle_state *curr_state, *next_state; 729390075Sobrien 7294132718Skan for (curr_state = allocated_bundle_states_chain; 7295132718Skan curr_state != NULL; 7296132718Skan curr_state = next_state) 729790075Sobrien { 7298132718Skan next_state = curr_state->allocated_states_chain; 7299132718Skan free (curr_state->dfa_state); 7300132718Skan free (curr_state); 7301132718Skan } 7302132718Skan} 730390075Sobrien 7304132718Skan/* Hash table of the bundle states. The key is dfa_state and insn_num 7305132718Skan of the bundle states. */ 730690075Sobrien 7307132718Skanstatic htab_t bundle_state_table; 730890075Sobrien 7309132718Skan/* The function returns hash of BUNDLE_STATE. */ 731090075Sobrien 7311132718Skanstatic unsigned 7312132718Skanbundle_state_hash (const void *bundle_state) 7313132718Skan{ 7314132718Skan const struct bundle_state *state = (struct bundle_state *) bundle_state; 7315132718Skan unsigned result, i; 731690075Sobrien 7317132718Skan for (result = i = 0; i < dfa_state_size; i++) 7318132718Skan result += (((unsigned char *) state->dfa_state) [i] 7319132718Skan << ((i % CHAR_BIT) * 3 + CHAR_BIT)); 7320132718Skan return result + state->insn_num; 732190075Sobrien} 732290075Sobrien 7323132718Skan/* The function returns nonzero if the bundle state keys are equal. */ 732490075Sobrien 732590075Sobrienstatic int 7326132718Skanbundle_state_eq_p (const void *bundle_state_1, const void *bundle_state_2) 732790075Sobrien{ 7328132718Skan const struct bundle_state * state1 = (struct bundle_state *) bundle_state_1; 7329132718Skan const struct bundle_state * state2 = (struct bundle_state *) bundle_state_2; 733090075Sobrien 7331132718Skan return (state1->insn_num == state2->insn_num 7332132718Skan && memcmp (state1->dfa_state, state2->dfa_state, 7333132718Skan dfa_state_size) == 0); 733490075Sobrien} 733590075Sobrien 7336132718Skan/* The function inserts the BUNDLE_STATE into the hash table. The 7337132718Skan function returns nonzero if the bundle has been inserted into the 7338132718Skan table. The table contains the best bundle state with given key. */ 733990075Sobrien 734090075Sobrienstatic int 7341132718Skaninsert_bundle_state (struct bundle_state *bundle_state) 734290075Sobrien{ 7343132718Skan void **entry_ptr; 734490075Sobrien 7345132718Skan entry_ptr = htab_find_slot (bundle_state_table, bundle_state, 1); 7346132718Skan if (*entry_ptr == NULL) 7347132718Skan { 7348132718Skan bundle_state->next = index_to_bundle_states [bundle_state->insn_num]; 7349132718Skan index_to_bundle_states [bundle_state->insn_num] = bundle_state; 7350132718Skan *entry_ptr = (void *) bundle_state; 7351132718Skan return TRUE; 7352132718Skan } 7353132718Skan else if (bundle_state->cost < ((struct bundle_state *) *entry_ptr)->cost 7354132718Skan || (bundle_state->cost == ((struct bundle_state *) *entry_ptr)->cost 7355132718Skan && (((struct bundle_state *)*entry_ptr)->accumulated_insns_num 7356132718Skan > bundle_state->accumulated_insns_num 7357132718Skan || (((struct bundle_state *) 7358132718Skan *entry_ptr)->accumulated_insns_num 7359132718Skan == bundle_state->accumulated_insns_num 7360132718Skan && ((struct bundle_state *) 7361132718Skan *entry_ptr)->branch_deviation 7362132718Skan > bundle_state->branch_deviation)))) 736390075Sobrien 736490075Sobrien { 7365132718Skan struct bundle_state temp; 736690075Sobrien 7367132718Skan temp = *(struct bundle_state *) *entry_ptr; 7368132718Skan *(struct bundle_state *) *entry_ptr = *bundle_state; 7369132718Skan ((struct bundle_state *) *entry_ptr)->next = temp.next; 7370132718Skan *bundle_state = temp; 737190075Sobrien } 7372132718Skan return FALSE; 737390075Sobrien} 737490075Sobrien 7375132718Skan/* Start work with the hash table. */ 737690075Sobrien 737790075Sobrienstatic void 7378132718Skaninitiate_bundle_state_table (void) 737990075Sobrien{ 7380132718Skan bundle_state_table = htab_create (50, bundle_state_hash, bundle_state_eq_p, 7381132718Skan (htab_del) 0); 7382132718Skan} 738390075Sobrien 7384132718Skan/* Finish work with the hash table. */ 738590075Sobrien 7386132718Skanstatic void 7387132718Skanfinish_bundle_state_table (void) 7388132718Skan{ 7389132718Skan htab_delete (bundle_state_table); 7390132718Skan} 739190075Sobrien 7392132718Skan 739390075Sobrien 7394132718Skan/* The following variable is a insn `nop' used to check bundle states 7395132718Skan with different number of inserted nops. */ 739690075Sobrien 7397132718Skanstatic rtx ia64_nop; 739890075Sobrien 7399132718Skan/* The following function tries to issue NOPS_NUM nops for the current 7400132718Skan state without advancing processor cycle. If it failed, the 7401132718Skan function returns FALSE and frees the current state. */ 740290075Sobrien 7403132718Skanstatic int 7404132718Skantry_issue_nops (struct bundle_state *curr_state, int nops_num) 7405132718Skan{ 7406132718Skan int i; 7407132718Skan 7408132718Skan for (i = 0; i < nops_num; i++) 7409132718Skan if (state_transition (curr_state->dfa_state, ia64_nop) >= 0) 7410132718Skan { 7411132718Skan free_bundle_state (curr_state); 7412132718Skan return FALSE; 7413132718Skan } 7414132718Skan return TRUE; 741590075Sobrien} 741690075Sobrien 7417132718Skan/* The following function tries to issue INSN for the current 7418132718Skan state without advancing processor cycle. If it failed, the 7419132718Skan function returns FALSE and frees the current state. */ 742090075Sobrien 742190075Sobrienstatic int 7422132718Skantry_issue_insn (struct bundle_state *curr_state, rtx insn) 742390075Sobrien{ 7424132718Skan if (insn && state_transition (curr_state->dfa_state, insn) >= 0) 7425132718Skan { 7426132718Skan free_bundle_state (curr_state); 7427132718Skan return FALSE; 7428132718Skan } 7429132718Skan return TRUE; 7430132718Skan} 743190075Sobrien 7432132718Skan/* The following function tries to issue BEFORE_NOPS_NUM nops and INSN 7433132718Skan starting with ORIGINATOR without advancing processor cycle. If 7434132718Skan TRY_BUNDLE_END_P is TRUE, the function also/only (if 7435132718Skan ONLY_BUNDLE_END_P is TRUE) tries to issue nops to fill all bundle. 7436132718Skan If it was successful, the function creates new bundle state and 7437132718Skan insert into the hash table and into `index_to_bundle_states'. */ 743890075Sobrien 7439132718Skanstatic void 7440132718Skanissue_nops_and_insn (struct bundle_state *originator, int before_nops_num, 7441132718Skan rtx insn, int try_bundle_end_p, int only_bundle_end_p) 7442132718Skan{ 7443132718Skan struct bundle_state *curr_state; 744490075Sobrien 7445132718Skan curr_state = get_free_bundle_state (); 7446132718Skan memcpy (curr_state->dfa_state, originator->dfa_state, dfa_state_size); 7447132718Skan curr_state->insn = insn; 7448132718Skan curr_state->insn_num = originator->insn_num + 1; 7449132718Skan curr_state->cost = originator->cost; 7450132718Skan curr_state->originator = originator; 7451132718Skan curr_state->before_nops_num = before_nops_num; 7452132718Skan curr_state->after_nops_num = 0; 7453132718Skan curr_state->accumulated_insns_num 7454132718Skan = originator->accumulated_insns_num + before_nops_num; 7455132718Skan curr_state->branch_deviation = originator->branch_deviation; 7456169689Skan gcc_assert (insn); 7457169689Skan if (INSN_CODE (insn) == CODE_FOR_insn_group_barrier) 745890075Sobrien { 7459169689Skan gcc_assert (GET_MODE (insn) != TImode); 7460132718Skan if (!try_issue_nops (curr_state, before_nops_num)) 7461132718Skan return; 7462132718Skan if (!try_issue_insn (curr_state, insn)) 7463132718Skan return; 7464132718Skan memcpy (temp_dfa_state, curr_state->dfa_state, dfa_state_size); 7465132718Skan if (state_transition (temp_dfa_state, dfa_pre_cycle_insn) >= 0 7466132718Skan && curr_state->accumulated_insns_num % 3 != 0) 7467132718Skan { 7468132718Skan free_bundle_state (curr_state); 7469132718Skan return; 7470132718Skan } 747190075Sobrien } 7472132718Skan else if (GET_MODE (insn) != TImode) 747390075Sobrien { 7474132718Skan if (!try_issue_nops (curr_state, before_nops_num)) 7475132718Skan return; 7476132718Skan if (!try_issue_insn (curr_state, insn)) 7477132718Skan return; 7478132718Skan curr_state->accumulated_insns_num++; 7479169689Skan gcc_assert (GET_CODE (PATTERN (insn)) != ASM_INPUT 7480169689Skan && asm_noperands (PATTERN (insn)) < 0); 7481169689Skan 7482132718Skan if (ia64_safe_type (insn) == TYPE_L) 7483132718Skan curr_state->accumulated_insns_num++; 748490075Sobrien } 7485132718Skan else 748690075Sobrien { 7487169689Skan /* If this is an insn that must be first in a group, then don't allow 7488169689Skan nops to be emitted before it. Currently, alloc is the only such 7489169689Skan supported instruction. */ 7490169689Skan /* ??? The bundling automatons should handle this for us, but they do 7491169689Skan not yet have support for the first_insn attribute. */ 7492169689Skan if (before_nops_num > 0 && get_attr_first_insn (insn) == FIRST_INSN_YES) 7493169689Skan { 7494169689Skan free_bundle_state (curr_state); 7495169689Skan return; 7496169689Skan } 7497169689Skan 7498132718Skan state_transition (curr_state->dfa_state, dfa_pre_cycle_insn); 7499132718Skan state_transition (curr_state->dfa_state, NULL); 7500132718Skan curr_state->cost++; 7501132718Skan if (!try_issue_nops (curr_state, before_nops_num)) 7502132718Skan return; 7503132718Skan if (!try_issue_insn (curr_state, insn)) 7504132718Skan return; 7505132718Skan curr_state->accumulated_insns_num++; 7506132718Skan if (GET_CODE (PATTERN (insn)) == ASM_INPUT 7507132718Skan || asm_noperands (PATTERN (insn)) >= 0) 750890075Sobrien { 7509132718Skan /* Finish bundle containing asm insn. */ 7510132718Skan curr_state->after_nops_num 7511132718Skan = 3 - curr_state->accumulated_insns_num % 3; 7512132718Skan curr_state->accumulated_insns_num 7513132718Skan += 3 - curr_state->accumulated_insns_num % 3; 751490075Sobrien } 7515132718Skan else if (ia64_safe_type (insn) == TYPE_L) 7516132718Skan curr_state->accumulated_insns_num++; 751790075Sobrien } 7518132718Skan if (ia64_safe_type (insn) == TYPE_B) 7519132718Skan curr_state->branch_deviation 7520132718Skan += 2 - (curr_state->accumulated_insns_num - 1) % 3; 7521132718Skan if (try_bundle_end_p && curr_state->accumulated_insns_num % 3 != 0) 7522132718Skan { 7523132718Skan if (!only_bundle_end_p && insert_bundle_state (curr_state)) 7524132718Skan { 7525132718Skan state_t dfa_state; 7526132718Skan struct bundle_state *curr_state1; 7527132718Skan struct bundle_state *allocated_states_chain; 752890075Sobrien 7529132718Skan curr_state1 = get_free_bundle_state (); 7530132718Skan dfa_state = curr_state1->dfa_state; 7531132718Skan allocated_states_chain = curr_state1->allocated_states_chain; 7532132718Skan *curr_state1 = *curr_state; 7533132718Skan curr_state1->dfa_state = dfa_state; 7534132718Skan curr_state1->allocated_states_chain = allocated_states_chain; 7535132718Skan memcpy (curr_state1->dfa_state, curr_state->dfa_state, 7536132718Skan dfa_state_size); 7537132718Skan curr_state = curr_state1; 7538132718Skan } 7539132718Skan if (!try_issue_nops (curr_state, 7540132718Skan 3 - curr_state->accumulated_insns_num % 3)) 7541132718Skan return; 7542132718Skan curr_state->after_nops_num 7543132718Skan = 3 - curr_state->accumulated_insns_num % 3; 7544132718Skan curr_state->accumulated_insns_num 7545132718Skan += 3 - curr_state->accumulated_insns_num % 3; 7546132718Skan } 7547132718Skan if (!insert_bundle_state (curr_state)) 7548132718Skan free_bundle_state (curr_state); 7549132718Skan return; 755090075Sobrien} 755190075Sobrien 7552132718Skan/* The following function returns position in the two window bundle 7553132718Skan for given STATE. */ 755490075Sobrien 7555132718Skanstatic int 7556132718Skanget_max_pos (state_t state) 755790075Sobrien{ 7558132718Skan if (cpu_unit_reservation_p (state, pos_6)) 7559132718Skan return 6; 7560132718Skan else if (cpu_unit_reservation_p (state, pos_5)) 7561132718Skan return 5; 7562132718Skan else if (cpu_unit_reservation_p (state, pos_4)) 7563132718Skan return 4; 7564132718Skan else if (cpu_unit_reservation_p (state, pos_3)) 7565132718Skan return 3; 7566132718Skan else if (cpu_unit_reservation_p (state, pos_2)) 7567132718Skan return 2; 7568132718Skan else if (cpu_unit_reservation_p (state, pos_1)) 7569132718Skan return 1; 7570132718Skan else 7571132718Skan return 0; 757290075Sobrien} 757390075Sobrien 7574132718Skan/* The function returns code of a possible template for given position 7575132718Skan and state. The function should be called only with 2 values of 7576169689Skan position equal to 3 or 6. We avoid generating F NOPs by putting 7577169689Skan templates containing F insns at the end of the template search 7578169689Skan because undocumented anomaly in McKinley derived cores which can 7579169689Skan cause stalls if an F-unit insn (including a NOP) is issued within a 7580169689Skan six-cycle window after reading certain application registers (such 7581169689Skan as ar.bsp). Furthermore, power-considerations also argue against 7582169689Skan the use of F-unit instructions unless they're really needed. */ 758390075Sobrien 7584132718Skanstatic int 7585132718Skanget_template (state_t state, int pos) 758690075Sobrien{ 7587132718Skan switch (pos) 758890075Sobrien { 7589132718Skan case 3: 7590169689Skan if (cpu_unit_reservation_p (state, _0mmi_)) 7591169689Skan return 1; 7592169689Skan else if (cpu_unit_reservation_p (state, _0mii_)) 7593132718Skan return 0; 7594169689Skan else if (cpu_unit_reservation_p (state, _0mmb_)) 7595169689Skan return 7; 7596169689Skan else if (cpu_unit_reservation_p (state, _0mib_)) 7597169689Skan return 6; 7598169689Skan else if (cpu_unit_reservation_p (state, _0mbb_)) 7599169689Skan return 5; 7600169689Skan else if (cpu_unit_reservation_p (state, _0bbb_)) 7601169689Skan return 4; 7602169689Skan else if (cpu_unit_reservation_p (state, _0mmf_)) 7603169689Skan return 3; 7604132718Skan else if (cpu_unit_reservation_p (state, _0mfi_)) 7605132718Skan return 2; 7606132718Skan else if (cpu_unit_reservation_p (state, _0mfb_)) 7607132718Skan return 8; 7608132718Skan else if (cpu_unit_reservation_p (state, _0mlx_)) 7609132718Skan return 9; 7610132718Skan else 7611169689Skan gcc_unreachable (); 7612132718Skan case 6: 7613169689Skan if (cpu_unit_reservation_p (state, _1mmi_)) 7614169689Skan return 1; 7615169689Skan else if (cpu_unit_reservation_p (state, _1mii_)) 7616132718Skan return 0; 7617169689Skan else if (cpu_unit_reservation_p (state, _1mmb_)) 7618169689Skan return 7; 7619169689Skan else if (cpu_unit_reservation_p (state, _1mib_)) 7620169689Skan return 6; 7621169689Skan else if (cpu_unit_reservation_p (state, _1mbb_)) 7622169689Skan return 5; 7623169689Skan else if (cpu_unit_reservation_p (state, _1bbb_)) 7624169689Skan return 4; 7625169689Skan else if (_1mmf_ >= 0 && cpu_unit_reservation_p (state, _1mmf_)) 7626169689Skan return 3; 7627132718Skan else if (cpu_unit_reservation_p (state, _1mfi_)) 7628132718Skan return 2; 7629132718Skan else if (cpu_unit_reservation_p (state, _1mfb_)) 7630132718Skan return 8; 7631132718Skan else if (cpu_unit_reservation_p (state, _1mlx_)) 7632132718Skan return 9; 7633132718Skan else 7634169689Skan gcc_unreachable (); 7635132718Skan default: 7636169689Skan gcc_unreachable (); 763790075Sobrien } 763890075Sobrien} 763990075Sobrien 7640132718Skan/* The following function returns an insn important for insn bundling 7641132718Skan followed by INSN and before TAIL. */ 764290075Sobrien 7643132718Skanstatic rtx 7644132718Skanget_next_important_insn (rtx insn, rtx tail) 764590075Sobrien{ 7646132718Skan for (; insn && insn != tail; insn = NEXT_INSN (insn)) 7647132718Skan if (INSN_P (insn) 7648132718Skan && ia64_safe_itanium_class (insn) != ITANIUM_CLASS_IGNORE 7649132718Skan && GET_CODE (PATTERN (insn)) != USE 7650132718Skan && GET_CODE (PATTERN (insn)) != CLOBBER) 7651132718Skan return insn; 7652132718Skan return NULL_RTX; 765390075Sobrien} 765490075Sobrien 7655169689Skan/* Add a bundle selector TEMPLATE0 before INSN. */ 7656169689Skan 7657169689Skanstatic void 7658169689Skania64_add_bundle_selector_before (int template0, rtx insn) 7659169689Skan{ 7660169689Skan rtx b = gen_bundle_selector (GEN_INT (template0)); 7661169689Skan 7662169689Skan ia64_emit_insn_before (b, insn); 7663169689Skan#if NR_BUNDLES == 10 7664169689Skan if ((template0 == 4 || template0 == 5) 7665169689Skan && (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS))) 7666169689Skan { 7667169689Skan int i; 7668169689Skan rtx note = NULL_RTX; 7669169689Skan 7670169689Skan /* In .mbb and .bbb bundles, check if CALL_INSN isn't in the 7671169689Skan first or second slot. If it is and has REG_EH_NOTE set, copy it 7672169689Skan to following nops, as br.call sets rp to the address of following 7673169689Skan bundle and therefore an EH region end must be on a bundle 7674169689Skan boundary. */ 7675169689Skan insn = PREV_INSN (insn); 7676169689Skan for (i = 0; i < 3; i++) 7677169689Skan { 7678169689Skan do 7679169689Skan insn = next_active_insn (insn); 7680169689Skan while (GET_CODE (insn) == INSN 7681169689Skan && get_attr_empty (insn) == EMPTY_YES); 7682169689Skan if (GET_CODE (insn) == CALL_INSN) 7683169689Skan note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); 7684169689Skan else if (note) 7685169689Skan { 7686169689Skan int code; 7687169689Skan 7688169689Skan gcc_assert ((code = recog_memoized (insn)) == CODE_FOR_nop 7689169689Skan || code == CODE_FOR_nop_b); 7690169689Skan if (find_reg_note (insn, REG_EH_REGION, NULL_RTX)) 7691169689Skan note = NULL_RTX; 7692169689Skan else 7693169689Skan REG_NOTES (insn) 7694169689Skan = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (note, 0), 7695169689Skan REG_NOTES (insn)); 7696169689Skan } 7697169689Skan } 7698169689Skan } 7699169689Skan#endif 7700169689Skan} 7701169689Skan 7702132718Skan/* The following function does insn bundling. Bundling means 7703132718Skan inserting templates and nop insns to fit insn groups into permitted 7704132718Skan templates. Instruction scheduling uses NDFA (non-deterministic 7705132718Skan finite automata) encoding informations about the templates and the 7706132718Skan inserted nops. Nondeterminism of the automata permits follows 7707132718Skan all possible insn sequences very fast. 770890075Sobrien 7709132718Skan Unfortunately it is not possible to get information about inserting 7710132718Skan nop insns and used templates from the automata states. The 7711132718Skan automata only says that we can issue an insn possibly inserting 7712132718Skan some nops before it and using some template. Therefore insn 7713132718Skan bundling in this function is implemented by using DFA 7714169689Skan (deterministic finite automata). We follow all possible insn 7715132718Skan sequences by inserting 0-2 nops (that is what the NDFA describe for 7716132718Skan insn scheduling) before/after each insn being bundled. We know the 7717132718Skan start of simulated processor cycle from insn scheduling (insn 7718132718Skan starting a new cycle has TImode). 771990075Sobrien 7720132718Skan Simple implementation of insn bundling would create enormous 7721132718Skan number of possible insn sequences satisfying information about new 7722132718Skan cycle ticks taken from the insn scheduling. To make the algorithm 7723132718Skan practical we use dynamic programming. Each decision (about 7724132718Skan inserting nops and implicitly about previous decisions) is described 7725132718Skan by structure bundle_state (see above). If we generate the same 7726132718Skan bundle state (key is automaton state after issuing the insns and 7727132718Skan nops for it), we reuse already generated one. As consequence we 7728169689Skan reject some decisions which cannot improve the solution and 7729132718Skan reduce memory for the algorithm. 773090075Sobrien 7731132718Skan When we reach the end of EBB (extended basic block), we choose the 7732132718Skan best sequence and then, moving back in EBB, insert templates for 7733132718Skan the best alternative. The templates are taken from querying 7734132718Skan automaton state for each insn in chosen bundle states. 7735132718Skan 7736132718Skan So the algorithm makes two (forward and backward) passes through 7737132718Skan EBB. There is an additional forward pass through EBB for Itanium1 7738132718Skan processor. This pass inserts more nops to make dependency between 7739132718Skan a producer insn and MMMUL/MMSHF at least 4 cycles long. */ 7740132718Skan 774190075Sobrienstatic void 7742132718Skanbundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail) 774390075Sobrien{ 7744132718Skan struct bundle_state *curr_state, *next_state, *best_state; 7745132718Skan rtx insn, next_insn; 7746132718Skan int insn_num; 7747132718Skan int i, bundle_end_p, only_bundle_end_p, asm_p; 7748132718Skan int pos = 0, max_pos, template0, template1; 7749132718Skan rtx b; 7750132718Skan rtx nop; 7751132718Skan enum attr_type type; 775290075Sobrien 7753132718Skan insn_num = 0; 7754132718Skan /* Count insns in the EBB. */ 7755132718Skan for (insn = NEXT_INSN (prev_head_insn); 7756132718Skan insn && insn != tail; 7757132718Skan insn = NEXT_INSN (insn)) 7758132718Skan if (INSN_P (insn)) 7759132718Skan insn_num++; 7760132718Skan if (insn_num == 0) 7761132718Skan return; 7762132718Skan bundling_p = 1; 7763132718Skan dfa_clean_insn_cache (); 7764132718Skan initiate_bundle_state_table (); 7765132718Skan index_to_bundle_states = xmalloc ((insn_num + 2) 7766132718Skan * sizeof (struct bundle_state *)); 7767169689Skan /* First (forward) pass -- generation of bundle states. */ 7768132718Skan curr_state = get_free_bundle_state (); 7769132718Skan curr_state->insn = NULL; 7770132718Skan curr_state->before_nops_num = 0; 7771132718Skan curr_state->after_nops_num = 0; 7772132718Skan curr_state->insn_num = 0; 7773132718Skan curr_state->cost = 0; 7774132718Skan curr_state->accumulated_insns_num = 0; 7775132718Skan curr_state->branch_deviation = 0; 7776132718Skan curr_state->next = NULL; 7777132718Skan curr_state->originator = NULL; 7778132718Skan state_reset (curr_state->dfa_state); 7779132718Skan index_to_bundle_states [0] = curr_state; 7780132718Skan insn_num = 0; 7781132718Skan /* Shift cycle mark if it is put on insn which could be ignored. */ 7782132718Skan for (insn = NEXT_INSN (prev_head_insn); 7783132718Skan insn != tail; 7784132718Skan insn = NEXT_INSN (insn)) 7785132718Skan if (INSN_P (insn) 7786132718Skan && (ia64_safe_itanium_class (insn) == ITANIUM_CLASS_IGNORE 7787132718Skan || GET_CODE (PATTERN (insn)) == USE 7788132718Skan || GET_CODE (PATTERN (insn)) == CLOBBER) 7789132718Skan && GET_MODE (insn) == TImode) 7790132718Skan { 7791132718Skan PUT_MODE (insn, VOIDmode); 7792132718Skan for (next_insn = NEXT_INSN (insn); 7793132718Skan next_insn != tail; 7794132718Skan next_insn = NEXT_INSN (next_insn)) 7795132718Skan if (INSN_P (next_insn) 7796132718Skan && ia64_safe_itanium_class (next_insn) != ITANIUM_CLASS_IGNORE 7797132718Skan && GET_CODE (PATTERN (next_insn)) != USE 7798132718Skan && GET_CODE (PATTERN (next_insn)) != CLOBBER) 7799132718Skan { 7800132718Skan PUT_MODE (next_insn, TImode); 7801132718Skan break; 7802132718Skan } 7803132718Skan } 7804169689Skan /* Forward pass: generation of bundle states. */ 7805132718Skan for (insn = get_next_important_insn (NEXT_INSN (prev_head_insn), tail); 7806132718Skan insn != NULL_RTX; 7807132718Skan insn = next_insn) 780890075Sobrien { 7809169689Skan gcc_assert (INSN_P (insn) 7810169689Skan && ia64_safe_itanium_class (insn) != ITANIUM_CLASS_IGNORE 7811169689Skan && GET_CODE (PATTERN (insn)) != USE 7812169689Skan && GET_CODE (PATTERN (insn)) != CLOBBER); 7813132718Skan type = ia64_safe_type (insn); 7814132718Skan next_insn = get_next_important_insn (NEXT_INSN (insn), tail); 7815132718Skan insn_num++; 7816132718Skan index_to_bundle_states [insn_num] = NULL; 7817132718Skan for (curr_state = index_to_bundle_states [insn_num - 1]; 7818132718Skan curr_state != NULL; 7819132718Skan curr_state = next_state) 7820132718Skan { 7821132718Skan pos = curr_state->accumulated_insns_num % 3; 7822132718Skan next_state = curr_state->next; 7823132718Skan /* We must fill up the current bundle in order to start a 7824132718Skan subsequent asm insn in a new bundle. Asm insn is always 7825132718Skan placed in a separate bundle. */ 7826132718Skan only_bundle_end_p 7827132718Skan = (next_insn != NULL_RTX 7828132718Skan && INSN_CODE (insn) == CODE_FOR_insn_group_barrier 7829132718Skan && ia64_safe_type (next_insn) == TYPE_UNKNOWN); 7830132718Skan /* We may fill up the current bundle if it is the cycle end 7831132718Skan without a group barrier. */ 7832132718Skan bundle_end_p 7833132718Skan = (only_bundle_end_p || next_insn == NULL_RTX 7834132718Skan || (GET_MODE (next_insn) == TImode 7835132718Skan && INSN_CODE (insn) != CODE_FOR_insn_group_barrier)); 7836132718Skan if (type == TYPE_F || type == TYPE_B || type == TYPE_L 7837132718Skan || type == TYPE_S 7838132718Skan /* We need to insert 2 nops for cases like M_MII. To 7839132718Skan guarantee issuing all insns on the same cycle for 7840132718Skan Itanium 1, we need to issue 2 nops after the first M 7841132718Skan insn (MnnMII where n is a nop insn). */ 7842132718Skan || ((type == TYPE_M || type == TYPE_A) 7843132718Skan && ia64_tune == PROCESSOR_ITANIUM 7844132718Skan && !bundle_end_p && pos == 1)) 7845132718Skan issue_nops_and_insn (curr_state, 2, insn, bundle_end_p, 7846132718Skan only_bundle_end_p); 7847132718Skan issue_nops_and_insn (curr_state, 1, insn, bundle_end_p, 7848132718Skan only_bundle_end_p); 7849132718Skan issue_nops_and_insn (curr_state, 0, insn, bundle_end_p, 7850132718Skan only_bundle_end_p); 7851132718Skan } 7852169689Skan gcc_assert (index_to_bundle_states [insn_num]); 7853132718Skan for (curr_state = index_to_bundle_states [insn_num]; 7854132718Skan curr_state != NULL; 7855132718Skan curr_state = curr_state->next) 7856132718Skan if (verbose >= 2 && dump) 7857132718Skan { 7858132718Skan /* This structure is taken from generated code of the 7859132718Skan pipeline hazard recognizer (see file insn-attrtab.c). 7860132718Skan Please don't forget to change the structure if a new 7861132718Skan automaton is added to .md file. */ 7862132718Skan struct DFA_chip 7863132718Skan { 7864132718Skan unsigned short one_automaton_state; 7865132718Skan unsigned short oneb_automaton_state; 7866132718Skan unsigned short two_automaton_state; 7867132718Skan unsigned short twob_automaton_state; 7868132718Skan }; 7869132718Skan 7870132718Skan fprintf 7871132718Skan (dump, 7872132718Skan "// Bundle state %d (orig %d, cost %d, nops %d/%d, insns %d, branch %d, state %d) for %d\n", 7873132718Skan curr_state->unique_num, 7874132718Skan (curr_state->originator == NULL 7875132718Skan ? -1 : curr_state->originator->unique_num), 7876132718Skan curr_state->cost, 7877132718Skan curr_state->before_nops_num, curr_state->after_nops_num, 7878132718Skan curr_state->accumulated_insns_num, curr_state->branch_deviation, 7879132718Skan (ia64_tune == PROCESSOR_ITANIUM 7880132718Skan ? ((struct DFA_chip *) curr_state->dfa_state)->oneb_automaton_state 7881132718Skan : ((struct DFA_chip *) curr_state->dfa_state)->twob_automaton_state), 7882132718Skan INSN_UID (insn)); 7883132718Skan } 788490075Sobrien } 7885169689Skan 7886169689Skan /* We should find a solution because the 2nd insn scheduling has 7887169689Skan found one. */ 7888169689Skan gcc_assert (index_to_bundle_states [insn_num]); 7889132718Skan /* Find a state corresponding to the best insn sequence. */ 7890132718Skan best_state = NULL; 7891132718Skan for (curr_state = index_to_bundle_states [insn_num]; 7892132718Skan curr_state != NULL; 7893132718Skan curr_state = curr_state->next) 7894132718Skan /* We are just looking at the states with fully filled up last 7895132718Skan bundle. The first we prefer insn sequences with minimal cost 7896132718Skan then with minimal inserted nops and finally with branch insns 7897132718Skan placed in the 3rd slots. */ 7898132718Skan if (curr_state->accumulated_insns_num % 3 == 0 7899132718Skan && (best_state == NULL || best_state->cost > curr_state->cost 7900132718Skan || (best_state->cost == curr_state->cost 7901132718Skan && (curr_state->accumulated_insns_num 7902132718Skan < best_state->accumulated_insns_num 7903132718Skan || (curr_state->accumulated_insns_num 7904132718Skan == best_state->accumulated_insns_num 7905132718Skan && curr_state->branch_deviation 7906132718Skan < best_state->branch_deviation))))) 7907132718Skan best_state = curr_state; 7908132718Skan /* Second (backward) pass: adding nops and templates. */ 7909132718Skan insn_num = best_state->before_nops_num; 7910132718Skan template0 = template1 = -1; 7911132718Skan for (curr_state = best_state; 7912132718Skan curr_state->originator != NULL; 7913132718Skan curr_state = curr_state->originator) 791490075Sobrien { 7915132718Skan insn = curr_state->insn; 7916132718Skan asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT 7917132718Skan || asm_noperands (PATTERN (insn)) >= 0); 7918132718Skan insn_num++; 7919132718Skan if (verbose >= 2 && dump) 792090075Sobrien { 7921132718Skan struct DFA_chip 7922132718Skan { 7923132718Skan unsigned short one_automaton_state; 7924132718Skan unsigned short oneb_automaton_state; 7925132718Skan unsigned short two_automaton_state; 7926132718Skan unsigned short twob_automaton_state; 7927132718Skan }; 792890075Sobrien 7929132718Skan fprintf 7930132718Skan (dump, 7931132718Skan "// Best %d (orig %d, cost %d, nops %d/%d, insns %d, branch %d, state %d) for %d\n", 7932132718Skan curr_state->unique_num, 7933132718Skan (curr_state->originator == NULL 7934132718Skan ? -1 : curr_state->originator->unique_num), 7935132718Skan curr_state->cost, 7936132718Skan curr_state->before_nops_num, curr_state->after_nops_num, 7937132718Skan curr_state->accumulated_insns_num, curr_state->branch_deviation, 7938132718Skan (ia64_tune == PROCESSOR_ITANIUM 7939132718Skan ? ((struct DFA_chip *) curr_state->dfa_state)->oneb_automaton_state 7940132718Skan : ((struct DFA_chip *) curr_state->dfa_state)->twob_automaton_state), 7941132718Skan INSN_UID (insn)); 794290075Sobrien } 7943132718Skan /* Find the position in the current bundle window. The window can 7944132718Skan contain at most two bundles. Two bundle window means that 7945132718Skan the processor will make two bundle rotation. */ 7946132718Skan max_pos = get_max_pos (curr_state->dfa_state); 7947132718Skan if (max_pos == 6 7948132718Skan /* The following (negative template number) means that the 7949132718Skan processor did one bundle rotation. */ 7950132718Skan || (max_pos == 3 && template0 < 0)) 795190075Sobrien { 7952132718Skan /* We are at the end of the window -- find template(s) for 7953132718Skan its bundle(s). */ 7954132718Skan pos = max_pos; 7955132718Skan if (max_pos == 3) 7956132718Skan template0 = get_template (curr_state->dfa_state, 3); 7957132718Skan else 795890075Sobrien { 7959132718Skan template1 = get_template (curr_state->dfa_state, 3); 7960132718Skan template0 = get_template (curr_state->dfa_state, 6); 796190075Sobrien } 796290075Sobrien } 7963132718Skan if (max_pos > 3 && template1 < 0) 7964132718Skan /* It may happen when we have the stop inside a bundle. */ 796590075Sobrien { 7966169689Skan gcc_assert (pos <= 3); 7967132718Skan template1 = get_template (curr_state->dfa_state, 3); 7968132718Skan pos += 3; 796990075Sobrien } 7970132718Skan if (!asm_p) 7971132718Skan /* Emit nops after the current insn. */ 7972132718Skan for (i = 0; i < curr_state->after_nops_num; i++) 7973132718Skan { 7974132718Skan nop = gen_nop (); 7975132718Skan emit_insn_after (nop, insn); 7976132718Skan pos--; 7977169689Skan gcc_assert (pos >= 0); 7978132718Skan if (pos % 3 == 0) 7979132718Skan { 7980132718Skan /* We are at the start of a bundle: emit the template 7981132718Skan (it should be defined). */ 7982169689Skan gcc_assert (template0 >= 0); 7983169689Skan ia64_add_bundle_selector_before (template0, nop); 7984132718Skan /* If we have two bundle window, we make one bundle 7985132718Skan rotation. Otherwise template0 will be undefined 7986132718Skan (negative value). */ 7987132718Skan template0 = template1; 7988132718Skan template1 = -1; 7989132718Skan } 7990132718Skan } 7991132718Skan /* Move the position backward in the window. Group barrier has 7992132718Skan no slot. Asm insn takes all bundle. */ 7993132718Skan if (INSN_CODE (insn) != CODE_FOR_insn_group_barrier 7994132718Skan && GET_CODE (PATTERN (insn)) != ASM_INPUT 7995132718Skan && asm_noperands (PATTERN (insn)) < 0) 7996132718Skan pos--; 7997132718Skan /* Long insn takes 2 slots. */ 7998132718Skan if (ia64_safe_type (insn) == TYPE_L) 7999132718Skan pos--; 8000169689Skan gcc_assert (pos >= 0); 8001132718Skan if (pos % 3 == 0 8002132718Skan && INSN_CODE (insn) != CODE_FOR_insn_group_barrier 8003132718Skan && GET_CODE (PATTERN (insn)) != ASM_INPUT 8004132718Skan && asm_noperands (PATTERN (insn)) < 0) 800590075Sobrien { 8006132718Skan /* The current insn is at the bundle start: emit the 8007132718Skan template. */ 8008169689Skan gcc_assert (template0 >= 0); 8009169689Skan ia64_add_bundle_selector_before (template0, insn); 8010132718Skan b = PREV_INSN (insn); 8011132718Skan insn = b; 8012169689Skan /* See comment above in analogous place for emitting nops 8013132718Skan after the insn. */ 8014132718Skan template0 = template1; 8015132718Skan template1 = -1; 801690075Sobrien } 8017132718Skan /* Emit nops after the current insn. */ 8018132718Skan for (i = 0; i < curr_state->before_nops_num; i++) 801990075Sobrien { 8020132718Skan nop = gen_nop (); 8021132718Skan ia64_emit_insn_before (nop, insn); 8022132718Skan nop = PREV_INSN (insn); 8023132718Skan insn = nop; 8024132718Skan pos--; 8025169689Skan gcc_assert (pos >= 0); 8026132718Skan if (pos % 3 == 0) 8027132718Skan { 8028169689Skan /* See comment above in analogous place for emitting nops 8029132718Skan after the insn. */ 8030169689Skan gcc_assert (template0 >= 0); 8031169689Skan ia64_add_bundle_selector_before (template0, insn); 8032132718Skan b = PREV_INSN (insn); 8033132718Skan insn = b; 8034132718Skan template0 = template1; 8035132718Skan template1 = -1; 8036132718Skan } 803790075Sobrien } 803890075Sobrien } 8039132718Skan if (ia64_tune == PROCESSOR_ITANIUM) 8040132718Skan /* Insert additional cycles for MM-insns (MMMUL and MMSHF). 8041132718Skan Itanium1 has a strange design, if the distance between an insn 8042132718Skan and dependent MM-insn is less 4 then we have a 6 additional 8043132718Skan cycles stall. So we make the distance equal to 4 cycles if it 8044132718Skan is less. */ 8045132718Skan for (insn = get_next_important_insn (NEXT_INSN (prev_head_insn), tail); 8046132718Skan insn != NULL_RTX; 8047132718Skan insn = next_insn) 804890075Sobrien { 8049169689Skan gcc_assert (INSN_P (insn) 8050169689Skan && ia64_safe_itanium_class (insn) != ITANIUM_CLASS_IGNORE 8051169689Skan && GET_CODE (PATTERN (insn)) != USE 8052169689Skan && GET_CODE (PATTERN (insn)) != CLOBBER); 8053132718Skan next_insn = get_next_important_insn (NEXT_INSN (insn), tail); 8054132718Skan if (INSN_UID (insn) < clocks_length && add_cycles [INSN_UID (insn)]) 8055132718Skan /* We found a MM-insn which needs additional cycles. */ 805690075Sobrien { 8057132718Skan rtx last; 8058132718Skan int i, j, n; 8059132718Skan int pred_stop_p; 8060132718Skan 8061132718Skan /* Now we are searching for a template of the bundle in 8062132718Skan which the MM-insn is placed and the position of the 8063132718Skan insn in the bundle (0, 1, 2). Also we are searching 8064132718Skan for that there is a stop before the insn. */ 8065132718Skan last = prev_active_insn (insn); 8066132718Skan pred_stop_p = recog_memoized (last) == CODE_FOR_insn_group_barrier; 8067132718Skan if (pred_stop_p) 8068132718Skan last = prev_active_insn (last); 8069132718Skan n = 0; 8070132718Skan for (;; last = prev_active_insn (last)) 8071132718Skan if (recog_memoized (last) == CODE_FOR_bundle_selector) 8072132718Skan { 8073132718Skan template0 = XINT (XVECEXP (PATTERN (last), 0, 0), 0); 8074132718Skan if (template0 == 9) 8075132718Skan /* The insn is in MLX bundle. Change the template 8076132718Skan onto MFI because we will add nops before the 8077132718Skan insn. It simplifies subsequent code a lot. */ 8078132718Skan PATTERN (last) 8079169689Skan = gen_bundle_selector (const2_rtx); /* -> MFI */ 8080132718Skan break; 8081132718Skan } 8082132718Skan else if (recog_memoized (last) != CODE_FOR_insn_group_barrier 8083132718Skan && (ia64_safe_itanium_class (last) 8084132718Skan != ITANIUM_CLASS_IGNORE)) 8085132718Skan n++; 8086132718Skan /* Some check of correctness: the stop is not at the 8087132718Skan bundle start, there are no more 3 insns in the bundle, 8088132718Skan and the MM-insn is not at the start of bundle with 8089132718Skan template MLX. */ 8090169689Skan gcc_assert ((!pred_stop_p || n) 8091169689Skan && n <= 2 8092169689Skan && (template0 != 9 || !n)); 8093132718Skan /* Put nops after the insn in the bundle. */ 8094132718Skan for (j = 3 - n; j > 0; j --) 8095132718Skan ia64_emit_insn_before (gen_nop (), insn); 8096132718Skan /* It takes into account that we will add more N nops 8097132718Skan before the insn lately -- please see code below. */ 8098132718Skan add_cycles [INSN_UID (insn)]--; 8099132718Skan if (!pred_stop_p || add_cycles [INSN_UID (insn)]) 8100132718Skan ia64_emit_insn_before (gen_insn_group_barrier (GEN_INT (3)), 8101132718Skan insn); 8102132718Skan if (pred_stop_p) 8103132718Skan add_cycles [INSN_UID (insn)]--; 8104132718Skan for (i = add_cycles [INSN_UID (insn)]; i > 0; i--) 810590075Sobrien { 8106132718Skan /* Insert "MII;" template. */ 8107169689Skan ia64_emit_insn_before (gen_bundle_selector (const0_rtx), 8108132718Skan insn); 8109132718Skan ia64_emit_insn_before (gen_nop (), insn); 8110132718Skan ia64_emit_insn_before (gen_nop (), insn); 8111132718Skan if (i > 1) 811290075Sobrien { 8113132718Skan /* To decrease code size, we use "MI;I;" 8114132718Skan template. */ 8115132718Skan ia64_emit_insn_before 8116132718Skan (gen_insn_group_barrier (GEN_INT (3)), insn); 8117132718Skan i--; 811890075Sobrien } 8119132718Skan ia64_emit_insn_before (gen_nop (), insn); 8120132718Skan ia64_emit_insn_before (gen_insn_group_barrier (GEN_INT (3)), 8121132718Skan insn); 812290075Sobrien } 8123132718Skan /* Put the MM-insn in the same slot of a bundle with the 8124132718Skan same template as the original one. */ 8125169689Skan ia64_add_bundle_selector_before (template0, insn); 8126132718Skan /* To put the insn in the same slot, add necessary number 8127132718Skan of nops. */ 8128132718Skan for (j = n; j > 0; j --) 8129132718Skan ia64_emit_insn_before (gen_nop (), insn); 8130132718Skan /* Put the stop if the original bundle had it. */ 8131132718Skan if (pred_stop_p) 8132132718Skan ia64_emit_insn_before (gen_insn_group_barrier (GEN_INT (3)), 8133132718Skan insn); 813490075Sobrien } 813590075Sobrien } 8136132718Skan free (index_to_bundle_states); 8137132718Skan finish_bundle_state_table (); 8138132718Skan bundling_p = 0; 8139132718Skan dfa_clean_insn_cache (); 8140132718Skan} 814190075Sobrien 8142132718Skan/* The following function is called at the end of scheduling BB or 8143132718Skan EBB. After reload, it inserts stop bits and does insn bundling. */ 8144132718Skan 8145132718Skanstatic void 8146132718Skania64_sched_finish (FILE *dump, int sched_verbose) 8147132718Skan{ 8148132718Skan if (sched_verbose) 8149132718Skan fprintf (dump, "// Finishing schedule.\n"); 8150132718Skan if (!reload_completed) 8151132718Skan return; 8152132718Skan if (reload_completed) 815390075Sobrien { 8154132718Skan final_emit_insn_group_barriers (dump); 8155132718Skan bundling (dump, sched_verbose, current_sched_info->prev_head, 8156132718Skan current_sched_info->next_tail); 8157132718Skan if (sched_verbose && dump) 8158132718Skan fprintf (dump, "// finishing %d-%d\n", 8159132718Skan INSN_UID (NEXT_INSN (current_sched_info->prev_head)), 8160132718Skan INSN_UID (PREV_INSN (current_sched_info->next_tail))); 816190075Sobrien 8162132718Skan return; 816390075Sobrien } 816490075Sobrien} 816590075Sobrien 8166132718Skan/* The following function inserts stop bits in scheduled BB or EBB. */ 8167132718Skan 8168132718Skanstatic void 8169132718Skanfinal_emit_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED) 817090075Sobrien{ 8171132718Skan rtx insn; 8172132718Skan int need_barrier_p = 0; 8173132718Skan rtx prev_insn = NULL_RTX; 817490075Sobrien 8175132718Skan init_insn_group_barriers (); 817690075Sobrien 8177132718Skan for (insn = NEXT_INSN (current_sched_info->prev_head); 8178132718Skan insn != current_sched_info->next_tail; 8179132718Skan insn = NEXT_INSN (insn)) 818090075Sobrien { 8181132718Skan if (GET_CODE (insn) == BARRIER) 818290075Sobrien { 8183132718Skan rtx last = prev_active_insn (insn); 818490075Sobrien 8185132718Skan if (! last) 818690075Sobrien continue; 8187132718Skan if (GET_CODE (last) == JUMP_INSN 8188132718Skan && GET_CODE (PATTERN (last)) == ADDR_DIFF_VEC) 8189132718Skan last = prev_active_insn (last); 8190132718Skan if (recog_memoized (last) != CODE_FOR_insn_group_barrier) 8191132718Skan emit_insn_after (gen_insn_group_barrier (GEN_INT (3)), last); 819290075Sobrien 8193132718Skan init_insn_group_barriers (); 8194132718Skan need_barrier_p = 0; 8195132718Skan prev_insn = NULL_RTX; 819690075Sobrien } 8197132718Skan else if (INSN_P (insn)) 819890075Sobrien { 8199132718Skan if (recog_memoized (insn) == CODE_FOR_insn_group_barrier) 820090075Sobrien { 8201132718Skan init_insn_group_barriers (); 8202132718Skan need_barrier_p = 0; 8203132718Skan prev_insn = NULL_RTX; 820490075Sobrien } 8205169689Skan else if (need_barrier_p || group_barrier_needed (insn)) 8206132718Skan { 8207132718Skan if (TARGET_EARLY_STOP_BITS) 8208132718Skan { 8209132718Skan rtx last; 821090075Sobrien 8211132718Skan for (last = insn; 8212132718Skan last != current_sched_info->prev_head; 8213132718Skan last = PREV_INSN (last)) 8214132718Skan if (INSN_P (last) && GET_MODE (last) == TImode 8215132718Skan && stops_p [INSN_UID (last)]) 8216132718Skan break; 8217132718Skan if (last == current_sched_info->prev_head) 8218132718Skan last = insn; 8219132718Skan last = prev_active_insn (last); 8220132718Skan if (last 8221132718Skan && recog_memoized (last) != CODE_FOR_insn_group_barrier) 8222132718Skan emit_insn_after (gen_insn_group_barrier (GEN_INT (3)), 8223132718Skan last); 8224132718Skan init_insn_group_barriers (); 8225132718Skan for (last = NEXT_INSN (last); 8226132718Skan last != insn; 8227132718Skan last = NEXT_INSN (last)) 8228132718Skan if (INSN_P (last)) 8229169689Skan group_barrier_needed (last); 8230132718Skan } 8231132718Skan else 8232132718Skan { 8233132718Skan emit_insn_before (gen_insn_group_barrier (GEN_INT (3)), 8234132718Skan insn); 8235132718Skan init_insn_group_barriers (); 8236132718Skan } 8237169689Skan group_barrier_needed (insn); 8238132718Skan prev_insn = NULL_RTX; 823990075Sobrien } 8240132718Skan else if (recog_memoized (insn) >= 0) 8241132718Skan prev_insn = insn; 8242132718Skan need_barrier_p = (GET_CODE (insn) == CALL_INSN 8243132718Skan || GET_CODE (PATTERN (insn)) == ASM_INPUT 8244132718Skan || asm_noperands (PATTERN (insn)) >= 0); 824590075Sobrien } 824690075Sobrien } 8247132718Skan} 824890075Sobrien 8249132718Skan 825090075Sobrien 8251169689Skan/* If the following function returns TRUE, we will use the DFA 8252132718Skan insn scheduler. */ 825390075Sobrien 8254132718Skanstatic int 8255132718Skania64_first_cycle_multipass_dfa_lookahead (void) 825690075Sobrien{ 8257132718Skan return (reload_completed ? 6 : 4); 8258132718Skan} 825990075Sobrien 8260132718Skan/* The following function initiates variable `dfa_pre_cycle_insn'. */ 826190075Sobrien 8262132718Skanstatic void 8263132718Skania64_init_dfa_pre_cycle_insn (void) 8264132718Skan{ 8265132718Skan if (temp_dfa_state == NULL) 826690075Sobrien { 8267132718Skan dfa_state_size = state_size (); 8268132718Skan temp_dfa_state = xmalloc (dfa_state_size); 8269132718Skan prev_cycle_state = xmalloc (dfa_state_size); 827090075Sobrien } 8271132718Skan dfa_pre_cycle_insn = make_insn_raw (gen_pre_cycle ()); 8272132718Skan PREV_INSN (dfa_pre_cycle_insn) = NEXT_INSN (dfa_pre_cycle_insn) = NULL_RTX; 8273132718Skan recog_memoized (dfa_pre_cycle_insn); 8274132718Skan dfa_stop_insn = make_insn_raw (gen_insn_group_barrier (GEN_INT (3))); 8275132718Skan PREV_INSN (dfa_stop_insn) = NEXT_INSN (dfa_stop_insn) = NULL_RTX; 8276132718Skan recog_memoized (dfa_stop_insn); 8277132718Skan} 827890075Sobrien 8279132718Skan/* The following function returns the pseudo insn DFA_PRE_CYCLE_INSN 8280132718Skan used by the DFA insn scheduler. */ 8281132718Skan 8282132718Skanstatic rtx 8283132718Skania64_dfa_pre_cycle_insn (void) 8284132718Skan{ 8285132718Skan return dfa_pre_cycle_insn; 8286132718Skan} 8287132718Skan 8288132718Skan/* The following function returns TRUE if PRODUCER (of type ilog or 8289132718Skan ld) produces address for CONSUMER (of type st or stf). */ 8290132718Skan 8291132718Skanint 8292132718Skania64_st_address_bypass_p (rtx producer, rtx consumer) 8293132718Skan{ 8294132718Skan rtx dest, reg, mem; 8295132718Skan 8296169689Skan gcc_assert (producer && consumer); 8297132718Skan dest = ia64_single_set (producer); 8298169689Skan gcc_assert (dest); 8299169689Skan reg = SET_DEST (dest); 8300169689Skan gcc_assert (reg); 8301132718Skan if (GET_CODE (reg) == SUBREG) 8302132718Skan reg = SUBREG_REG (reg); 8303169689Skan gcc_assert (GET_CODE (reg) == REG); 8304169689Skan 8305132718Skan dest = ia64_single_set (consumer); 8306169689Skan gcc_assert (dest); 8307169689Skan mem = SET_DEST (dest); 8308169689Skan gcc_assert (mem && GET_CODE (mem) == MEM); 8309132718Skan return reg_mentioned_p (reg, mem); 8310132718Skan} 831190075Sobrien 8312132718Skan/* The following function returns TRUE if PRODUCER (of type ilog or 8313132718Skan ld) produces address for CONSUMER (of type ld or fld). */ 831490075Sobrien 8315132718Skanint 8316132718Skania64_ld_address_bypass_p (rtx producer, rtx consumer) 8317132718Skan{ 8318132718Skan rtx dest, src, reg, mem; 831990075Sobrien 8320169689Skan gcc_assert (producer && consumer); 8321132718Skan dest = ia64_single_set (producer); 8322169689Skan gcc_assert (dest); 8323169689Skan reg = SET_DEST (dest); 8324169689Skan gcc_assert (reg); 8325132718Skan if (GET_CODE (reg) == SUBREG) 8326132718Skan reg = SUBREG_REG (reg); 8327169689Skan gcc_assert (GET_CODE (reg) == REG); 8328169689Skan 8329132718Skan src = ia64_single_set (consumer); 8330169689Skan gcc_assert (src); 8331169689Skan mem = SET_SRC (src); 8332169689Skan gcc_assert (mem); 8333169689Skan 8334132718Skan if (GET_CODE (mem) == UNSPEC && XVECLEN (mem, 0) > 0) 8335132718Skan mem = XVECEXP (mem, 0, 0); 8336169689Skan else if (GET_CODE (mem) == IF_THEN_ELSE) 8337169689Skan /* ??? Is this bypass necessary for ld.c? */ 8338169689Skan { 8339169689Skan gcc_assert (XINT (XEXP (XEXP (mem, 0), 0), 1) == UNSPEC_LDCCLR); 8340169689Skan mem = XEXP (mem, 1); 8341169689Skan } 8342169689Skan 8343132718Skan while (GET_CODE (mem) == SUBREG || GET_CODE (mem) == ZERO_EXTEND) 8344132718Skan mem = XEXP (mem, 0); 834590075Sobrien 8346169689Skan if (GET_CODE (mem) == UNSPEC) 8347169689Skan { 8348169689Skan int c = XINT (mem, 1); 8349169689Skan 8350169689Skan gcc_assert (c == UNSPEC_LDA || c == UNSPEC_LDS || c == UNSPEC_LDSA); 8351169689Skan mem = XVECEXP (mem, 0, 0); 8352169689Skan } 8353169689Skan 8354132718Skan /* Note that LO_SUM is used for GOT loads. */ 8355169689Skan gcc_assert (GET_CODE (mem) == LO_SUM || GET_CODE (mem) == MEM); 8356132718Skan 8357132718Skan return reg_mentioned_p (reg, mem); 835890075Sobrien} 835990075Sobrien 8360132718Skan/* The following function returns TRUE if INSN produces address for a 8361132718Skan load/store insn. We will place such insns into M slot because it 8362169689Skan decreases its latency time. */ 836390075Sobrien 8364132718Skanint 8365132718Skania64_produce_address_p (rtx insn) 836690075Sobrien{ 8367132718Skan return insn->call; 836890075Sobrien} 8369132718Skan 837090075Sobrien 837190075Sobrien/* Emit pseudo-ops for the assembler to describe predicate relations. 837290075Sobrien At present this assumes that we only consider predicate pairs to 837390075Sobrien be mutex, and that the assembler can deduce proper values from 837490075Sobrien straight-line code. */ 837590075Sobrien 837690075Sobrienstatic void 8377132718Skanemit_predicate_relation_info (void) 837890075Sobrien{ 8379117395Skan basic_block bb; 838090075Sobrien 8381117395Skan FOR_EACH_BB_REVERSE (bb) 838290075Sobrien { 838390075Sobrien int r; 8384132718Skan rtx head = BB_HEAD (bb); 838590075Sobrien 838690075Sobrien /* We only need such notes at code labels. */ 838790075Sobrien if (GET_CODE (head) != CODE_LABEL) 838890075Sobrien continue; 838990075Sobrien if (GET_CODE (NEXT_INSN (head)) == NOTE 839090075Sobrien && NOTE_LINE_NUMBER (NEXT_INSN (head)) == NOTE_INSN_BASIC_BLOCK) 839190075Sobrien head = NEXT_INSN (head); 839290075Sobrien 8393169689Skan /* Skip p0, which may be thought to be live due to (reg:DI p0) 8394169689Skan grabbing the entire block of predicate registers. */ 8395169689Skan for (r = PR_REG (2); r < PR_REG (64); r += 2) 8396169689Skan if (REGNO_REG_SET_P (bb->il.rtl->global_live_at_start, r)) 839790075Sobrien { 839890075Sobrien rtx p = gen_rtx_REG (BImode, r); 839990075Sobrien rtx n = emit_insn_after (gen_pred_rel_mutex (p), head); 8400132718Skan if (head == BB_END (bb)) 8401132718Skan BB_END (bb) = n; 840290075Sobrien head = n; 840390075Sobrien } 840490075Sobrien } 840590075Sobrien 840690075Sobrien /* Look for conditional calls that do not return, and protect predicate 840790075Sobrien relations around them. Otherwise the assembler will assume the call 840890075Sobrien returns, and complain about uses of call-clobbered predicates after 840990075Sobrien the call. */ 8410117395Skan FOR_EACH_BB_REVERSE (bb) 841190075Sobrien { 8412132718Skan rtx insn = BB_HEAD (bb); 8413132718Skan 841490075Sobrien while (1) 841590075Sobrien { 841690075Sobrien if (GET_CODE (insn) == CALL_INSN 841790075Sobrien && GET_CODE (PATTERN (insn)) == COND_EXEC 841890075Sobrien && find_reg_note (insn, REG_NORETURN, NULL_RTX)) 841990075Sobrien { 842090075Sobrien rtx b = emit_insn_before (gen_safe_across_calls_all (), insn); 842190075Sobrien rtx a = emit_insn_after (gen_safe_across_calls_normal (), insn); 8422132718Skan if (BB_HEAD (bb) == insn) 8423132718Skan BB_HEAD (bb) = b; 8424132718Skan if (BB_END (bb) == insn) 8425132718Skan BB_END (bb) = a; 842690075Sobrien } 8427132718Skan 8428132718Skan if (insn == BB_END (bb)) 842990075Sobrien break; 843090075Sobrien insn = NEXT_INSN (insn); 843190075Sobrien } 843290075Sobrien } 843390075Sobrien} 843490075Sobrien 8435132718Skan/* Perform machine dependent operations on the rtl chain INSNS. */ 843690075Sobrien 843790075Sobrienstatic void 8438132718Skania64_reorg (void) 843990075Sobrien{ 8440117395Skan /* We are freeing block_for_insn in the toplev to keep compatibility 8441117395Skan with old MDEP_REORGS that are not CFG based. Recompute it now. */ 8442117395Skan compute_bb_for_insn (); 8443117395Skan 844490075Sobrien /* If optimizing, we'll have split before scheduling. */ 844590075Sobrien if (optimize == 0) 8446117395Skan split_all_insns (0); 844790075Sobrien 8448117395Skan /* ??? update_life_info_in_dirty_blocks fails to terminate during 8449117395Skan non-optimizing bootstrap. */ 8450117395Skan update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES); 845190075Sobrien 8452169689Skan if (optimize && ia64_flag_schedule_insns2) 845390075Sobrien { 845490075Sobrien timevar_push (TV_SCHED2); 845590075Sobrien ia64_final_schedule = 1; 8456132718Skan 8457132718Skan initiate_bundle_states (); 8458132718Skan ia64_nop = make_insn_raw (gen_nop ()); 8459132718Skan PREV_INSN (ia64_nop) = NEXT_INSN (ia64_nop) = NULL_RTX; 8460132718Skan recog_memoized (ia64_nop); 8461132718Skan clocks_length = get_max_uid () + 1; 8462132718Skan stops_p = xcalloc (1, clocks_length); 8463132718Skan if (ia64_tune == PROCESSOR_ITANIUM) 8464132718Skan { 8465132718Skan clocks = xcalloc (clocks_length, sizeof (int)); 8466132718Skan add_cycles = xcalloc (clocks_length, sizeof (int)); 8467132718Skan } 8468132718Skan if (ia64_tune == PROCESSOR_ITANIUM2) 8469132718Skan { 8470132718Skan pos_1 = get_cpu_unit_code ("2_1"); 8471132718Skan pos_2 = get_cpu_unit_code ("2_2"); 8472132718Skan pos_3 = get_cpu_unit_code ("2_3"); 8473132718Skan pos_4 = get_cpu_unit_code ("2_4"); 8474132718Skan pos_5 = get_cpu_unit_code ("2_5"); 8475132718Skan pos_6 = get_cpu_unit_code ("2_6"); 8476132718Skan _0mii_ = get_cpu_unit_code ("2b_0mii."); 8477132718Skan _0mmi_ = get_cpu_unit_code ("2b_0mmi."); 8478132718Skan _0mfi_ = get_cpu_unit_code ("2b_0mfi."); 8479132718Skan _0mmf_ = get_cpu_unit_code ("2b_0mmf."); 8480132718Skan _0bbb_ = get_cpu_unit_code ("2b_0bbb."); 8481132718Skan _0mbb_ = get_cpu_unit_code ("2b_0mbb."); 8482132718Skan _0mib_ = get_cpu_unit_code ("2b_0mib."); 8483132718Skan _0mmb_ = get_cpu_unit_code ("2b_0mmb."); 8484132718Skan _0mfb_ = get_cpu_unit_code ("2b_0mfb."); 8485132718Skan _0mlx_ = get_cpu_unit_code ("2b_0mlx."); 8486132718Skan _1mii_ = get_cpu_unit_code ("2b_1mii."); 8487132718Skan _1mmi_ = get_cpu_unit_code ("2b_1mmi."); 8488132718Skan _1mfi_ = get_cpu_unit_code ("2b_1mfi."); 8489132718Skan _1mmf_ = get_cpu_unit_code ("2b_1mmf."); 8490132718Skan _1bbb_ = get_cpu_unit_code ("2b_1bbb."); 8491132718Skan _1mbb_ = get_cpu_unit_code ("2b_1mbb."); 8492132718Skan _1mib_ = get_cpu_unit_code ("2b_1mib."); 8493132718Skan _1mmb_ = get_cpu_unit_code ("2b_1mmb."); 8494132718Skan _1mfb_ = get_cpu_unit_code ("2b_1mfb."); 8495132718Skan _1mlx_ = get_cpu_unit_code ("2b_1mlx."); 8496132718Skan } 8497132718Skan else 8498132718Skan { 8499132718Skan pos_1 = get_cpu_unit_code ("1_1"); 8500132718Skan pos_2 = get_cpu_unit_code ("1_2"); 8501132718Skan pos_3 = get_cpu_unit_code ("1_3"); 8502132718Skan pos_4 = get_cpu_unit_code ("1_4"); 8503132718Skan pos_5 = get_cpu_unit_code ("1_5"); 8504132718Skan pos_6 = get_cpu_unit_code ("1_6"); 8505132718Skan _0mii_ = get_cpu_unit_code ("1b_0mii."); 8506132718Skan _0mmi_ = get_cpu_unit_code ("1b_0mmi."); 8507132718Skan _0mfi_ = get_cpu_unit_code ("1b_0mfi."); 8508132718Skan _0mmf_ = get_cpu_unit_code ("1b_0mmf."); 8509132718Skan _0bbb_ = get_cpu_unit_code ("1b_0bbb."); 8510132718Skan _0mbb_ = get_cpu_unit_code ("1b_0mbb."); 8511132718Skan _0mib_ = get_cpu_unit_code ("1b_0mib."); 8512132718Skan _0mmb_ = get_cpu_unit_code ("1b_0mmb."); 8513132718Skan _0mfb_ = get_cpu_unit_code ("1b_0mfb."); 8514132718Skan _0mlx_ = get_cpu_unit_code ("1b_0mlx."); 8515132718Skan _1mii_ = get_cpu_unit_code ("1b_1mii."); 8516132718Skan _1mmi_ = get_cpu_unit_code ("1b_1mmi."); 8517132718Skan _1mfi_ = get_cpu_unit_code ("1b_1mfi."); 8518132718Skan _1mmf_ = get_cpu_unit_code ("1b_1mmf."); 8519132718Skan _1bbb_ = get_cpu_unit_code ("1b_1bbb."); 8520132718Skan _1mbb_ = get_cpu_unit_code ("1b_1mbb."); 8521132718Skan _1mib_ = get_cpu_unit_code ("1b_1mib."); 8522132718Skan _1mmb_ = get_cpu_unit_code ("1b_1mmb."); 8523132718Skan _1mfb_ = get_cpu_unit_code ("1b_1mfb."); 8524132718Skan _1mlx_ = get_cpu_unit_code ("1b_1mlx."); 8525132718Skan } 8526169689Skan schedule_ebbs (); 8527132718Skan finish_bundle_states (); 8528132718Skan if (ia64_tune == PROCESSOR_ITANIUM) 8529132718Skan { 8530132718Skan free (add_cycles); 8531132718Skan free (clocks); 8532132718Skan } 8533132718Skan free (stops_p); 8534169689Skan stops_p = NULL; 8535169689Skan emit_insn_group_barriers (dump_file); 8536132718Skan 853790075Sobrien ia64_final_schedule = 0; 853890075Sobrien timevar_pop (TV_SCHED2); 853990075Sobrien } 854090075Sobrien else 8541169689Skan emit_all_insn_group_barriers (dump_file); 854290075Sobrien 854390075Sobrien /* A call must not be the last instruction in a function, so that the 854490075Sobrien return address is still within the function, so that unwinding works 854590075Sobrien properly. Note that IA-64 differs from dwarf2 on this point. */ 854690075Sobrien if (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)) 854790075Sobrien { 854890075Sobrien rtx insn; 854990075Sobrien int saw_stop = 0; 855090075Sobrien 855190075Sobrien insn = get_last_insn (); 855290075Sobrien if (! INSN_P (insn)) 855390075Sobrien insn = prev_active_insn (insn); 8554132718Skan /* Skip over insns that expand to nothing. */ 8555132718Skan while (GET_CODE (insn) == INSN && get_attr_empty (insn) == EMPTY_YES) 8556132718Skan { 8557132718Skan if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE 8558132718Skan && XINT (PATTERN (insn), 1) == UNSPECV_INSN_GROUP_BARRIER) 8559132718Skan saw_stop = 1; 856090075Sobrien insn = prev_active_insn (insn); 856190075Sobrien } 856290075Sobrien if (GET_CODE (insn) == CALL_INSN) 856390075Sobrien { 856490075Sobrien if (! saw_stop) 856590075Sobrien emit_insn (gen_insn_group_barrier (GEN_INT (3))); 856690075Sobrien emit_insn (gen_break_f ()); 856790075Sobrien emit_insn (gen_insn_group_barrier (GEN_INT (3))); 856890075Sobrien } 856990075Sobrien } 857090075Sobrien 857190075Sobrien emit_predicate_relation_info (); 8572169689Skan 8573169689Skan if (ia64_flag_var_tracking) 8574169689Skan { 8575169689Skan timevar_push (TV_VAR_TRACKING); 8576169689Skan variable_tracking_main (); 8577169689Skan timevar_pop (TV_VAR_TRACKING); 8578169689Skan } 857990075Sobrien} 858090075Sobrien 858190075Sobrien/* Return true if REGNO is used by the epilogue. */ 858290075Sobrien 858390075Sobrienint 8584132718Skania64_epilogue_uses (int regno) 858590075Sobrien{ 858690075Sobrien switch (regno) 858790075Sobrien { 858890075Sobrien case R_GR (1): 8589119256Skan /* With a call to a function in another module, we will write a new 8590119256Skan value to "gp". After returning from such a call, we need to make 8591119256Skan sure the function restores the original gp-value, even if the 8592119256Skan function itself does not use the gp anymore. */ 8593119256Skan return !(TARGET_AUTO_PIC || TARGET_NO_PIC); 859490075Sobrien 859590075Sobrien case IN_REG (0): case IN_REG (1): case IN_REG (2): case IN_REG (3): 859690075Sobrien case IN_REG (4): case IN_REG (5): case IN_REG (6): case IN_REG (7): 859790075Sobrien /* For functions defined with the syscall_linkage attribute, all 859890075Sobrien input registers are marked as live at all function exits. This 859990075Sobrien prevents the register allocator from using the input registers, 860090075Sobrien which in turn makes it possible to restart a system call after 860190075Sobrien an interrupt without having to save/restore the input registers. 860290075Sobrien This also prevents kernel data from leaking to application code. */ 860390075Sobrien return lookup_attribute ("syscall_linkage", 860490075Sobrien TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))) != NULL; 860590075Sobrien 860690075Sobrien case R_BR (0): 860790075Sobrien /* Conditional return patterns can't represent the use of `b0' as 860890075Sobrien the return address, so we force the value live this way. */ 860990075Sobrien return 1; 861090075Sobrien 861190075Sobrien case AR_PFS_REGNUM: 861290075Sobrien /* Likewise for ar.pfs, which is used by br.ret. */ 861390075Sobrien return 1; 861490075Sobrien 861590075Sobrien default: 861690075Sobrien return 0; 861790075Sobrien } 861890075Sobrien} 861990075Sobrien 862096263Sobrien/* Return true if REGNO is used by the frame unwinder. */ 862196263Sobrien 862296263Sobrienint 8623132718Skania64_eh_uses (int regno) 862490075Sobrien{ 862596263Sobrien if (! reload_completed) 862696263Sobrien return 0; 862796263Sobrien 862896263Sobrien if (current_frame_info.reg_save_b0 862996263Sobrien && regno == current_frame_info.reg_save_b0) 863096263Sobrien return 1; 863196263Sobrien if (current_frame_info.reg_save_pr 863296263Sobrien && regno == current_frame_info.reg_save_pr) 863396263Sobrien return 1; 863496263Sobrien if (current_frame_info.reg_save_ar_pfs 863596263Sobrien && regno == current_frame_info.reg_save_ar_pfs) 863696263Sobrien return 1; 863796263Sobrien if (current_frame_info.reg_save_ar_unat 863896263Sobrien && regno == current_frame_info.reg_save_ar_unat) 863996263Sobrien return 1; 864096263Sobrien if (current_frame_info.reg_save_ar_lc 864196263Sobrien && regno == current_frame_info.reg_save_ar_lc) 864296263Sobrien return 1; 864396263Sobrien 864496263Sobrien return 0; 864596263Sobrien} 864690075Sobrien 8647132718Skan/* Return true if this goes in small data/bss. */ 864890075Sobrien 864990075Sobrien/* ??? We could also support own long data here. Generating movl/add/ld8 865090075Sobrien instead of addl,ld8/ld8. This makes the code bigger, but should make the 865190075Sobrien code faster because there is one less load. This also includes incomplete 865290075Sobrien types which can't go in sdata/sbss. */ 865390075Sobrien 8654117395Skanstatic bool 8655132718Skania64_in_small_data_p (tree exp) 8656117395Skan{ 8657117395Skan if (TARGET_NO_SDATA) 8658117395Skan return false; 865990075Sobrien 8660132718Skan /* We want to merge strings, so we never consider them small data. */ 8661132718Skan if (TREE_CODE (exp) == STRING_CST) 8662132718Skan return false; 8663132718Skan 8664132718Skan /* Functions are never small data. */ 8665132718Skan if (TREE_CODE (exp) == FUNCTION_DECL) 8666132718Skan return false; 8667132718Skan 8668117395Skan if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) 8669117395Skan { 8670117395Skan const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); 8671169689Skan 8672117395Skan if (strcmp (section, ".sdata") == 0 8673169689Skan || strncmp (section, ".sdata.", 7) == 0 8674169689Skan || strncmp (section, ".gnu.linkonce.s.", 16) == 0 8675169689Skan || strcmp (section, ".sbss") == 0 8676169689Skan || strncmp (section, ".sbss.", 6) == 0 8677169689Skan || strncmp (section, ".gnu.linkonce.sb.", 17) == 0) 8678117395Skan return true; 8679117395Skan } 8680117395Skan else 8681117395Skan { 8682117395Skan HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); 868390075Sobrien 8684117395Skan /* If this is an incomplete type with size 0, then we can't put it 8685117395Skan in sdata because it might be too big when completed. */ 8686117395Skan if (size > 0 && size <= ia64_section_threshold) 8687117395Skan return true; 8688117395Skan } 8689117395Skan 8690117395Skan return false; 8691117395Skan} 869290075Sobrien 869390075Sobrien/* Output assembly directives for prologue regions. */ 869490075Sobrien 869590075Sobrien/* The current basic block number. */ 869690075Sobrien 8697117395Skanstatic bool last_block; 869890075Sobrien 869990075Sobrien/* True if we need a copy_state command at the start of the next block. */ 870090075Sobrien 8701117395Skanstatic bool need_copy_state; 870290075Sobrien 8703169689Skan#ifndef MAX_ARTIFICIAL_LABEL_BYTES 8704169689Skan# define MAX_ARTIFICIAL_LABEL_BYTES 30 8705169689Skan#endif 8706169689Skan 8707169689Skan/* Emit a debugging label after a call-frame-related insn. We'd 8708169689Skan rather output the label right away, but we'd have to output it 8709169689Skan after, not before, the instruction, and the instruction has not 8710169689Skan been output yet. So we emit the label after the insn, delete it to 8711169689Skan avoid introducing basic blocks, and mark it as preserved, such that 8712169689Skan it is still output, given that it is referenced in debug info. */ 8713169689Skan 8714169689Skanstatic const char * 8715169689Skania64_emit_deleted_label_after_insn (rtx insn) 8716169689Skan{ 8717169689Skan char label[MAX_ARTIFICIAL_LABEL_BYTES]; 8718169689Skan rtx lb = gen_label_rtx (); 8719169689Skan rtx label_insn = emit_label_after (lb, insn); 8720169689Skan 8721169689Skan LABEL_PRESERVE_P (lb) = 1; 8722169689Skan 8723169689Skan delete_insn (label_insn); 8724169689Skan 8725169689Skan ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (label_insn)); 8726169689Skan 8727169689Skan return xstrdup (label); 8728169689Skan} 8729169689Skan 8730169689Skan/* Define the CFA after INSN with the steady-state definition. */ 8731169689Skan 8732169689Skanstatic void 8733169689Skania64_dwarf2out_def_steady_cfa (rtx insn) 8734169689Skan{ 8735169689Skan rtx fp = frame_pointer_needed 8736169689Skan ? hard_frame_pointer_rtx 8737169689Skan : stack_pointer_rtx; 8738169689Skan 8739169689Skan dwarf2out_def_cfa 8740169689Skan (ia64_emit_deleted_label_after_insn (insn), 8741169689Skan REGNO (fp), 8742169689Skan ia64_initial_elimination_offset 8743169689Skan (REGNO (arg_pointer_rtx), REGNO (fp)) 8744169689Skan + ARG_POINTER_CFA_OFFSET (current_function_decl)); 8745169689Skan} 8746169689Skan 8747169689Skan/* The generic dwarf2 frame debug info generator does not define a 8748169689Skan separate region for the very end of the epilogue, so refrain from 8749169689Skan doing so in the IA64-specific code as well. */ 8750169689Skan 8751169689Skan#define IA64_CHANGE_CFA_IN_EPILOGUE 0 8752169689Skan 875390075Sobrien/* The function emits unwind directives for the start of an epilogue. */ 875490075Sobrien 875590075Sobrienstatic void 8756169689Skanprocess_epilogue (FILE *asm_out_file, rtx insn, bool unwind, bool frame) 875790075Sobrien{ 875890075Sobrien /* If this isn't the last block of the function, then we need to label the 875990075Sobrien current state, and copy it back in at the start of the next block. */ 876090075Sobrien 8761117395Skan if (!last_block) 876290075Sobrien { 8763169689Skan if (unwind) 8764169689Skan fprintf (asm_out_file, "\t.label_state %d\n", 8765169689Skan ++cfun->machine->state_num); 8766117395Skan need_copy_state = true; 876790075Sobrien } 876890075Sobrien 8769169689Skan if (unwind) 8770169689Skan fprintf (asm_out_file, "\t.restore sp\n"); 8771169689Skan if (IA64_CHANGE_CFA_IN_EPILOGUE && frame) 8772169689Skan dwarf2out_def_cfa (ia64_emit_deleted_label_after_insn (insn), 8773169689Skan STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); 877490075Sobrien} 877590075Sobrien 877690075Sobrien/* This function processes a SET pattern looking for specific patterns 877790075Sobrien which result in emitting an assembly directive required for unwinding. */ 877890075Sobrien 877990075Sobrienstatic int 8780169689Skanprocess_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame) 878190075Sobrien{ 878290075Sobrien rtx src = SET_SRC (pat); 878390075Sobrien rtx dest = SET_DEST (pat); 878490075Sobrien int src_regno, dest_regno; 878590075Sobrien 878690075Sobrien /* Look for the ALLOC insn. */ 878790075Sobrien if (GET_CODE (src) == UNSPEC_VOLATILE 8788117395Skan && XINT (src, 1) == UNSPECV_ALLOC 878990075Sobrien && GET_CODE (dest) == REG) 879090075Sobrien { 879190075Sobrien dest_regno = REGNO (dest); 879290075Sobrien 8793146895Skan /* If this is the final destination for ar.pfs, then this must 8794146895Skan be the alloc in the prologue. */ 8795146895Skan if (dest_regno == current_frame_info.reg_save_ar_pfs) 8796169689Skan { 8797169689Skan if (unwind) 8798169689Skan fprintf (asm_out_file, "\t.save ar.pfs, r%d\n", 8799169689Skan ia64_dbx_register_number (dest_regno)); 8800169689Skan } 8801146895Skan else 8802146895Skan { 8803146895Skan /* This must be an alloc before a sibcall. We must drop the 8804146895Skan old frame info. The easiest way to drop the old frame 8805146895Skan info is to ensure we had a ".restore sp" directive 8806146895Skan followed by a new prologue. If the procedure doesn't 8807146895Skan have a memory-stack frame, we'll issue a dummy ".restore 8808146895Skan sp" now. */ 8809146895Skan if (current_frame_info.total_size == 0 && !frame_pointer_needed) 8810146895Skan /* if haven't done process_epilogue() yet, do it now */ 8811169689Skan process_epilogue (asm_out_file, insn, unwind, frame); 8812169689Skan if (unwind) 8813169689Skan fprintf (asm_out_file, "\t.prologue\n"); 8814146895Skan } 881590075Sobrien return 1; 881690075Sobrien } 881790075Sobrien 881890075Sobrien /* Look for SP = .... */ 881990075Sobrien if (GET_CODE (dest) == REG && REGNO (dest) == STACK_POINTER_REGNUM) 882090075Sobrien { 882190075Sobrien if (GET_CODE (src) == PLUS) 882290075Sobrien { 882390075Sobrien rtx op0 = XEXP (src, 0); 882490075Sobrien rtx op1 = XEXP (src, 1); 8825169689Skan 8826169689Skan gcc_assert (op0 == dest && GET_CODE (op1) == CONST_INT); 8827169689Skan 8828169689Skan if (INTVAL (op1) < 0) 882990075Sobrien { 8830169689Skan gcc_assert (!frame_pointer_needed); 8831169689Skan if (unwind) 8832132718Skan fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n", 8833132718Skan -INTVAL (op1)); 8834169689Skan if (frame) 8835169689Skan ia64_dwarf2out_def_steady_cfa (insn); 883690075Sobrien } 883790075Sobrien else 8838169689Skan process_epilogue (asm_out_file, insn, unwind, frame); 883990075Sobrien } 884090075Sobrien else 8841169689Skan { 8842169689Skan gcc_assert (GET_CODE (src) == REG 8843169689Skan && REGNO (src) == HARD_FRAME_POINTER_REGNUM); 8844169689Skan process_epilogue (asm_out_file, insn, unwind, frame); 8845169689Skan } 884690075Sobrien 884790075Sobrien return 1; 884890075Sobrien } 884990075Sobrien 885090075Sobrien /* Register move we need to look at. */ 885190075Sobrien if (GET_CODE (dest) == REG && GET_CODE (src) == REG) 885290075Sobrien { 885390075Sobrien src_regno = REGNO (src); 885490075Sobrien dest_regno = REGNO (dest); 885590075Sobrien 885690075Sobrien switch (src_regno) 885790075Sobrien { 885890075Sobrien case BR_REG (0): 885990075Sobrien /* Saving return address pointer. */ 8860169689Skan gcc_assert (dest_regno == current_frame_info.reg_save_b0); 8861169689Skan if (unwind) 8862169689Skan fprintf (asm_out_file, "\t.save rp, r%d\n", 8863169689Skan ia64_dbx_register_number (dest_regno)); 886490075Sobrien return 1; 886590075Sobrien 886690075Sobrien case PR_REG (0): 8867169689Skan gcc_assert (dest_regno == current_frame_info.reg_save_pr); 8868169689Skan if (unwind) 8869169689Skan fprintf (asm_out_file, "\t.save pr, r%d\n", 8870169689Skan ia64_dbx_register_number (dest_regno)); 887190075Sobrien return 1; 887290075Sobrien 887390075Sobrien case AR_UNAT_REGNUM: 8874169689Skan gcc_assert (dest_regno == current_frame_info.reg_save_ar_unat); 8875169689Skan if (unwind) 8876169689Skan fprintf (asm_out_file, "\t.save ar.unat, r%d\n", 8877169689Skan ia64_dbx_register_number (dest_regno)); 887890075Sobrien return 1; 887990075Sobrien 888090075Sobrien case AR_LC_REGNUM: 8881169689Skan gcc_assert (dest_regno == current_frame_info.reg_save_ar_lc); 8882169689Skan if (unwind) 8883169689Skan fprintf (asm_out_file, "\t.save ar.lc, r%d\n", 8884169689Skan ia64_dbx_register_number (dest_regno)); 888590075Sobrien return 1; 888690075Sobrien 888790075Sobrien case STACK_POINTER_REGNUM: 8888169689Skan gcc_assert (dest_regno == HARD_FRAME_POINTER_REGNUM 8889169689Skan && frame_pointer_needed); 8890169689Skan if (unwind) 8891169689Skan fprintf (asm_out_file, "\t.vframe r%d\n", 8892169689Skan ia64_dbx_register_number (dest_regno)); 8893169689Skan if (frame) 8894169689Skan ia64_dwarf2out_def_steady_cfa (insn); 889590075Sobrien return 1; 889690075Sobrien 889790075Sobrien default: 889890075Sobrien /* Everything else should indicate being stored to memory. */ 8899169689Skan gcc_unreachable (); 890090075Sobrien } 890190075Sobrien } 890290075Sobrien 890390075Sobrien /* Memory store we need to look at. */ 890490075Sobrien if (GET_CODE (dest) == MEM && GET_CODE (src) == REG) 890590075Sobrien { 890690075Sobrien long off; 890790075Sobrien rtx base; 890890075Sobrien const char *saveop; 890990075Sobrien 891090075Sobrien if (GET_CODE (XEXP (dest, 0)) == REG) 891190075Sobrien { 891290075Sobrien base = XEXP (dest, 0); 891390075Sobrien off = 0; 891490075Sobrien } 8915169689Skan else 891690075Sobrien { 8917169689Skan gcc_assert (GET_CODE (XEXP (dest, 0)) == PLUS 8918169689Skan && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT); 891990075Sobrien base = XEXP (XEXP (dest, 0), 0); 892090075Sobrien off = INTVAL (XEXP (XEXP (dest, 0), 1)); 892190075Sobrien } 892290075Sobrien 892390075Sobrien if (base == hard_frame_pointer_rtx) 892490075Sobrien { 892590075Sobrien saveop = ".savepsp"; 892690075Sobrien off = - off; 892790075Sobrien } 892890075Sobrien else 8929169689Skan { 8930169689Skan gcc_assert (base == stack_pointer_rtx); 8931169689Skan saveop = ".savesp"; 8932169689Skan } 893390075Sobrien 893490075Sobrien src_regno = REGNO (src); 893590075Sobrien switch (src_regno) 893690075Sobrien { 893790075Sobrien case BR_REG (0): 8938169689Skan gcc_assert (!current_frame_info.reg_save_b0); 8939169689Skan if (unwind) 8940169689Skan fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off); 894190075Sobrien return 1; 894290075Sobrien 894390075Sobrien case PR_REG (0): 8944169689Skan gcc_assert (!current_frame_info.reg_save_pr); 8945169689Skan if (unwind) 8946169689Skan fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off); 894790075Sobrien return 1; 894890075Sobrien 894990075Sobrien case AR_LC_REGNUM: 8950169689Skan gcc_assert (!current_frame_info.reg_save_ar_lc); 8951169689Skan if (unwind) 8952169689Skan fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off); 895390075Sobrien return 1; 895490075Sobrien 895590075Sobrien case AR_PFS_REGNUM: 8956169689Skan gcc_assert (!current_frame_info.reg_save_ar_pfs); 8957169689Skan if (unwind) 8958169689Skan fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off); 895990075Sobrien return 1; 896090075Sobrien 896190075Sobrien case AR_UNAT_REGNUM: 8962169689Skan gcc_assert (!current_frame_info.reg_save_ar_unat); 8963169689Skan if (unwind) 8964169689Skan fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off); 896590075Sobrien return 1; 896690075Sobrien 896790075Sobrien case GR_REG (4): 896890075Sobrien case GR_REG (5): 896990075Sobrien case GR_REG (6): 897090075Sobrien case GR_REG (7): 8971169689Skan if (unwind) 8972169689Skan fprintf (asm_out_file, "\t.save.g 0x%x\n", 8973169689Skan 1 << (src_regno - GR_REG (4))); 897490075Sobrien return 1; 897590075Sobrien 897690075Sobrien case BR_REG (1): 897790075Sobrien case BR_REG (2): 897890075Sobrien case BR_REG (3): 897990075Sobrien case BR_REG (4): 898090075Sobrien case BR_REG (5): 8981169689Skan if (unwind) 8982169689Skan fprintf (asm_out_file, "\t.save.b 0x%x\n", 8983169689Skan 1 << (src_regno - BR_REG (1))); 898490075Sobrien return 1; 898590075Sobrien 898690075Sobrien case FR_REG (2): 898790075Sobrien case FR_REG (3): 898890075Sobrien case FR_REG (4): 898990075Sobrien case FR_REG (5): 8990169689Skan if (unwind) 8991169689Skan fprintf (asm_out_file, "\t.save.f 0x%x\n", 8992169689Skan 1 << (src_regno - FR_REG (2))); 899390075Sobrien return 1; 899490075Sobrien 899590075Sobrien case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19): 899690075Sobrien case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23): 899790075Sobrien case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27): 899890075Sobrien case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31): 8999169689Skan if (unwind) 9000169689Skan fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n", 9001169689Skan 1 << (src_regno - FR_REG (12))); 900290075Sobrien return 1; 900390075Sobrien 900490075Sobrien default: 900590075Sobrien return 0; 900690075Sobrien } 900790075Sobrien } 900890075Sobrien 900990075Sobrien return 0; 901090075Sobrien} 901190075Sobrien 901290075Sobrien 901390075Sobrien/* This function looks at a single insn and emits any directives 901490075Sobrien required to unwind this insn. */ 901590075Sobrienvoid 9016132718Skanprocess_for_unwind_directive (FILE *asm_out_file, rtx insn) 901790075Sobrien{ 9018169689Skan bool unwind = (flag_unwind_tables 9019169689Skan || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)); 9020169689Skan bool frame = dwarf2out_do_frame (); 9021169689Skan 9022169689Skan if (unwind || frame) 902390075Sobrien { 902490075Sobrien rtx pat; 902590075Sobrien 902690075Sobrien if (GET_CODE (insn) == NOTE 902790075Sobrien && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK) 902890075Sobrien { 9029117395Skan last_block = NOTE_BASIC_BLOCK (insn)->next_bb == EXIT_BLOCK_PTR; 903090075Sobrien 903190075Sobrien /* Restore unwind state from immediately before the epilogue. */ 903290075Sobrien if (need_copy_state) 903390075Sobrien { 9034169689Skan if (unwind) 9035169689Skan { 9036169689Skan fprintf (asm_out_file, "\t.body\n"); 9037169689Skan fprintf (asm_out_file, "\t.copy_state %d\n", 9038169689Skan cfun->machine->state_num); 9039169689Skan } 9040169689Skan if (IA64_CHANGE_CFA_IN_EPILOGUE && frame) 9041169689Skan ia64_dwarf2out_def_steady_cfa (insn); 9042117395Skan need_copy_state = false; 904390075Sobrien } 904490075Sobrien } 904590075Sobrien 9046117395Skan if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn)) 904790075Sobrien return; 904890075Sobrien 904990075Sobrien pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); 905090075Sobrien if (pat) 905190075Sobrien pat = XEXP (pat, 0); 905290075Sobrien else 905390075Sobrien pat = PATTERN (insn); 905490075Sobrien 905590075Sobrien switch (GET_CODE (pat)) 905690075Sobrien { 905790075Sobrien case SET: 9058169689Skan process_set (asm_out_file, pat, insn, unwind, frame); 905990075Sobrien break; 906090075Sobrien 906190075Sobrien case PARALLEL: 906290075Sobrien { 906390075Sobrien int par_index; 906490075Sobrien int limit = XVECLEN (pat, 0); 906590075Sobrien for (par_index = 0; par_index < limit; par_index++) 906690075Sobrien { 906790075Sobrien rtx x = XVECEXP (pat, 0, par_index); 906890075Sobrien if (GET_CODE (x) == SET) 9069169689Skan process_set (asm_out_file, x, insn, unwind, frame); 907090075Sobrien } 907190075Sobrien break; 907290075Sobrien } 907390075Sobrien 907490075Sobrien default: 9075169689Skan gcc_unreachable (); 907690075Sobrien } 907790075Sobrien } 907890075Sobrien} 907990075Sobrien 908090075Sobrien 9081169689Skanenum ia64_builtins 9082169689Skan{ 9083169689Skan IA64_BUILTIN_BSP, 9084169689Skan IA64_BUILTIN_FLUSHRS 9085169689Skan}; 9086169689Skan 908790075Sobrienvoid 9088132718Skania64_init_builtins (void) 908990075Sobrien{ 9090132718Skan tree fpreg_type; 9091132718Skan tree float80_type; 9092132718Skan 9093132718Skan /* The __fpreg type. */ 9094132718Skan fpreg_type = make_node (REAL_TYPE); 9095169689Skan TYPE_PRECISION (fpreg_type) = 82; 9096132718Skan layout_type (fpreg_type); 9097132718Skan (*lang_hooks.types.register_builtin_type) (fpreg_type, "__fpreg"); 9098132718Skan 9099132718Skan /* The __float80 type. */ 9100132718Skan float80_type = make_node (REAL_TYPE); 9101169689Skan TYPE_PRECISION (float80_type) = 80; 9102132718Skan layout_type (float80_type); 9103132718Skan (*lang_hooks.types.register_builtin_type) (float80_type, "__float80"); 9104132718Skan 9105132718Skan /* The __float128 type. */ 9106132718Skan if (!TARGET_HPUX) 9107132718Skan { 9108132718Skan tree float128_type = make_node (REAL_TYPE); 9109132718Skan TYPE_PRECISION (float128_type) = 128; 9110132718Skan layout_type (float128_type); 9111132718Skan (*lang_hooks.types.register_builtin_type) (float128_type, "__float128"); 9112132718Skan } 9113132718Skan else 9114132718Skan /* Under HPUX, this is a synonym for "long double". */ 9115132718Skan (*lang_hooks.types.register_builtin_type) (long_double_type_node, 9116132718Skan "__float128"); 9117132718Skan 9118169689Skan#define def_builtin(name, type, code) \ 9119169689Skan lang_hooks.builtin_function ((name), (type), (code), BUILT_IN_MD, \ 9120169689Skan NULL, NULL_TREE) 912190075Sobrien 912290075Sobrien def_builtin ("__builtin_ia64_bsp", 9123117395Skan build_function_type (ptr_type_node, void_list_node), 912490075Sobrien IA64_BUILTIN_BSP); 912590075Sobrien 9126132718Skan def_builtin ("__builtin_ia64_flushrs", 9127132718Skan build_function_type (void_type_node, void_list_node), 912890075Sobrien IA64_BUILTIN_FLUSHRS); 912990075Sobrien 913090075Sobrien#undef def_builtin 913190075Sobrien} 913290075Sobrien 913390075Sobrienrtx 9134132718Skania64_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, 9135132718Skan enum machine_mode mode ATTRIBUTE_UNUSED, 9136132718Skan int ignore ATTRIBUTE_UNUSED) 913790075Sobrien{ 913890075Sobrien tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); 913990075Sobrien unsigned int fcode = DECL_FUNCTION_CODE (fndecl); 914090075Sobrien 914190075Sobrien switch (fcode) 914290075Sobrien { 914390075Sobrien case IA64_BUILTIN_BSP: 914490075Sobrien if (! target || ! register_operand (target, DImode)) 914590075Sobrien target = gen_reg_rtx (DImode); 914690075Sobrien emit_insn (gen_bsp_value (target)); 9147132718Skan#ifdef POINTERS_EXTEND_UNSIGNED 9148132718Skan target = convert_memory_address (ptr_mode, target); 9149132718Skan#endif 915090075Sobrien return target; 915190075Sobrien 915290075Sobrien case IA64_BUILTIN_FLUSHRS: 915390075Sobrien emit_insn (gen_flushrs ()); 915490075Sobrien return const0_rtx; 915590075Sobrien 915690075Sobrien default: 915790075Sobrien break; 915890075Sobrien } 915990075Sobrien 916090075Sobrien return NULL_RTX; 916190075Sobrien} 916290075Sobrien 916390075Sobrien/* For the HP-UX IA64 aggregate parameters are passed stored in the 916490075Sobrien most significant bits of the stack slot. */ 916590075Sobrien 916690075Sobrienenum direction 9167132718Skania64_hpux_function_arg_padding (enum machine_mode mode, tree type) 916890075Sobrien{ 916990075Sobrien /* Exception to normal case for structures/unions/etc. */ 917090075Sobrien 917190075Sobrien if (type && AGGREGATE_TYPE_P (type) 917290075Sobrien && int_size_in_bytes (type) < UNITS_PER_WORD) 917390075Sobrien return upward; 917490075Sobrien 9175132718Skan /* Fall back to the default. */ 9176132718Skan return DEFAULT_FUNCTION_ARG_PADDING (mode, type); 917790075Sobrien} 9178117395Skan 9179215840Sdim/* Emit text to declare externally defined variables and functions, because 9180215840Sdim the Intel assembler does not support undefined externals. */ 9181117395Skan 9182215840Sdimvoid 9183215840Sdimia64_asm_output_external (FILE *file, tree decl, const char *name) 9184117395Skan{ 9185215840Sdim /* We output the name if and only if TREE_SYMBOL_REFERENCED is 9186215840Sdim set in order to avoid putting out names that are never really 9187215840Sdim used. */ 9188215840Sdim if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) 9189117395Skan { 9190215840Sdim /* maybe_assemble_visibility will return 1 if the assembler 9191215840Sdim visibility directive is outputed. */ 9192215840Sdim int need_visibility = ((*targetm.binds_local_p) (decl) 9193215840Sdim && maybe_assemble_visibility (decl)); 9194117395Skan 9195215840Sdim /* GNU as does not need anything here, but the HP linker does 9196215840Sdim need something for external functions. */ 9197215840Sdim if ((TARGET_HPUX_LD || !TARGET_GNU_AS) 9198215840Sdim && TREE_CODE (decl) == FUNCTION_DECL) 9199215840Sdim { 9200215840Sdim ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); 9201215840Sdim (*targetm.asm_out.globalize_label) (file, name); 9202215840Sdim } 9203215840Sdim else if (need_visibility && !TARGET_GNU_AS) 9204215840Sdim (*targetm.asm_out.globalize_label) (file, name); 9205117395Skan } 9206117395Skan} 9207117395Skan 9208169689Skan/* Set SImode div/mod functions, init_integral_libfuncs only initializes 9209169689Skan modes of word_mode and larger. Rename the TFmode libfuncs using the 9210169689Skan HPUX conventions. __divtf3 is used for XFmode. We need to keep it for 9211169689Skan backward compatibility. */ 9212132718Skan 9213132718Skanstatic void 9214169689Skania64_init_libfuncs (void) 9215132718Skan{ 9216169689Skan set_optab_libfunc (sdiv_optab, SImode, "__divsi3"); 9217169689Skan set_optab_libfunc (udiv_optab, SImode, "__udivsi3"); 9218169689Skan set_optab_libfunc (smod_optab, SImode, "__modsi3"); 9219169689Skan set_optab_libfunc (umod_optab, SImode, "__umodsi3"); 9220169689Skan 9221132718Skan set_optab_libfunc (add_optab, TFmode, "_U_Qfadd"); 9222132718Skan set_optab_libfunc (sub_optab, TFmode, "_U_Qfsub"); 9223132718Skan set_optab_libfunc (smul_optab, TFmode, "_U_Qfmpy"); 9224132718Skan set_optab_libfunc (sdiv_optab, TFmode, "_U_Qfdiv"); 9225169689Skan set_optab_libfunc (neg_optab, TFmode, "_U_Qfneg"); 9226169689Skan 9227169689Skan set_conv_libfunc (sext_optab, TFmode, SFmode, "_U_Qfcnvff_sgl_to_quad"); 9228169689Skan set_conv_libfunc (sext_optab, TFmode, DFmode, "_U_Qfcnvff_dbl_to_quad"); 9229169689Skan set_conv_libfunc (sext_optab, TFmode, XFmode, "_U_Qfcnvff_f80_to_quad"); 9230169689Skan set_conv_libfunc (trunc_optab, SFmode, TFmode, "_U_Qfcnvff_quad_to_sgl"); 9231169689Skan set_conv_libfunc (trunc_optab, DFmode, TFmode, "_U_Qfcnvff_quad_to_dbl"); 9232169689Skan set_conv_libfunc (trunc_optab, XFmode, TFmode, "_U_Qfcnvff_quad_to_f80"); 9233169689Skan 9234169689Skan set_conv_libfunc (sfix_optab, SImode, TFmode, "_U_Qfcnvfxt_quad_to_sgl"); 9235169689Skan set_conv_libfunc (sfix_optab, DImode, TFmode, "_U_Qfcnvfxt_quad_to_dbl"); 9236169689Skan set_conv_libfunc (sfix_optab, TImode, TFmode, "_U_Qfcnvfxt_quad_to_quad"); 9237169689Skan set_conv_libfunc (ufix_optab, SImode, TFmode, "_U_Qfcnvfxut_quad_to_sgl"); 9238169689Skan set_conv_libfunc (ufix_optab, DImode, TFmode, "_U_Qfcnvfxut_quad_to_dbl"); 9239169689Skan 9240169689Skan set_conv_libfunc (sfloat_optab, TFmode, SImode, "_U_Qfcnvxf_sgl_to_quad"); 9241169689Skan set_conv_libfunc (sfloat_optab, TFmode, DImode, "_U_Qfcnvxf_dbl_to_quad"); 9242169689Skan set_conv_libfunc (sfloat_optab, TFmode, TImode, "_U_Qfcnvxf_quad_to_quad"); 9243169689Skan /* HP-UX 11.23 libc does not have a function for unsigned 9244169689Skan SImode-to-TFmode conversion. */ 9245169689Skan set_conv_libfunc (ufloat_optab, TFmode, DImode, "_U_Qfcnvxuf_dbl_to_quad"); 9246169689Skan} 9247169689Skan 9248169689Skan/* Rename all the TFmode libfuncs using the HPUX conventions. */ 9249169689Skan 9250169689Skanstatic void 9251169689Skania64_hpux_init_libfuncs (void) 9252169689Skan{ 9253169689Skan ia64_init_libfuncs (); 9254169689Skan 9255169689Skan /* The HP SI millicode division and mod functions expect DI arguments. 9256169689Skan By turning them off completely we avoid using both libgcc and the 9257169689Skan non-standard millicode routines and use the HP DI millicode routines 9258169689Skan instead. */ 9259169689Skan 9260169689Skan set_optab_libfunc (sdiv_optab, SImode, 0); 9261169689Skan set_optab_libfunc (udiv_optab, SImode, 0); 9262169689Skan set_optab_libfunc (smod_optab, SImode, 0); 9263169689Skan set_optab_libfunc (umod_optab, SImode, 0); 9264169689Skan 9265169689Skan set_optab_libfunc (sdiv_optab, DImode, "__milli_divI"); 9266169689Skan set_optab_libfunc (udiv_optab, DImode, "__milli_divU"); 9267169689Skan set_optab_libfunc (smod_optab, DImode, "__milli_remI"); 9268169689Skan set_optab_libfunc (umod_optab, DImode, "__milli_remU"); 9269169689Skan 9270169689Skan /* HP-UX libc has TF min/max/abs routines in it. */ 9271132718Skan set_optab_libfunc (smin_optab, TFmode, "_U_Qfmin"); 9272132718Skan set_optab_libfunc (smax_optab, TFmode, "_U_Qfmax"); 9273132718Skan set_optab_libfunc (abs_optab, TFmode, "_U_Qfabs"); 9274132718Skan 9275132718Skan /* ia64_expand_compare uses this. */ 9276132718Skan cmptf_libfunc = init_one_libfunc ("_U_Qfcmp"); 9277132718Skan 9278132718Skan /* These should never be used. */ 9279132718Skan set_optab_libfunc (eq_optab, TFmode, 0); 9280132718Skan set_optab_libfunc (ne_optab, TFmode, 0); 9281132718Skan set_optab_libfunc (gt_optab, TFmode, 0); 9282132718Skan set_optab_libfunc (ge_optab, TFmode, 0); 9283132718Skan set_optab_libfunc (lt_optab, TFmode, 0); 9284132718Skan set_optab_libfunc (le_optab, TFmode, 0); 9285132718Skan} 9286132718Skan 9287132718Skan/* Rename the division and modulus functions in VMS. */ 9288132718Skan 9289132718Skanstatic void 9290132718Skania64_vms_init_libfuncs (void) 9291132718Skan{ 9292132718Skan set_optab_libfunc (sdiv_optab, SImode, "OTS$DIV_I"); 9293132718Skan set_optab_libfunc (sdiv_optab, DImode, "OTS$DIV_L"); 9294132718Skan set_optab_libfunc (udiv_optab, SImode, "OTS$DIV_UI"); 9295132718Skan set_optab_libfunc (udiv_optab, DImode, "OTS$DIV_UL"); 9296132718Skan set_optab_libfunc (smod_optab, SImode, "OTS$REM_I"); 9297132718Skan set_optab_libfunc (smod_optab, DImode, "OTS$REM_L"); 9298132718Skan set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI"); 9299132718Skan set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL"); 9300132718Skan} 9301117395Skan 9302169689Skan/* Rename the TFmode libfuncs available from soft-fp in glibc using 9303169689Skan the HPUX conventions. */ 9304169689Skan 9305117395Skanstatic void 9306169689Skania64_sysv4_init_libfuncs (void) 9307117395Skan{ 9308169689Skan ia64_init_libfuncs (); 9309169689Skan 9310169689Skan /* These functions are not part of the HPUX TFmode interface. We 9311169689Skan use them instead of _U_Qfcmp, which doesn't work the way we 9312169689Skan expect. */ 9313169689Skan set_optab_libfunc (eq_optab, TFmode, "_U_Qfeq"); 9314169689Skan set_optab_libfunc (ne_optab, TFmode, "_U_Qfne"); 9315169689Skan set_optab_libfunc (gt_optab, TFmode, "_U_Qfgt"); 9316169689Skan set_optab_libfunc (ge_optab, TFmode, "_U_Qfge"); 9317169689Skan set_optab_libfunc (lt_optab, TFmode, "_U_Qflt"); 9318169689Skan set_optab_libfunc (le_optab, TFmode, "_U_Qfle"); 9319169689Skan 9320169689Skan /* We leave out _U_Qfmin, _U_Qfmax and _U_Qfabs since soft-fp in 9321169689Skan glibc doesn't have them. */ 9322117395Skan} 9323169689Skan 9324169689Skan/* For HPUX, it is illegal to have relocations in shared segments. */ 9325117395Skan 9326169689Skanstatic int 9327169689Skania64_hpux_reloc_rw_mask (void) 9328117395Skan{ 9329169689Skan return 3; 9330117395Skan} 9331117395Skan 9332169689Skan/* For others, relax this so that relocations to local data goes in 9333169689Skan read-only segments, but we still cannot allow global relocations 9334169689Skan in read-only segments. */ 9335169689Skan 9336169689Skanstatic int 9337169689Skania64_reloc_rw_mask (void) 9338117395Skan{ 9339169689Skan return flag_pic ? 3 : 2; 9340117395Skan} 9341117395Skan 9342169689Skan/* Return the section to use for X. The only special thing we do here 9343169689Skan is to honor small data. */ 9344169689Skan 9345169689Skanstatic section * 9346169689Skania64_select_rtx_section (enum machine_mode mode, rtx x, 9347169689Skan unsigned HOST_WIDE_INT align) 9348117395Skan{ 9349169689Skan if (GET_MODE_SIZE (mode) > 0 9350169689Skan && GET_MODE_SIZE (mode) <= ia64_section_threshold 9351169689Skan && !TARGET_NO_SDATA) 9352169689Skan return sdata_section; 9353169689Skan else 9354169689Skan return default_elf_select_rtx_section (mode, x, align); 9355117395Skan} 9356117395Skan 9357117395Skanstatic unsigned int 9358169689Skania64_section_type_flags (tree decl, const char *name, int reloc) 9359117395Skan{ 9360169689Skan unsigned int flags = 0; 9361169689Skan 9362169689Skan if (strcmp (name, ".sdata") == 0 9363169689Skan || strncmp (name, ".sdata.", 7) == 0 9364169689Skan || strncmp (name, ".gnu.linkonce.s.", 16) == 0 9365169689Skan || strncmp (name, ".sdata2.", 8) == 0 9366169689Skan || strncmp (name, ".gnu.linkonce.s2.", 17) == 0 9367169689Skan || strcmp (name, ".sbss") == 0 9368169689Skan || strncmp (name, ".sbss.", 6) == 0 9369169689Skan || strncmp (name, ".gnu.linkonce.sb.", 17) == 0) 9370169689Skan flags = SECTION_SMALL; 9371169689Skan 9372169689Skan flags |= default_section_type_flags (decl, name, reloc); 9373169689Skan return flags; 9374117395Skan} 9375117395Skan 9376132718Skan/* Returns true if FNTYPE (a FUNCTION_TYPE or a METHOD_TYPE) returns a 9377132718Skan structure type and that the address of that type should be passed 9378132718Skan in out0, rather than in r8. */ 9379117395Skan 9380132718Skanstatic bool 9381132718Skania64_struct_retval_addr_is_first_parm_p (tree fntype) 9382132718Skan{ 9383132718Skan tree ret_type = TREE_TYPE (fntype); 9384132718Skan 9385132718Skan /* The Itanium C++ ABI requires that out0, rather than r8, be used 9386132718Skan as the structure return address parameter, if the return value 9387132718Skan type has a non-trivial copy constructor or destructor. It is not 9388132718Skan clear if this same convention should be used for other 9389132718Skan programming languages. Until G++ 3.4, we incorrectly used r8 for 9390132718Skan these return values. */ 9391132718Skan return (abi_version_at_least (2) 9392132718Skan && ret_type 9393132718Skan && TYPE_MODE (ret_type) == BLKmode 9394132718Skan && TREE_ADDRESSABLE (ret_type) 9395132718Skan && strcmp (lang_hooks.name, "GNU C++") == 0); 9396132718Skan} 9397132718Skan 9398117395Skan/* Output the assembler code for a thunk function. THUNK_DECL is the 9399117395Skan declaration for the thunk function itself, FUNCTION is the decl for 9400117395Skan the target function. DELTA is an immediate constant offset to be 9401132718Skan added to THIS. If VCALL_OFFSET is nonzero, the word at 9402117395Skan *(*this + vcall_offset) should be added to THIS. */ 9403117395Skan 9404117395Skanstatic void 9405132718Skania64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, 9406132718Skan HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 9407132718Skan tree function) 9408117395Skan{ 9409117395Skan rtx this, insn, funexp; 9410132718Skan unsigned int this_parmno; 9411132718Skan unsigned int this_regno; 9412117395Skan 9413117395Skan reload_completed = 1; 9414132718Skan epilogue_completed = 1; 9415117395Skan no_new_pseudos = 1; 9416169689Skan reset_block_changes (); 9417117395Skan 9418117395Skan /* Set things up as ia64_expand_prologue might. */ 9419117395Skan last_scratch_gr_reg = 15; 9420117395Skan 9421117395Skan memset (¤t_frame_info, 0, sizeof (current_frame_info)); 9422117395Skan current_frame_info.spill_cfa_off = -16; 9423117395Skan current_frame_info.n_input_regs = 1; 9424117395Skan current_frame_info.need_regstk = (TARGET_REG_NAMES != 0); 9425117395Skan 9426132718Skan /* Mark the end of the (empty) prologue. */ 9427132718Skan emit_note (NOTE_INSN_PROLOGUE_END); 9428132718Skan 9429132718Skan /* Figure out whether "this" will be the first parameter (the 9430132718Skan typical case) or the second parameter (as happens when the 9431132718Skan virtual function returns certain class objects). */ 9432132718Skan this_parmno 9433132718Skan = (ia64_struct_retval_addr_is_first_parm_p (TREE_TYPE (thunk)) 9434132718Skan ? 1 : 0); 9435132718Skan this_regno = IN_REG (this_parmno); 9436117395Skan if (!TARGET_REG_NAMES) 9437132718Skan reg_names[this_regno] = ia64_reg_numbers[this_parmno]; 9438117395Skan 9439132718Skan this = gen_rtx_REG (Pmode, this_regno); 9440122180Skan if (TARGET_ILP32) 9441132718Skan { 9442132718Skan rtx tmp = gen_rtx_REG (ptr_mode, this_regno); 9443132718Skan REG_POINTER (tmp) = 1; 9444132718Skan if (delta && CONST_OK_FOR_I (delta)) 9445132718Skan { 9446132718Skan emit_insn (gen_ptr_extend_plus_imm (this, tmp, GEN_INT (delta))); 9447132718Skan delta = 0; 9448132718Skan } 9449132718Skan else 9450132718Skan emit_insn (gen_ptr_extend (this, tmp)); 9451132718Skan } 9452117395Skan 9453117395Skan /* Apply the constant offset, if required. */ 9454117395Skan if (delta) 9455117395Skan { 9456117395Skan rtx delta_rtx = GEN_INT (delta); 9457117395Skan 9458117395Skan if (!CONST_OK_FOR_I (delta)) 9459117395Skan { 9460117395Skan rtx tmp = gen_rtx_REG (Pmode, 2); 9461117395Skan emit_move_insn (tmp, delta_rtx); 9462117395Skan delta_rtx = tmp; 9463117395Skan } 9464117395Skan emit_insn (gen_adddi3 (this, this, delta_rtx)); 9465117395Skan } 9466117395Skan 9467117395Skan /* Apply the offset from the vtable, if required. */ 9468117395Skan if (vcall_offset) 9469117395Skan { 9470117395Skan rtx vcall_offset_rtx = GEN_INT (vcall_offset); 9471117395Skan rtx tmp = gen_rtx_REG (Pmode, 2); 9472117395Skan 9473122180Skan if (TARGET_ILP32) 9474122180Skan { 9475122180Skan rtx t = gen_rtx_REG (ptr_mode, 2); 9476132718Skan REG_POINTER (t) = 1; 9477122180Skan emit_move_insn (t, gen_rtx_MEM (ptr_mode, this)); 9478132718Skan if (CONST_OK_FOR_I (vcall_offset)) 9479132718Skan { 9480132718Skan emit_insn (gen_ptr_extend_plus_imm (tmp, t, 9481132718Skan vcall_offset_rtx)); 9482132718Skan vcall_offset = 0; 9483132718Skan } 9484132718Skan else 9485132718Skan emit_insn (gen_ptr_extend (tmp, t)); 9486122180Skan } 9487122180Skan else 9488122180Skan emit_move_insn (tmp, gen_rtx_MEM (Pmode, this)); 9489117395Skan 9490132718Skan if (vcall_offset) 9491117395Skan { 9492132718Skan if (!CONST_OK_FOR_J (vcall_offset)) 9493132718Skan { 9494132718Skan rtx tmp2 = gen_rtx_REG (Pmode, next_scratch_gr_reg ()); 9495132718Skan emit_move_insn (tmp2, vcall_offset_rtx); 9496132718Skan vcall_offset_rtx = tmp2; 9497132718Skan } 9498132718Skan emit_insn (gen_adddi3 (tmp, tmp, vcall_offset_rtx)); 9499117395Skan } 9500117395Skan 9501122180Skan if (TARGET_ILP32) 9502122180Skan emit_move_insn (gen_rtx_REG (ptr_mode, 2), 9503122180Skan gen_rtx_MEM (ptr_mode, tmp)); 9504122180Skan else 9505122180Skan emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp)); 9506117395Skan 9507117395Skan emit_insn (gen_adddi3 (this, this, tmp)); 9508117395Skan } 9509117395Skan 9510117395Skan /* Generate a tail call to the target function. */ 9511117395Skan if (! TREE_USED (function)) 9512117395Skan { 9513117395Skan assemble_external (function); 9514117395Skan TREE_USED (function) = 1; 9515117395Skan } 9516117395Skan funexp = XEXP (DECL_RTL (function), 0); 9517117395Skan funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); 9518117395Skan ia64_expand_call (NULL_RTX, funexp, NULL_RTX, 1); 9519117395Skan insn = get_last_insn (); 9520117395Skan SIBLING_CALL_P (insn) = 1; 9521117395Skan 9522117395Skan /* Code generation for calls relies on splitting. */ 9523117395Skan reload_completed = 1; 9524132718Skan epilogue_completed = 1; 9525117395Skan try_split (PATTERN (insn), insn, 0); 9526117395Skan 9527117395Skan emit_barrier (); 9528117395Skan 9529117395Skan /* Run just enough of rest_of_compilation to get the insns emitted. 9530117395Skan There's not really enough bulk here to make other passes such as 9531117395Skan instruction scheduling worth while. Note that use_thunk calls 9532117395Skan assemble_start_function and assemble_end_function. */ 9533117395Skan 9534132718Skan insn_locators_initialize (); 9535132718Skan emit_all_insn_group_barriers (NULL); 9536117395Skan insn = get_insns (); 9537117395Skan shorten_branches (insn); 9538117395Skan final_start_function (insn, file, 1); 9539169689Skan final (insn, file, 1); 9540117395Skan final_end_function (); 9541117395Skan 9542117395Skan reload_completed = 0; 9543132718Skan epilogue_completed = 0; 9544117395Skan no_new_pseudos = 0; 9545117395Skan} 9546117395Skan 9547132718Skan/* Worker function for TARGET_STRUCT_VALUE_RTX. */ 9548132718Skan 9549132718Skanstatic rtx 9550132718Skania64_struct_value_rtx (tree fntype, 9551132718Skan int incoming ATTRIBUTE_UNUSED) 9552132718Skan{ 9553132718Skan if (fntype && ia64_struct_retval_addr_is_first_parm_p (fntype)) 9554132718Skan return NULL_RTX; 9555132718Skan return gen_rtx_REG (Pmode, GR_REG (8)); 9556132718Skan} 9557132718Skan 9558169689Skanstatic bool 9559169689Skania64_scalar_mode_supported_p (enum machine_mode mode) 9560169689Skan{ 9561169689Skan switch (mode) 9562169689Skan { 9563169689Skan case QImode: 9564169689Skan case HImode: 9565169689Skan case SImode: 9566169689Skan case DImode: 9567169689Skan case TImode: 9568169689Skan return true; 9569169689Skan 9570169689Skan case SFmode: 9571169689Skan case DFmode: 9572169689Skan case XFmode: 9573169689Skan case RFmode: 9574169689Skan return true; 9575169689Skan 9576169689Skan case TFmode: 9577169689Skan return TARGET_HPUX; 9578169689Skan 9579169689Skan default: 9580169689Skan return false; 9581169689Skan } 9582169689Skan} 9583169689Skan 9584169689Skanstatic bool 9585169689Skania64_vector_mode_supported_p (enum machine_mode mode) 9586169689Skan{ 9587169689Skan switch (mode) 9588169689Skan { 9589169689Skan case V8QImode: 9590169689Skan case V4HImode: 9591169689Skan case V2SImode: 9592169689Skan return true; 9593169689Skan 9594169689Skan case V2SFmode: 9595169689Skan return true; 9596169689Skan 9597169689Skan default: 9598169689Skan return false; 9599169689Skan } 9600169689Skan} 9601169689Skan 9602169689Skan/* Implement the FUNCTION_PROFILER macro. */ 9603169689Skan 9604169689Skanvoid 9605169689Skania64_output_function_profiler (FILE *file, int labelno) 9606169689Skan{ 9607169689Skan bool indirect_call; 9608169689Skan 9609169689Skan /* If the function needs a static chain and the static chain 9610169689Skan register is r15, we use an indirect call so as to bypass 9611169689Skan the PLT stub in case the executable is dynamically linked, 9612169689Skan because the stub clobbers r15 as per 5.3.6 of the psABI. 9613169689Skan We don't need to do that in non canonical PIC mode. */ 9614169689Skan 9615169689Skan if (cfun->static_chain_decl && !TARGET_NO_PIC && !TARGET_AUTO_PIC) 9616169689Skan { 9617169689Skan gcc_assert (STATIC_CHAIN_REGNUM == 15); 9618169689Skan indirect_call = true; 9619169689Skan } 9620169689Skan else 9621169689Skan indirect_call = false; 9622169689Skan 9623169689Skan if (TARGET_GNU_AS) 9624169689Skan fputs ("\t.prologue 4, r40\n", file); 9625169689Skan else 9626169689Skan fputs ("\t.prologue\n\t.save ar.pfs, r40\n", file); 9627169689Skan fputs ("\talloc out0 = ar.pfs, 8, 0, 4, 0\n", file); 9628169689Skan 9629169689Skan if (NO_PROFILE_COUNTERS) 9630169689Skan fputs ("\tmov out3 = r0\n", file); 9631169689Skan else 9632169689Skan { 9633169689Skan char buf[20]; 9634169689Skan ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno); 9635169689Skan 9636169689Skan if (TARGET_AUTO_PIC) 9637169689Skan fputs ("\tmovl out3 = @gprel(", file); 9638169689Skan else 9639169689Skan fputs ("\taddl out3 = @ltoff(", file); 9640169689Skan assemble_name (file, buf); 9641169689Skan if (TARGET_AUTO_PIC) 9642169689Skan fputs (")\n", file); 9643169689Skan else 9644169689Skan fputs ("), r1\n", file); 9645169689Skan } 9646169689Skan 9647169689Skan if (indirect_call) 9648169689Skan fputs ("\taddl r14 = @ltoff(@fptr(_mcount)), r1\n", file); 9649169689Skan fputs ("\t;;\n", file); 9650169689Skan 9651169689Skan fputs ("\t.save rp, r42\n", file); 9652169689Skan fputs ("\tmov out2 = b0\n", file); 9653169689Skan if (indirect_call) 9654169689Skan fputs ("\tld8 r14 = [r14]\n\t;;\n", file); 9655169689Skan fputs ("\t.body\n", file); 9656169689Skan fputs ("\tmov out1 = r1\n", file); 9657169689Skan if (indirect_call) 9658169689Skan { 9659169689Skan fputs ("\tld8 r16 = [r14], 8\n\t;;\n", file); 9660169689Skan fputs ("\tmov b6 = r16\n", file); 9661169689Skan fputs ("\tld8 r1 = [r14]\n", file); 9662169689Skan fputs ("\tbr.call.sptk.many b0 = b6\n\t;;\n", file); 9663169689Skan } 9664169689Skan else 9665169689Skan fputs ("\tbr.call.sptk.many b0 = _mcount\n\t;;\n", file); 9666169689Skan} 9667169689Skan 9668169689Skanstatic GTY(()) rtx mcount_func_rtx; 9669169689Skanstatic rtx 9670169689Skangen_mcount_func_rtx (void) 9671169689Skan{ 9672169689Skan if (!mcount_func_rtx) 9673169689Skan mcount_func_rtx = init_one_libfunc ("_mcount"); 9674169689Skan return mcount_func_rtx; 9675169689Skan} 9676169689Skan 9677169689Skanvoid 9678169689Skania64_profile_hook (int labelno) 9679169689Skan{ 9680169689Skan rtx label, ip; 9681169689Skan 9682169689Skan if (NO_PROFILE_COUNTERS) 9683169689Skan label = const0_rtx; 9684169689Skan else 9685169689Skan { 9686169689Skan char buf[30]; 9687169689Skan const char *label_name; 9688169689Skan ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno); 9689169689Skan label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf)); 9690169689Skan label = gen_rtx_SYMBOL_REF (Pmode, label_name); 9691169689Skan SYMBOL_REF_FLAGS (label) = SYMBOL_FLAG_LOCAL; 9692169689Skan } 9693169689Skan ip = gen_reg_rtx (Pmode); 9694169689Skan emit_insn (gen_ip_value (ip)); 9695169689Skan emit_library_call (gen_mcount_func_rtx (), LCT_NORMAL, 9696169689Skan VOIDmode, 3, 9697169689Skan gen_rtx_REG (Pmode, BR_REG (0)), Pmode, 9698169689Skan ip, Pmode, 9699169689Skan label, Pmode); 9700169689Skan} 9701169689Skan 9702169689Skan/* Return the mangling of TYPE if it is an extended fundamental type. */ 9703169689Skan 9704169689Skanstatic const char * 9705169689Skania64_mangle_fundamental_type (tree type) 9706169689Skan{ 9707169689Skan /* On HP-UX, "long double" is mangled as "e" so __float128 is 9708169689Skan mangled as "e". */ 9709169689Skan if (!TARGET_HPUX && TYPE_MODE (type) == TFmode) 9710169689Skan return "g"; 9711169689Skan /* On HP-UX, "e" is not available as a mangling of __float80 so use 9712169689Skan an extended mangling. Elsewhere, "e" is available since long 9713169689Skan double is 80 bits. */ 9714169689Skan if (TYPE_MODE (type) == XFmode) 9715169689Skan return TARGET_HPUX ? "u9__float80" : "e"; 9716169689Skan if (TYPE_MODE (type) == RFmode) 9717169689Skan return "u7__fpreg"; 9718169689Skan return NULL; 9719169689Skan} 9720169689Skan 9721169689Skan/* Return the diagnostic message string if conversion from FROMTYPE to 9722169689Skan TOTYPE is not allowed, NULL otherwise. */ 9723169689Skanstatic const char * 9724169689Skania64_invalid_conversion (tree fromtype, tree totype) 9725169689Skan{ 9726169689Skan /* Reject nontrivial conversion to or from __fpreg. */ 9727169689Skan if (TYPE_MODE (fromtype) == RFmode 9728169689Skan && TYPE_MODE (totype) != RFmode 9729169689Skan && TYPE_MODE (totype) != VOIDmode) 9730169689Skan return N_("invalid conversion from %<__fpreg%>"); 9731169689Skan if (TYPE_MODE (totype) == RFmode 9732169689Skan && TYPE_MODE (fromtype) != RFmode) 9733169689Skan return N_("invalid conversion to %<__fpreg%>"); 9734169689Skan return NULL; 9735169689Skan} 9736169689Skan 9737169689Skan/* Return the diagnostic message string if the unary operation OP is 9738169689Skan not permitted on TYPE, NULL otherwise. */ 9739169689Skanstatic const char * 9740169689Skania64_invalid_unary_op (int op, tree type) 9741169689Skan{ 9742169689Skan /* Reject operations on __fpreg other than unary + or &. */ 9743169689Skan if (TYPE_MODE (type) == RFmode 9744169689Skan && op != CONVERT_EXPR 9745169689Skan && op != ADDR_EXPR) 9746169689Skan return N_("invalid operation on %<__fpreg%>"); 9747169689Skan return NULL; 9748169689Skan} 9749169689Skan 9750169689Skan/* Return the diagnostic message string if the binary operation OP is 9751169689Skan not permitted on TYPE1 and TYPE2, NULL otherwise. */ 9752169689Skanstatic const char * 9753169689Skania64_invalid_binary_op (int op ATTRIBUTE_UNUSED, tree type1, tree type2) 9754169689Skan{ 9755169689Skan /* Reject operations on __fpreg. */ 9756169689Skan if (TYPE_MODE (type1) == RFmode || TYPE_MODE (type2) == RFmode) 9757169689Skan return N_("invalid operation on %<__fpreg%>"); 9758169689Skan return NULL; 9759169689Skan} 9760169689Skan 9761169689Skan/* Implement overriding of the optimization options. */ 9762169689Skanvoid 9763169689Skania64_optimization_options (int level ATTRIBUTE_UNUSED, 9764169689Skan int size ATTRIBUTE_UNUSED) 9765169689Skan{ 9766169689Skan /* Let the scheduler form additional regions. */ 9767169689Skan set_param_value ("max-sched-extend-regions-iters", 2); 9768169689Skan} 9769169689Skan 9770117395Skan#include "gt-ia64.h" 9771