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 (&current_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 (&current_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